bêta

Angle Dial <mv-angle-dial>

Saisie d’angle en degrés qui se lit comme en CSS (0° en haut, sens horaire) : un bouton rotatif dans un anneau de graduations qui sert aussi de grille d’aimantation, avec les graduations derrière le bouton allumées et qui s’estompent avec la distance. Faites glisser avec de légers crans tous les 45° ou maintenez Maj pour aimanter, clavier complet de slider, associé aux formulaires.

CatégorieFormulaires
TypeWeb Component (<mv-angle-dial>)
Statutbêta
Keywordsangle, dial, knob, rotation, gradient, inspector, slider, form-associated, editor, ticks

When to use

  • A design tool lets users set a rotation or gradient direction in degrees by dragging around a dial
  • An inspector panel needs a compact angle control that snaps to 15 or 45 degree steps
  • A settings form must submit a direction or heading as a plain number of degrees

Avoid when

  • The value is a generic linear number rather than an angle → use Slider instead
  • Users need to type the exact angle more often than drag it → use Scrub Field instead
  • The audience is non-technical and a circular control would be unfamiliar in a regular form

Installation

node scripts/add.mjs angle-dial --out ./src/marvelous

Agent IA avec le serveur MCP de Marvelous UI : install_components({ slugs: ["angle-dial"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Fichiers copiés (dépendances comprises) : tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/form.js, components/angle-dial/angle-dial.js, components/angle-dial/angle-dial.css.

Utilisation

Balisage de référence : partez de celui-ci et personnalisez-le avec les attributs, data-* et les variables CSS :

<div id="angle-demo">
  <style>
    #angle-demo { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: center; justify-content: center; width: 100%; }
    #angle-demo .ad-stage { display: grid; place-items: center; width: 15rem; height: 15rem; border-radius: var(--mv-radius-xl); background: radial-gradient(circle at 1px 1px, color-mix(in oklch, var(--mv-fg) 12%, transparent) 1px, transparent 0) 0 0 / 12px 12px, var(--mv-bg); border: 1px solid var(--mv-border); }
    #angle-demo .ad-shape { width: 8rem; height: 8rem; border-radius: 1.5rem; box-shadow: 0 18px 40px -16px oklch(0.4 0.2 260 / .55); }
    #angle-demo .ad-panel { display: grid; gap: .6rem; width: 16.5rem; padding: .85rem; border: 1px solid var(--mv-border); border-radius: var(--mv-radius-lg); background: var(--mv-surface); box-shadow: var(--mv-shadow-sm); }
    #angle-demo .ad-head { margin: 0; font: 600 .7rem var(--mv-font-sans); letter-spacing: .06em; text-transform: uppercase; color: var(--mv-fg-subtle); }
    #angle-demo .ad-row { display: grid; grid-template-columns: 4.75rem auto 1fr; align-items: center; gap: .6rem; font-size: .75rem; color: var(--mv-fg-muted); }
    #angle-demo .ad-row mv-scrub-field { width: 100%; }
    #angle-demo .ad-big { --mv-angle-dial-size: 3.5rem; }
    #angle-demo .ad-hint { margin: .15rem 0 0; font-size: .7rem; line-height: 1.5; color: var(--mv-fg-muted); }
    #angle-demo kbd { font: 500 .65rem var(--mv-font-mono); padding: 0 .25rem; border-radius: 3px; background: var(--mv-bg-muted); border: 1px solid var(--mv-border); }
  </style>
  <div class="ad-stage"><div class="ad-shape" id="angle-demo-shape"></div></div>
  <div class="ad-panel" role="group" aria-label="Inspector">
    <p class="ad-head">Transform</p>
    <div class="ad-row">
      <span id="angle-demo-l1">Rotation</span>
      <mv-angle-dial id="angle-demo-rot" name="rotation" value="-15" aria-labelledby="angle-demo-l1"></mv-angle-dial>
      <mv-scrub-field id="angle-demo-rot-field" aria-label="Rotation in degrees" unit="°" value="345" min="0" max="360" wrap precision="0"></mv-scrub-field>
    </div>
    <p class="ad-head">Fill</p>
    <div class="ad-row">
      <span id="angle-demo-l2">Gradient</span>
      <mv-angle-dial id="angle-demo-grad" class="ad-big" name="angle" value="135" snap="45" readout aria-labelledby="angle-demo-l2"></mv-angle-dial>
      <span></span>
    </div>
    <p class="ad-hint">Drag the dial or use the arrow keys. <kbd>Shift</kbd> snaps to the ticks, <kbd>Alt</kbd> drags freely, double-click resets.</p>
  </div>
</div>
<script type="module">
  const $ = (id) => document.getElementById(`angle-demo-${id}`);
  const apply = () => {
    $("shape").style.rotate = `${$("rot").value}deg`;
    $("shape").style.background = `linear-gradient(${$("grad").value}deg, oklch(0.8 0.13 190), oklch(0.6 0.2 265) 55%, oklch(0.68 0.2 340))`;
  };
  $("rot").addEventListener("mv-input", (e) => { $("rot-field").value = e.detail.value; apply(); });
  $("rot-field").addEventListener("mv-input", (e) => { $("rot").value = e.detail.value; apply(); });
  $("grad").addEventListener("mv-input", apply);
  Promise.all(["mv-angle-dial", "mv-scrub-field"].map((t) => customElements.whenDefined(t))).then(() => requestAnimationFrame(apply));
</script>

API

Attributes

NameTypeDefaultDescription
valuenumber0Angle in degrees, normalized to [0, 360). Restored on form reset and on double-click.
namestringForm field name; the form receives the number of degrees.
labelstringAngleAccessible name. aria-labelledby / aria-label on the element or an external <label> work too.
stepnumber1Arrow-key step (Alt: a tenth of it, when precision allows).
snapnumber15Snap grid: Shift while dragging or with the arrows, PageUp/PageDown step, and the spacing of the ticks.
precisionnumber0Decimal places kept.
readoutbooleanShows the value in the center of the knob (for sizes of about 3rem and up).
localestringNumber formatting locale (defaults to the page lang, then en-US).
disabled / readonly / requiredbooleanStandard form states.

Properties

NameTypeDescription
valuenumberCurrent angle.
valueAsNumbernumberSame as value.
defaultValuenumberValue restored on form reset and double-click (the initial value).
stringsPartial<Record<string, string>>Overrides for every text: label ("Angle"), valueText ("{value} degrees"). English defaults.

Methods

NameDescription
focus()Focuses the slider.

Events

NameDescription
mv-inputWhile dragging and on every key press. detail: { value }.
mv-changeOn release (if the value changed) and on every key press. detail: { value }.

CSS classes

NameDescription
mv-angle-dial-face / -ticks / -tick / -arc / -plate / -needle / -knob / -readout / -badgeGenerated parts. -tick[data-major] marks every 90°.

CSS variables

NameDefaultDescription
--mv-angle-dial-sizevar(--mv-control-sm)Diameter; ticks, knob and readout scale with it.
--mv-angle-dial-bgBackground of the tick band.

Accessibility

The face has role="slider" with aria-valuemin 0, aria-valuemax 359 (the last value before it wraps, finer with precision), aria-valuenow and aria-valuetext “135 degrees” (localizable). Keyboard: →/↑ and ←/↓ by step (wrapping past 0°), Alt+arrow for a tenth of a step, Shift+arrow to the next snap tick, PageUp/PageDown ±snap, Home 0°, End the maximum. Esc while dragging restores the starting angle. Named by label, aria-labelledby/aria-label on the element, or a <label>. Visible focus ring; forced colors use system colors (Highlight for the value); the value bubble briefly shows after a key press; motion is limited to short transitions.

Cette page a été traduite par IA. Signaler un problème de traduction