bêta

Vector Field <mv-vector-field>

Saisies X/Y, X/Y/Z ou W/H compactes pour les inspecteurs : chaque axe est un spinbutton dans lequel vous pouvez taper, avancer par pas au clavier ou ajuster en faisant glisser sa lettre, avec un filet qui montre où se situe la valeur dans sa plage et un verrouillage facultatif des proportions. La valeur « x,y » est associée aux formulaires.

CatégorieFormulaires
TypeWeb Component (<mv-vector-field>)
Statutbêta
Keywordsvector, xy, xyz, size, aspect-ratio, lock, scrub, spinbutton, inspector, form-associated, editor

When to use

  • An inspector edits a position as X/Y or X/Y/Z values side by side
  • Width and height must be edited with a lock that keeps the aspect ratio
  • A form submits several related numbers as one comma-separated value

Avoid when

  • Only one number is edited → use Number Field instead
  • The audience is non-technical and expects labeled regular fields → use Number Field instead

Installation

node scripts/add.mjs vector-field --out ./src/marvelous

Agent IA avec le serveur MCP de Marvelous UI : install_components({ slugs: ["vector-field"], 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/vector-field/vector-field.js, components/vector-field/vector-field.css.

Utilisation

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

<div id="vec-demo">
  <style>
    #vec-demo { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: center; justify-content: center; width: 100%; }
    #vec-demo .vfd-stage { position: relative; width: 18rem; height: 15rem; overflow: hidden; 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); perspective: 600px; }
    #vec-demo .vfd-card { position: absolute; left: 0; top: 0; display: grid; place-items: center; border-radius: 14px; color: #fff; font: 600 .7rem var(--mv-font-mono); background: linear-gradient(135deg, oklch(0.72 0.16 250), oklch(0.6 0.2 285)); box-shadow: 0 0 0 1px oklch(1 0 0 / .15) inset, 0 14px 30px -14px oklch(0.4 0.2 270 / .7); outline: 1px dashed color-mix(in oklch, var(--mv-accent) 70%, transparent); outline-offset: 4px; }
    #vec-demo .vfd-panel { display: grid; gap: .5rem; width: 17rem; padding: .75rem; border: 1px solid var(--mv-border); border-radius: var(--mv-radius-lg); background: var(--mv-surface); box-shadow: var(--mv-shadow-sm); }
    #vec-demo .vfd-head { margin: 0; font: 600 .7rem var(--mv-font-sans); letter-spacing: .06em; text-transform: uppercase; color: var(--mv-fg-subtle); }
    #vec-demo .vfd-row { display: grid; gap: .3rem; font-size: .72rem; color: var(--mv-fg-muted); }
  </style>
  <div class="vfd-stage"><div class="vfd-card" id="vec-demo-card"></div></div>
  <div class="vfd-panel" role="group" aria-label="Inspector">
    <p class="vfd-head">Layout</p>
    <div class="vfd-row"><span>Position</span>
      <mv-vector-field id="vec-demo-pos" label="Position" name="position" axes="X,Y" unit="px" value="64,48" min="0,0" max="240,200"></mv-vector-field>
    </div>
    <div class="vfd-row"><span>Size</span>
      <mv-vector-field id="vec-demo-size" label="Size" name="size" axes="W,H" axis-labels="Width,Height" unit="px" value="144,96" min="24" max="280" linkable linked></mv-vector-field>
    </div>
    <div class="vfd-row"><span>3D rotation</span>
      <mv-vector-field id="vec-demo-rot" label="3D rotation" name="rotation" axes="X,Y,Z" unit="°" value="0,-18,0" min="-180" max="180"></mv-vector-field>
    </div>
  </div>
</div>
<script type="module">
  const $ = (id) => document.getElementById(`vec-demo-${id}`);
  const apply = () => {
    const [x, y] = $("pos").values, [w, hh] = $("size").values, [rx, ry, rz] = $("rot").values;
    const c = $("card");
    c.style.width = `${w}px`;
    c.style.height = `${hh}px`;
    c.style.transform = `translate(${x}px, ${y}px) rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`;
    c.textContent = `${Math.round(w)} × ${Math.round(hh)}`;
  };
  document.getElementById("vec-demo").addEventListener("mv-input", apply);
  customElements.whenDefined("mv-vector-field").then(() => requestAnimationFrame(apply));
</script>

API

Attributes

NameTypeDefaultDescription
valuestringComma-separated values: “120,48”. Restored on reset.
axesstringX,YShort axis labels (2 to 4), shown in each handle.
axis-labelsstringAccessible axis names (“Width,Height”); otherwise “<label> <axis>”.
labelstringGroup name (role=group).
unit / min / max / stepstringOne value for all axes or one per axis (“0,0,-100”). Values are clamped to min/max; a bounded axis shows its position as a hairline.
precisionnumberstep decimals + 1Decimals kept, for all axes.
linkablebooleanShows the aspect-ratio lock button.
linkedbooleanAspect ratio locked: changing one axis scales the others (ratio captured when locking).
name / disabled / readonlyStandard behavior.

Properties

NameTypeDescription
valuestring“x,y[,z]”.
valuesnumber[]Numeric values (read/write). Assignable before the element is defined.
fieldsHTMLInputElement[]The generated axis inputs (role=spinbutton), read-only.
strings{ lock }Default texts, for translation (“Lock aspect ratio”). Assignable before the element is defined.

Methods

NameDescription
focus()Focuses the first axis.

Events

NameDescription
mv-inputOn every value change (drag, arrow keys, committed typing). detail: { value, values, axis }.
mv-changeOn commit: drag release, arrow key, Enter, blur. detail: { value, values, axis }. Native input/change events of the inner inputs do not bubble out.
mv-linkThe lock was toggled. detail: { linked }.

CSS classes

NameDescription
mv-vector-field-axisOne axis cell; data-scrubbing while its letter is dragged.
mv-vector-field-handle / -input / -unit / -meterGenerated parts: draggable letter, input, unit suffix, range hairline.
mv-vector-field-linkLock button (aria-pressed).

CSS variables

NameDefaultDescription
--mv-vector-field-width100%Group width.
--mv-vector-field-gapvar(--mv-space-1)Gap between fields.

Accessibility

role="group" named by label. Each axis is a text input with role="spinbutton", aria-valuenow/min/max and an aria-valuetext that includes the unit (“64 px”), named by axis-labels or “<label> <axis>”. Keyboard: ↑/↓ step (Shift ×10, Alt ×0.1), PageUp/PageDown ×10, Home/End jump to min/max, type a value then Enter or Tab to commit, Escape to revert the typing or cancel a drag. An unreadable value is flagged with aria-invalid until fixed or left. Dragging the axis letter is a pointer shortcut only (no pointer lock, system cursor kept). The lock is a toggle button (aria-pressed) named “Lock aspect ratio”. Forced colors keep borders, focus, the range hairline and the pressed lock visible.

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