sherick-ui 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cjs/components/Checkbox.cjs +3 -1
  2. package/dist/cjs/components/Checkbox.cjs.map +1 -1
  3. package/dist/cjs/components/Combobox.cjs +1 -1
  4. package/dist/cjs/components/Combobox.cjs.map +1 -1
  5. package/dist/cjs/components/Command.cjs +1 -1
  6. package/dist/cjs/components/Command.cjs.map +1 -1
  7. package/dist/cjs/components/FileUpload.cjs +1 -1
  8. package/dist/cjs/components/FileUpload.cjs.map +1 -1
  9. package/dist/cjs/components/Input.cjs +1 -1
  10. package/dist/cjs/components/Input.cjs.map +1 -1
  11. package/dist/cjs/components/NumberField.cjs +2 -2
  12. package/dist/cjs/components/NumberField.cjs.map +1 -1
  13. package/dist/cjs/components/RadioGroup.cjs +1 -1
  14. package/dist/cjs/components/RadioGroup.cjs.map +1 -1
  15. package/dist/cjs/components/Search.cjs +4 -1
  16. package/dist/cjs/components/Search.cjs.map +1 -1
  17. package/dist/cjs/components/Select.cjs +1 -1
  18. package/dist/cjs/components/Select.cjs.map +1 -1
  19. package/dist/cjs/components/Textarea.cjs +1 -1
  20. package/dist/cjs/components/Textarea.cjs.map +1 -1
  21. package/dist/cjs/components/date-field.cjs +2 -2
  22. package/dist/cjs/components/date-field.cjs.map +1 -1
  23. package/dist/cjs/components/ui.common.cjs +97 -43
  24. package/dist/cjs/components/ui.common.cjs.map +1 -1
  25. package/dist/cjs/components/ui.motion.cjs +6 -1
  26. package/dist/cjs/components/ui.motion.cjs.map +1 -1
  27. package/dist/cjs/dev.cjs +2 -0
  28. package/dist/cjs/dev.cjs.map +1 -1
  29. package/dist/esm/components/Checkbox.js +3 -1
  30. package/dist/esm/components/Checkbox.js.map +1 -1
  31. package/dist/esm/components/Combobox.js +2 -2
  32. package/dist/esm/components/Combobox.js.map +1 -1
  33. package/dist/esm/components/Command.js +2 -2
  34. package/dist/esm/components/Command.js.map +1 -1
  35. package/dist/esm/components/FileUpload.js +2 -2
  36. package/dist/esm/components/FileUpload.js.map +1 -1
  37. package/dist/esm/components/Input.js +2 -2
  38. package/dist/esm/components/Input.js.map +1 -1
  39. package/dist/esm/components/NumberField.js +3 -3
  40. package/dist/esm/components/NumberField.js.map +1 -1
  41. package/dist/esm/components/RadioGroup.js +2 -2
  42. package/dist/esm/components/RadioGroup.js.map +1 -1
  43. package/dist/esm/components/Search.js +5 -2
  44. package/dist/esm/components/Search.js.map +1 -1
  45. package/dist/esm/components/Select.js +2 -2
  46. package/dist/esm/components/Select.js.map +1 -1
  47. package/dist/esm/components/Textarea.js +2 -2
  48. package/dist/esm/components/Textarea.js.map +1 -1
  49. package/dist/esm/components/date-field.js +3 -3
  50. package/dist/esm/components/date-field.js.map +1 -1
  51. package/dist/esm/components/ui.common.js +98 -45
  52. package/dist/esm/components/ui.common.js.map +1 -1
  53. package/dist/esm/components/ui.motion.js +6 -2
  54. package/dist/esm/components/ui.motion.js.map +1 -1
  55. package/dist/esm/dev.js +2 -2
  56. package/dist/styles.css +191 -49
  57. package/dist/theme.css +7 -3
  58. package/dist/types/dev.d.cts +34 -21
  59. package/dist/types/dev.d.ts +34 -21
  60. package/package.json +1 -1
@@ -31,7 +31,7 @@ import { cx } from '../libs/utils.js';
31
31
  /** Non-spatial feedback: hover, focus, field tone, a highlighted row, a filled surface.
32
32
  * It never translates, scales or resizes; reduced motion simply drops the interpolation
33
33
  * and the state still arrives. */
34
- const motionFeedback = "transition-[background-color,color,box-shadow,opacity] duration-press ease-press motion-reduce:transition-none";
34
+ const motionFeedback = "transition-[background-color,border-color,color,box-shadow,opacity] duration-press ease-press motion-reduce:transition-none";
35
35
  /** A control answers a press immediately and settles on its release.
36
36
  *
37
37
  * The recipe owns the *amplitude* of that answer as well as its timing, because how far a press
@@ -167,6 +167,10 @@ const motionActivityIndeterminate = "animate-sherick-indeterminate [[dir=rtl]_&]
167
167
  * is, and arrowing through a list with a soft fade on every row leaves a smear of half-lit rows.
168
168
  * The row's layer therefore changes in one step, for the pointer and the keyboard alike. */
169
169
  const motionRowLayer = "before:transition-none";
170
+ /** A rim drawn as an overlay of its own — an empty selection mark's lip, a drop target's dashes —
171
+ * carries its own feedback timing: it steps up on hover and fades as a selection fill arrives,
172
+ * on the same press curve as the surface beneath it. */
173
+ const motionRim = "after:transition-[background-color,border-color,opacity] after:duration-press after:ease-press motion-reduce:after:transition-none";
170
174
  const motionStateLayer = "before:transition-opacity before:duration-release before:ease-release active:before:duration-tactile active:before:ease-press group-active:before:duration-tactile group-active:before:ease-press motion-reduce:before:transition-none";
171
175
  /* `disclose` is the in-flow counterpart of presence: nothing mounts or unmounts, and nothing
172
176
  leaves the page — one region changes its own height where it sits. Base measures the panel and
@@ -197,5 +201,5 @@ const motionPresenceSheet = /* @__PURE__ */ cx("transition-[transform,opacity] d
197
201
  already going instead of turning around. */
198
202
  const motionPresenceToast = /* @__PURE__ */ cx("transition-[transform,opacity,height] duration-overlay ease-glide", "data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit", "data-[swiping]:transition-none", "motion-reduce:transition-[opacity]", "data-[starting-style]:opacity-0", "data-[ending-style]:opacity-0", "data-[starting-style]:[transform:translateY(var(--sui-toast-from-y,150%))]", "[&[data-ending-style]:not([data-swipe-direction])]:[transform:translateY(var(--sui-toast-from-y,150%))]", "data-[ending-style]:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y,0px)+150%))]", "data-[ending-style]:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y,0px)-150%))]", "data-[ending-style]:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x,0px)-150%))]", "data-[ending-style]:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x,0px)+150%))]", "motion-reduce:data-[starting-style]:transform-none", "motion-reduce:data-[ending-style]:transform-none");
199
203
 
200
- export { motionActivityIndeterminate, motionActivityPulse, motionActivitySpin, motionArrive, motionDirect, motionDisclose, motionFeedback, motionInkPress, motionOrient, motionPresenceAnchored, motionPresenceModal, motionPresenceScrim, motionPresenceSheet, motionPresenceToast, motionPresenceTooltip, motionRelocate, motionRelocateLong, motionRowLayer, motionStateLayer, motionTactile, motionTactileField, motionTactileWide };
204
+ export { motionActivityIndeterminate, motionActivityPulse, motionActivitySpin, motionArrive, motionDirect, motionDisclose, motionFeedback, motionInkPress, motionOrient, motionPresenceAnchored, motionPresenceModal, motionPresenceScrim, motionPresenceSheet, motionPresenceToast, motionPresenceTooltip, motionRelocate, motionRelocateLong, motionRim, motionRowLayer, motionStateLayer, motionTactile, motionTactileField, motionTactileWide };
201
205
  //# sourceMappingURL=ui.motion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui.motion.js","sources":["../../../src/components/ui.motion.ts"],"sourcesContent":["/* Sherick UI motion grammar\n =========================\n Components describe what changes; this module exclusively describes how change moves.\n\n The canonical intents are:\n - feedback: non-spatial state response;\n - tactile: temporary physical response to activation;\n - arrive: a meaningful subordinate part appears or leaves;\n - orient: a persistent part changes orientation in place;\n - relocate: a persistent part moves or resizes between stable states;\n - direct: geometry continuously follows the user;\n - disclose: in-flow content expands and collapses;\n - presence: an independent surface enters/leaves;\n - activity: continuous motion that communicates ongoing work.\n\n Every recipe here owns the transition property, the duration, the curve and the\n `prefers-reduced-motion` behavior for one physical event. The durations and curves\n themselves are the authored tokens in `src/styles/tokens.ts`; nothing in this file\n writes a literal duration or an animation keyframe beyond the two activity loops.\n\n `docs/DESIGN_LANGUAGE.md` owns the semantics. Target geometry, material, tone and\n elevation remain component/anatomy concerns: a component says where something ends\n up, and this module says how it gets there. */\n\n/* A recipe that is composed from other recipes is built through `cx`, whose call is marked pure.\n That is load-bearing for the published bundles rather than a bundler detail: an unused recipe\n whose value is a template literal with a substitution in it is not provably side-effect-free, so\n it survives tree-shaking and every consumer that imports any part of this module pays for every\n recipe in it — including the families it never uses. See `libs/utils.ts`. */\nimport { cx } from \"@/libs/utils\";\n\nexport type MotionIntent =\n | \"feedback\"\n | \"tactile\"\n | \"arrive\"\n | \"orient\"\n | \"relocate\"\n | \"direct\"\n | \"disclose\"\n | \"presence\"\n | \"activity\";\n\n/** Non-spatial feedback: hover, focus, field tone, a highlighted row, a filled surface.\n * It never translates, scales or resizes; reduced motion simply drops the interpolation\n * and the state still arrives. */\nexport const motionFeedback =\n \"transition-[background-color,color,box-shadow,opacity] duration-press ease-press motion-reduce:transition-none\";\n\n/** A control answers a press immediately and settles on its release.\n *\n * The recipe owns the *amplitude* of that answer as well as its timing, because how far a press\n * travels is the system's physical character rather than a component's anatomy. A percentage is a\n * distance only once it meets a size, so the amplitude comes in tiers chosen by the control's role:\n *\n * - `motionTactile`: a content-width control — a button, a chip, a segment — compresses 4%, about\n * two pixels at the size of the ink it moves.\n * - `motionTactileWide`: a control that spans a track — a tab — compresses 1.5%, so its edges move\n * about as far as a button's.\n * - `motionTactileField`: a list-opening field — a Select trigger, an editable Combobox — spans\n * its whole container, and 4% of a 580px field moved each edge 11.6px. It compresses 0.7%, about\n * two pixels at that width: the field acknowledges the press without lurching.\n *\n * The press leg runs on `duration-tactile`, short enough to land inside a tap; the release settles\n * on the release timing. A control whose visible ink is far smaller than its target takes\n * `motionInkPress` on that ink instead, so the target itself never moves. The interpolation and\n * the compression are neutralised together under reduced motion. */\n/* Base may disable the surface itself or the value control inside a Select wrapper.\n Neither is a pressable surface. Timing is otherwise shared by every tier. */\nconst tactileTiming =\n \"transition-[background-color,color,box-shadow,transform,opacity] duration-release ease-release active:duration-tactile active:ease-press motion-reduce:transition-none\";\n\nexport const motionTactile = /* @__PURE__ */ cx(\n tactileTiming,\n \"motion-safe:[&:not([data-disabled],:disabled,:has(>[role=combobox][data-disabled]))]:active:scale-[0.96]\"\n);\n\nexport const motionTactileWide = /* @__PURE__ */ cx(\n tactileTiming,\n \"motion-safe:[&:not([data-disabled],:disabled)]:active:scale-[0.985]\"\n);\n\nexport const motionTactileField = /* @__PURE__ */ cx(\n tactileTiming,\n \"motion-safe:[&:not([data-disabled],:disabled,:has(>[role=combobox][data-disabled]))]:active:scale-[0.993]\"\n);\n\n/** The spatial half of a compact press, applied to the *mark* rather than to the control.\n *\n * A control whose visible ink is much smaller than the target it is aimed at — a dialog's close\n * control, a stepper, a search field's submit — is a large target around a small glyph, and only\n * the glyph is visible at rest. Compressing the whole control would shrink the ground the pointer\n * is already on (a 44px target becomes 38.7px while held, which is exactly where a near-edge\n * release lands), so the mark takes the twelve percent and the target keeps its geometry. The\n * target still owns the focus ring and the state layer, and still carries the tone and depth\n * response, so the boundary a press happens inside never moves. */\nexport const motionInkPress =\n \"transition-transform duration-release ease-release group-active:duration-tactile group-active:ease-press group-active:scale-[0.88] motion-reduce:transition-none motion-reduce:group-active:scale-100\";\n\n/* Motion is not owned here — but the recipes above are the whole vocabulary: every press, arrival,\n travel, presence and activity in the library is one of these names plus its owner's own target\n geometry. */\n\n/* A field that opens a list — a `Select`'s trigger, an editable `Combobox`'s field — takes\n `motionTactile` as a whole, which is what makes the two forms of the same control press\n identically. The *field* is the element that carries the compression in both: a press activates\n the whole chain, so a descendant being pressed is what makes the field itself match `:active`\n (and a select trigger's own active state is suppressed by the primitive, so its field's wrapper\n is the only element left to carry it). Typing, focus and hover never match it, so the field is\n perfectly still while it is used as a text field; a press that places a caret or drags across a\n word is the same press the field already answers, and distinguishing it would take pointer\n bookkeeping inside a component for a case that reads as one interaction either way. */\n\n/** A meaningful subordinate part arrives. Spring is reserved for this intent: a mark is\n * made by overshooting the position it lands in. It leaves without the overshoot, and\n * reduced motion lands it in one step — which takes a *state-specific* override, because the\n * starting state is a higher-specificity rule than a plain `transform: none` and would otherwise\n * win under reduced motion while the transition was gone, turning a spring into an instant jump. */\nexport const motionArrive =\n \"transition-[background-color,color,box-shadow,transform,opacity] duration-release ease-spring data-[starting-style]:scale-50 data-[ending-style]:scale-50 data-[ending-style]:opacity-0 data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit motion-reduce:transition-none motion-reduce:transform-none motion-reduce:data-[starting-style]:scale-100 motion-reduce:data-[ending-style]:scale-100\";\n\n/** A persistent affordance changes orientation in place: a disclosure chevron. It reaches\n * its target orientation consistently and never overshoots. */\nexport const motionOrient =\n \"transition-transform duration-release ease-release motion-reduce:transition-none\";\n\n/** A persistent object travels between stable destinations: a tab indicator, a switch\n * thumb. The travel itself is the event, so it takes the glide curve rather than the\n * arrival curve, and it never overshoots: a destination that is passed and come back\n * from reads as a defect. Position, size and the tone the object picks up on the way\n * settle together, and an interrupted move retargets from wherever it currently is\n * because it is a transition and not a keyframe. */\nexport const motionRelocate =\n \"transition-[left,inset-inline-start,top,width,height,transform,background-color,color,box-shadow,opacity] duration-release ease-glide motion-reduce:transition-none\";\n\n/** The same travel across a whole track — a tab indicator — on the longer travel timing, so a\n * movement of hundreds of pixels is followed rather than skipped. */\nexport const motionRelocateLong =\n \"transition-[left,inset-inline-start,top,width,height,transform,background-color,color,box-shadow,opacity] duration-travel ease-glide motion-reduce:transition-none\";\n\n/** Direct manipulation: the pointer owns the geometry, so a positional transition would be\n * lag. While the primitive reports a drag, position and size are removed from the\n * transition list and only tone and engagement geometry remain; a keyboard or programmatic\n * step still settles. Reduced motion never changes direct manipulation. */\nexport const motionDirect =\n \"transition-[inset-inline-start,width,height,background-color,color,box-shadow,transform,opacity] duration-release ease-release active:duration-press active:ease-press data-[dragging]:transition-[background-color,color,box-shadow,transform,opacity] motion-reduce:transition-none motion-reduce:transform-none\";\n\n/* Anchored popup, tooltip, modal, sheet, toast and scrim presence share three states:\n settled, `data-starting-style` and `data-ending-style`. The primitive decides\n when the node mounts and unmounts.\n None of them writes an animation keyframe or a timer, so a rapid open → close → open\n retargets from the current painted value instead of restarting.\n\n The anchored roles read their entrance direction from the resolved side. Base publishes\n the side on the popup after collision handling and the origin as `--transform-origin`, so\n a surface below its trigger rises into place, one above it settles down into it, and one\n flipped by a collision animates the way it is actually placed. */\n\nconst anchoredGeometry = /* @__PURE__ */ cx(\n \"[transform-origin:var(--transform-origin)]\",\n \"[--sui-overlay-from-shift-y:-4px]\",\n \"data-[side=top]:[--sui-overlay-from-shift-y:4px]\",\n \"data-[side=left]:[--sui-overlay-from-shift-y:0px] data-[side=left]:[--sui-overlay-from-shift-x:4px]\",\n \"data-[side=right]:[--sui-overlay-from-shift-y:0px] data-[side=right]:[--sui-overlay-from-shift-x:-4px]\",\n /* The logical sides resolve against the writing direction: `inline-start` puts the popup at the\n anchor's inline-start edge, which is its physical *left* on a left-to-right page and its\n physical *right* on a right-to-left one, so the four pixels that travel toward the anchor\n change sign with the page while the physical sides above never do. The direction is read from\n the `dir` attribute — the attribute that lays the page out, and the only one a portaled\n surface can see. The primitive resolves the side from the direction *it* is told about\n (`DirectionProvider`), so a consumer whose page is right-to-left declares that direction to\n both, exactly as the workbench's RTL specimens do. */\n \"data-[side=inline-start]:[--sui-overlay-from-shift-y:0px] data-[side=inline-start]:[--sui-overlay-from-shift-x:4px]\",\n \"[[dir=rtl]_&]:data-[side=inline-start]:[--sui-overlay-from-shift-x:-4px]\",\n \"data-[side=inline-end]:[--sui-overlay-from-shift-y:0px] data-[side=inline-end]:[--sui-overlay-from-shift-x:-4px]\",\n \"[[dir=rtl]_&]:data-[side=inline-end]:[--sui-overlay-from-shift-x:4px]\",\n);\n\n/* Both ends of a presence animation start from the same state, and reduced motion drops the\n spatial half of it: presence still reads as arriving, but only through opacity. The\n transform is a literal class rather than an interpolated one, because the stylesheet\n compiler reads class names as text: a name that only exists once a template is evaluated\n compiles to no rule at all. */\nconst anchoredFrom = /* @__PURE__ */ cx(\n \"data-[starting-style]:opacity-0\",\n \"data-[starting-style]:[transform:translate(var(--sui-overlay-from-shift-x,0px),var(--sui-overlay-from-shift-y,0px))scale(var(--sui-overlay-from-scale,1))]\",\n \"data-[ending-style]:opacity-0\",\n \"data-[ending-style]:[transform:translate(var(--sui-overlay-from-shift-x,0px),var(--sui-overlay-from-shift-y,0px))scale(var(--sui-overlay-from-scale,1))]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n\nconst modalFrom = /* @__PURE__ */ cx(\n \"data-[starting-style]:opacity-0\",\n \"data-[starting-style]:[transform:translate(0,12px)scale(0.96)]\",\n \"data-[ending-style]:opacity-0\",\n \"data-[ending-style]:[transform:translate(0,12px)scale(0.96)]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n\n/** An anchored surface: `Select`, `Combobox`, `Menu` and `Popover`. It grows out of the edge\n * it is attached to, enters on the overlay timing, and leaves on the shorter exit.\n *\n * The grow is the motion's signature and the four pixels of travel only support it, so the\n * entrance takes the glide curve rather than the arrival curve. With a front-loaded curve the\n * opacity and the scale both jump in the first frames, which means the surface is already half\n * grown by the time it is visible at all — a pop, not a grow. The glide curve spends its whole\n * duration visible, so the eye actually sees the surface open out of its anchor. */\nexport const motionPresenceAnchored = /* @__PURE__ */ cx(\n \"transition-[opacity,transform] duration-overlay ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n \"[--sui-overlay-from-scale:0.94]\",\n anchoredGeometry,\n anchoredFrom,\n);\n\n/** A tooltip: the same side-aware model and the same grow as an anchored popup, deliberately\n * lighter — it settles on the local timing rather than the overlay timing, and it never\n * bounces. */\nexport const motionPresenceTooltip = /* @__PURE__ */ cx(\n \"transition-[opacity,transform] duration-release ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n \"[--sui-overlay-from-scale:0.94]\",\n anchoredGeometry,\n anchoredFrom,\n);\n\n/** A modal surface: anchored to the viewport rather than to a trigger, so it has no side\n * to grow from. A large surface never bounces; it fades, rises a little and settles, and its\n * scale stays restrained because a plane this big grows visibly even from a few percent. */\nexport const motionPresenceModal = /* @__PURE__ */ cx(\n \"transition-[opacity,transform] duration-overlay ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n modalFrom,\n);\n\n/** The plane behind a surface that owns the viewport. Opacity only: a blur or a filter is\n * never animated, so the plane can never animate the page behind it. */\nexport const motionPresenceScrim =\n \"transition-opacity duration-overlay ease-release data-[starting-style]:opacity-0 data-[ending-style]:opacity-0 data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\";\n\n/** Continuous activity is a distinct intent, not an exception to interaction motion: it\n * reports work rather than answering an event, and it has no entrance of its own. */\nexport const motionActivitySpin = \"animate-spin motion-reduce:animate-none\";\nexport const motionActivityPulse = \"animate-pulse motion-reduce:animate-none\";\n\n/** The indeterminate half of a progress bar. A task with no known value cannot report a\n * position, so it reports *work* instead: the fill sweeps across its own track on the one loop\n * that is paced, because a loop that reports rather than answers cannot arrive. The travel is a\n * composited transform rather than a laid-out edge, and an endless loop must never sit on the\n * layout path; the direction is a value the recipe flips with the writing direction, because a\n * transform is physical and the sweep follows the page. Under reduced motion the loop stops and\n * the fill rests where it starts: a static status glyph, exactly as the spin and the pulse rest. */\nexport const motionActivityIndeterminate =\n \"animate-sherick-indeterminate [[dir=rtl]_&]:[--sui-indeterminate-direction:-1] motion-reduce:animate-none\";\n\n/** The state layer is a composited overlay, so its own opacity is the only thing that\n * moves. Shared here because four interaction states across the library ride it. */\n/** A row in a collection moves its highlight rather than fading it: a highlight is where the reader\n * is, and arrowing through a list with a soft fade on every row leaves a smear of half-lit rows.\n * The row's layer therefore changes in one step, for the pointer and the keyboard alike. */\nexport const motionRowLayer = \"before:transition-none\";\n\nexport const motionStateLayer =\n \"before:transition-opacity before:duration-release before:ease-release active:before:duration-tactile active:before:ease-press group-active:before:duration-tactile group-active:before:ease-press motion-reduce:before:transition-none\";\n\n/* `disclose` is the in-flow counterpart of presence: nothing mounts or unmounts, and nothing\n leaves the page — one region changes its own height where it sits. Base measures the panel and\n publishes that height, so the geometry is the primitive's and only the interpolation is here.\n The panel states the height it opens to; this recipe owns how it gets there, and reduced\n motion applies the layout state in one step rather than travelling through it. */\nexport const motionDisclose =\n \"transition-[height] duration-release ease-release data-[starting-style]:h-0 data-[ending-style]:h-0 data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit motion-reduce:transition-none\";\n\n/* A sheet is a surface that owns the viewport and is attached to one edge of it, so its presence is\n a slide out of that edge rather than the modal lift, and it never bounces. The component names the\n edge by setting exactly one of `--sui-sheet-from-x` / `--sui-sheet-from-y` to a full own-extent\n offset, because which edge a sheet is attached to is anatomy; how far it travels and how long it\n takes are not.\n\n The other axis is `0px`, and that default is load-bearing: a fallback of `100%` on the axis the\n component did not set would translate a side sheet on both axes at once, so a sheet attached to\n the right edge would enter from the bottom-right corner and travel diagonally instead of\n straight in. One edge means one axis. */\nexport const motionPresenceSheet = /* @__PURE__ */ cx(\n \"transition-[transform,opacity] duration-sheet ease-glide\",\n \"data-[ending-style]:duration-sheet-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n \"data-[starting-style]:opacity-0\",\n \"data-[ending-style]:opacity-0\",\n \"data-[starting-style]:[transform:translate(var(--sui-sheet-from-x,0px),var(--sui-sheet-from-y,0px))]\",\n \"data-[ending-style]:[transform:translate(var(--sui-sheet-from-x,0px),var(--sui-sheet-from-y,0px))]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n\n/* A toast is a stack, not a single surface: several independent surfaces share one corner,\n re-flow when one of them leaves, and can each be flung away by the pointer. That is one\n spatial owner on one node, and this is it.\n\n The component owns where a toast rests — its stacked offset, its clamped height and the\n expanded fan are geometry — and sets `--sui-toast-from-y` to the direction the stack grows in.\n This recipe owns the entrance, the exit, the stack's re-flow, and the gesture: while\n `data-swiping` is set the node follows the pointer with no interpolation at all, and a\n dismissal carries the movement it was flung with so the toast keeps travelling the way it was\n already going instead of turning around. */\nexport const motionPresenceToast = /* @__PURE__ */ cx(\n \"transition-[transform,opacity,height] duration-overlay ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"data-[swiping]:transition-none\",\n \"motion-reduce:transition-[opacity]\",\n \"data-[starting-style]:opacity-0\",\n \"data-[ending-style]:opacity-0\",\n \"data-[starting-style]:[transform:translateY(var(--sui-toast-from-y,150%))]\",\n \"[&[data-ending-style]:not([data-swipe-direction])]:[transform:translateY(var(--sui-toast-from-y,150%))]\",\n \"data-[ending-style]:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y,0px)+150%))]\",\n \"data-[ending-style]:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y,0px)-150%))]\",\n \"data-[ending-style]:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x,0px)-150%))]\",\n \"data-[ending-style]:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x,0px)+150%))]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;;;;;AAsBiD;AAEjD;;;;AAI+E;AAc/E;;AAEmC;AAC5B,MAAM,cAAc,GACzB;AAEF;;;;;;;;;;;;;;;;;AAiBqE;AACrE;AAC+E;AAC/E,MAAM,aAAa,GACjB,wKAAwK;AAEnK,MAAM,aAAa,mBAAmB,EAAE,CAC7C,aAAa,EACb,0GAA0G;AAGrG,MAAM,iBAAiB,mBAAmB,EAAE,CACjD,aAAa,EACb,qEAAqE;AAGhE,MAAM,kBAAkB,mBAAmB,EAAE,CAClD,aAAa,EACb,2GAA2G;AAG7G;;;;;;;;AAQoE;AAC7D,MAAM,cAAc,GACzB;AAEF;;AAEe;AAEf;;;;;;;;AAQyF;AAEzF;;;;AAIqG;AAC9F,MAAM,YAAY,GACvB;AAEF;AACgE;AACzD,MAAM,YAAY,GACvB;AAEF;;;;;AAKqD;AAC9C,MAAM,cAAc,GACzB;AAEF;AACsE;AAC/D,MAAM,kBAAkB,GAC7B;AAEF;;;AAG4E;AACrE,MAAM,YAAY,GACvB;AAEF;;;;;;;;;AASoE;AAEpE,MAAM,gBAAgB,mBAAmB,EAAE,CACzC,4CAA4C,EAC5C,mCAAmC,EACnC,kDAAkD,EAClD,qGAAqG,EACrG,wGAAwG;AACxG;;;;;;;AAOwD;AACxD,qHAAqH,EACrH,0EAA0E,EAC1E,kHAAkH,EAClH,uEAAuE,CACxE;AAED;;;;AAIiC;AACjC,MAAM,YAAY,mBAAmB,EAAE,CACrC,iCAAiC,EACjC,4JAA4J,EAC5J,+BAA+B,EAC/B,0JAA0J,EAC1J,oDAAoD,EACpD,kDAAkD,CACnD;AAED,MAAM,SAAS,mBAAmB,EAAE,CAClC,iCAAiC,EACjC,gEAAgE,EAChE,+BAA+B,EAC/B,8DAA8D,EAC9D,oDAAoD,EACpD,kDAAkD,CACnD;AAED;;;;;;;AAOqF;MACxE,sBAAsB,mBAAmB,EAAE,CACtD,4DAA4D,EAC5D,yEAAyE,EACzE,oCAAoC,EACpC,iCAAiC,EACjC,gBAAgB,EAChB,YAAY;AAGd;;AAEe;MACF,qBAAqB,mBAAmB,EAAE,CACrD,4DAA4D,EAC5D,yEAAyE,EACzE,oCAAoC,EACpC,iCAAiC,EACjC,gBAAgB,EAChB,YAAY;AAGd;;AAE6F;AACtF,MAAM,mBAAmB,mBAAmB,EAAE,CACnD,4DAA4D,EAC5D,yEAAyE,EACzE,oCAAoC,EACpC,SAAS;AAGX;AACyE;AAClE,MAAM,mBAAmB,GAC9B;AAEF;AACsF;AAC/E,MAAM,kBAAkB,GAAG;AAC3B,MAAM,mBAAmB,GAAG;AAEnC;;;;;;AAMqG;AAC9F,MAAM,2BAA2B,GACtC;AAEF;AACqF;AACrF;;AAE6F;AACtF,MAAM,cAAc,GAAG;AAEvB,MAAM,gBAAgB,GAC3B;AAEF;;;;AAIoF;AAC7E,MAAM,cAAc,GACzB;AAEF;;;;;;;;;AAS2C;AACpC,MAAM,mBAAmB,mBAAmB,EAAE,CACnD,0DAA0D,EAC1D,uEAAuE,EACvE,oCAAoC,EACpC,iCAAiC,EACjC,+BAA+B,EAC/B,sGAAsG,EACtG,oGAAoG,EACpG,oDAAoD,EACpD,kDAAkD;AAGpD;;;;;;;;;AAS8C;AACvC,MAAM,mBAAmB,mBAAmB,EAAE,CACnD,mEAAmE,EACnE,yEAAyE,EACzE,gCAAgC,EAChC,oCAAoC,EACpC,iCAAiC,EACjC,+BAA+B,EAC/B,4EAA4E,EAC5E,yGAAyG,EACzG,sHAAsH,EACtH,oHAAoH,EACpH,sHAAsH,EACtH,uHAAuH,EACvH,oDAAoD,EACpD,kDAAkD;;"}
1
+ {"version":3,"file":"ui.motion.js","sources":["../../../src/components/ui.motion.ts"],"sourcesContent":["/* Sherick UI motion grammar\n =========================\n Components describe what changes; this module exclusively describes how change moves.\n\n The canonical intents are:\n - feedback: non-spatial state response;\n - tactile: temporary physical response to activation;\n - arrive: a meaningful subordinate part appears or leaves;\n - orient: a persistent part changes orientation in place;\n - relocate: a persistent part moves or resizes between stable states;\n - direct: geometry continuously follows the user;\n - disclose: in-flow content expands and collapses;\n - presence: an independent surface enters/leaves;\n - activity: continuous motion that communicates ongoing work.\n\n Every recipe here owns the transition property, the duration, the curve and the\n `prefers-reduced-motion` behavior for one physical event. The durations and curves\n themselves are the authored tokens in `src/styles/tokens.ts`; nothing in this file\n writes a literal duration or an animation keyframe beyond the two activity loops.\n\n `docs/DESIGN_LANGUAGE.md` owns the semantics. Target geometry, material, tone and\n elevation remain component/anatomy concerns: a component says where something ends\n up, and this module says how it gets there. */\n\n/* A recipe that is composed from other recipes is built through `cx`, whose call is marked pure.\n That is load-bearing for the published bundles rather than a bundler detail: an unused recipe\n whose value is a template literal with a substitution in it is not provably side-effect-free, so\n it survives tree-shaking and every consumer that imports any part of this module pays for every\n recipe in it — including the families it never uses. See `libs/utils.ts`. */\nimport { cx } from \"@/libs/utils\";\n\nexport type MotionIntent =\n | \"feedback\"\n | \"tactile\"\n | \"arrive\"\n | \"orient\"\n | \"relocate\"\n | \"direct\"\n | \"disclose\"\n | \"presence\"\n | \"activity\";\n\n/** Non-spatial feedback: hover, focus, field tone, a highlighted row, a filled surface.\n * It never translates, scales or resizes; reduced motion simply drops the interpolation\n * and the state still arrives. */\nexport const motionFeedback =\n \"transition-[background-color,border-color,color,box-shadow,opacity] duration-press ease-press motion-reduce:transition-none\";\n\n/** A control answers a press immediately and settles on its release.\n *\n * The recipe owns the *amplitude* of that answer as well as its timing, because how far a press\n * travels is the system's physical character rather than a component's anatomy. A percentage is a\n * distance only once it meets a size, so the amplitude comes in tiers chosen by the control's role:\n *\n * - `motionTactile`: a content-width control — a button, a chip, a segment — compresses 4%, about\n * two pixels at the size of the ink it moves.\n * - `motionTactileWide`: a control that spans a track — a tab — compresses 1.5%, so its edges move\n * about as far as a button's.\n * - `motionTactileField`: a list-opening field — a Select trigger, an editable Combobox — spans\n * its whole container, and 4% of a 580px field moved each edge 11.6px. It compresses 0.7%, about\n * two pixels at that width: the field acknowledges the press without lurching.\n *\n * The press leg runs on `duration-tactile`, short enough to land inside a tap; the release settles\n * on the release timing. A control whose visible ink is far smaller than its target takes\n * `motionInkPress` on that ink instead, so the target itself never moves. The interpolation and\n * the compression are neutralised together under reduced motion. */\n/* Base may disable the surface itself or the value control inside a Select wrapper.\n Neither is a pressable surface. Timing is otherwise shared by every tier. */\nconst tactileTiming =\n \"transition-[background-color,color,box-shadow,transform,opacity] duration-release ease-release active:duration-tactile active:ease-press motion-reduce:transition-none\";\n\nexport const motionTactile = /* @__PURE__ */ cx(\n tactileTiming,\n \"motion-safe:[&:not([data-disabled],:disabled,:has(>[role=combobox][data-disabled]))]:active:scale-[0.96]\"\n);\n\nexport const motionTactileWide = /* @__PURE__ */ cx(\n tactileTiming,\n \"motion-safe:[&:not([data-disabled],:disabled)]:active:scale-[0.985]\"\n);\n\nexport const motionTactileField = /* @__PURE__ */ cx(\n tactileTiming,\n \"motion-safe:[&:not([data-disabled],:disabled,:has(>[role=combobox][data-disabled]))]:active:scale-[0.993]\"\n);\n\n/** The spatial half of a compact press, applied to the *mark* rather than to the control.\n *\n * A control whose visible ink is much smaller than the target it is aimed at — a dialog's close\n * control, a stepper, a search field's submit — is a large target around a small glyph, and only\n * the glyph is visible at rest. Compressing the whole control would shrink the ground the pointer\n * is already on (a 44px target becomes 38.7px while held, which is exactly where a near-edge\n * release lands), so the mark takes the twelve percent and the target keeps its geometry. The\n * target still owns the focus ring and the state layer, and still carries the tone and depth\n * response, so the boundary a press happens inside never moves. */\nexport const motionInkPress =\n \"transition-transform duration-release ease-release group-active:duration-tactile group-active:ease-press group-active:scale-[0.88] motion-reduce:transition-none motion-reduce:group-active:scale-100\";\n\n/* Motion is not owned here — but the recipes above are the whole vocabulary: every press, arrival,\n travel, presence and activity in the library is one of these names plus its owner's own target\n geometry. */\n\n/* A field that opens a list — a `Select`'s trigger, an editable `Combobox`'s field — takes\n `motionTactile` as a whole, which is what makes the two forms of the same control press\n identically. The *field* is the element that carries the compression in both: a press activates\n the whole chain, so a descendant being pressed is what makes the field itself match `:active`\n (and a select trigger's own active state is suppressed by the primitive, so its field's wrapper\n is the only element left to carry it). Typing, focus and hover never match it, so the field is\n perfectly still while it is used as a text field; a press that places a caret or drags across a\n word is the same press the field already answers, and distinguishing it would take pointer\n bookkeeping inside a component for a case that reads as one interaction either way. */\n\n/** A meaningful subordinate part arrives. Spring is reserved for this intent: a mark is\n * made by overshooting the position it lands in. It leaves without the overshoot, and\n * reduced motion lands it in one step — which takes a *state-specific* override, because the\n * starting state is a higher-specificity rule than a plain `transform: none` and would otherwise\n * win under reduced motion while the transition was gone, turning a spring into an instant jump. */\nexport const motionArrive =\n \"transition-[background-color,color,box-shadow,transform,opacity] duration-release ease-spring data-[starting-style]:scale-50 data-[ending-style]:scale-50 data-[ending-style]:opacity-0 data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit motion-reduce:transition-none motion-reduce:transform-none motion-reduce:data-[starting-style]:scale-100 motion-reduce:data-[ending-style]:scale-100\";\n\n/** A persistent affordance changes orientation in place: a disclosure chevron. It reaches\n * its target orientation consistently and never overshoots. */\nexport const motionOrient =\n \"transition-transform duration-release ease-release motion-reduce:transition-none\";\n\n/** A persistent object travels between stable destinations: a tab indicator, a switch\n * thumb. The travel itself is the event, so it takes the glide curve rather than the\n * arrival curve, and it never overshoots: a destination that is passed and come back\n * from reads as a defect. Position, size and the tone the object picks up on the way\n * settle together, and an interrupted move retargets from wherever it currently is\n * because it is a transition and not a keyframe. */\nexport const motionRelocate =\n \"transition-[left,inset-inline-start,top,width,height,transform,background-color,color,box-shadow,opacity] duration-release ease-glide motion-reduce:transition-none\";\n\n/** The same travel across a whole track — a tab indicator — on the longer travel timing, so a\n * movement of hundreds of pixels is followed rather than skipped. */\nexport const motionRelocateLong =\n \"transition-[left,inset-inline-start,top,width,height,transform,background-color,color,box-shadow,opacity] duration-travel ease-glide motion-reduce:transition-none\";\n\n/** Direct manipulation: the pointer owns the geometry, so a positional transition would be\n * lag. While the primitive reports a drag, position and size are removed from the\n * transition list and only tone and engagement geometry remain; a keyboard or programmatic\n * step still settles. Reduced motion never changes direct manipulation. */\nexport const motionDirect =\n \"transition-[inset-inline-start,width,height,background-color,color,box-shadow,transform,opacity] duration-release ease-release active:duration-press active:ease-press data-[dragging]:transition-[background-color,color,box-shadow,transform,opacity] motion-reduce:transition-none motion-reduce:transform-none\";\n\n/* Anchored popup, tooltip, modal, sheet, toast and scrim presence share three states:\n settled, `data-starting-style` and `data-ending-style`. The primitive decides\n when the node mounts and unmounts.\n None of them writes an animation keyframe or a timer, so a rapid open → close → open\n retargets from the current painted value instead of restarting.\n\n The anchored roles read their entrance direction from the resolved side. Base publishes\n the side on the popup after collision handling and the origin as `--transform-origin`, so\n a surface below its trigger rises into place, one above it settles down into it, and one\n flipped by a collision animates the way it is actually placed. */\n\nconst anchoredGeometry = /* @__PURE__ */ cx(\n \"[transform-origin:var(--transform-origin)]\",\n \"[--sui-overlay-from-shift-y:-4px]\",\n \"data-[side=top]:[--sui-overlay-from-shift-y:4px]\",\n \"data-[side=left]:[--sui-overlay-from-shift-y:0px] data-[side=left]:[--sui-overlay-from-shift-x:4px]\",\n \"data-[side=right]:[--sui-overlay-from-shift-y:0px] data-[side=right]:[--sui-overlay-from-shift-x:-4px]\",\n /* The logical sides resolve against the writing direction: `inline-start` puts the popup at the\n anchor's inline-start edge, which is its physical *left* on a left-to-right page and its\n physical *right* on a right-to-left one, so the four pixels that travel toward the anchor\n change sign with the page while the physical sides above never do. The direction is read from\n the `dir` attribute — the attribute that lays the page out, and the only one a portaled\n surface can see. The primitive resolves the side from the direction *it* is told about\n (`DirectionProvider`), so a consumer whose page is right-to-left declares that direction to\n both, exactly as the workbench's RTL specimens do. */\n \"data-[side=inline-start]:[--sui-overlay-from-shift-y:0px] data-[side=inline-start]:[--sui-overlay-from-shift-x:4px]\",\n \"[[dir=rtl]_&]:data-[side=inline-start]:[--sui-overlay-from-shift-x:-4px]\",\n \"data-[side=inline-end]:[--sui-overlay-from-shift-y:0px] data-[side=inline-end]:[--sui-overlay-from-shift-x:-4px]\",\n \"[[dir=rtl]_&]:data-[side=inline-end]:[--sui-overlay-from-shift-x:4px]\",\n);\n\n/* Both ends of a presence animation start from the same state, and reduced motion drops the\n spatial half of it: presence still reads as arriving, but only through opacity. The\n transform is a literal class rather than an interpolated one, because the stylesheet\n compiler reads class names as text: a name that only exists once a template is evaluated\n compiles to no rule at all. */\nconst anchoredFrom = /* @__PURE__ */ cx(\n \"data-[starting-style]:opacity-0\",\n \"data-[starting-style]:[transform:translate(var(--sui-overlay-from-shift-x,0px),var(--sui-overlay-from-shift-y,0px))scale(var(--sui-overlay-from-scale,1))]\",\n \"data-[ending-style]:opacity-0\",\n \"data-[ending-style]:[transform:translate(var(--sui-overlay-from-shift-x,0px),var(--sui-overlay-from-shift-y,0px))scale(var(--sui-overlay-from-scale,1))]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n\nconst modalFrom = /* @__PURE__ */ cx(\n \"data-[starting-style]:opacity-0\",\n \"data-[starting-style]:[transform:translate(0,12px)scale(0.96)]\",\n \"data-[ending-style]:opacity-0\",\n \"data-[ending-style]:[transform:translate(0,12px)scale(0.96)]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n\n/** An anchored surface: `Select`, `Combobox`, `Menu` and `Popover`. It grows out of the edge\n * it is attached to, enters on the overlay timing, and leaves on the shorter exit.\n *\n * The grow is the motion's signature and the four pixels of travel only support it, so the\n * entrance takes the glide curve rather than the arrival curve. With a front-loaded curve the\n * opacity and the scale both jump in the first frames, which means the surface is already half\n * grown by the time it is visible at all — a pop, not a grow. The glide curve spends its whole\n * duration visible, so the eye actually sees the surface open out of its anchor. */\nexport const motionPresenceAnchored = /* @__PURE__ */ cx(\n \"transition-[opacity,transform] duration-overlay ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n \"[--sui-overlay-from-scale:0.94]\",\n anchoredGeometry,\n anchoredFrom,\n);\n\n/** A tooltip: the same side-aware model and the same grow as an anchored popup, deliberately\n * lighter — it settles on the local timing rather than the overlay timing, and it never\n * bounces. */\nexport const motionPresenceTooltip = /* @__PURE__ */ cx(\n \"transition-[opacity,transform] duration-release ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n \"[--sui-overlay-from-scale:0.94]\",\n anchoredGeometry,\n anchoredFrom,\n);\n\n/** A modal surface: anchored to the viewport rather than to a trigger, so it has no side\n * to grow from. A large surface never bounces; it fades, rises a little and settles, and its\n * scale stays restrained because a plane this big grows visibly even from a few percent. */\nexport const motionPresenceModal = /* @__PURE__ */ cx(\n \"transition-[opacity,transform] duration-overlay ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n modalFrom,\n);\n\n/** The plane behind a surface that owns the viewport. Opacity only: a blur or a filter is\n * never animated, so the plane can never animate the page behind it. */\nexport const motionPresenceScrim =\n \"transition-opacity duration-overlay ease-release data-[starting-style]:opacity-0 data-[ending-style]:opacity-0 data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\";\n\n/** Continuous activity is a distinct intent, not an exception to interaction motion: it\n * reports work rather than answering an event, and it has no entrance of its own. */\nexport const motionActivitySpin = \"animate-spin motion-reduce:animate-none\";\nexport const motionActivityPulse = \"animate-pulse motion-reduce:animate-none\";\n\n/** The indeterminate half of a progress bar. A task with no known value cannot report a\n * position, so it reports *work* instead: the fill sweeps across its own track on the one loop\n * that is paced, because a loop that reports rather than answers cannot arrive. The travel is a\n * composited transform rather than a laid-out edge, and an endless loop must never sit on the\n * layout path; the direction is a value the recipe flips with the writing direction, because a\n * transform is physical and the sweep follows the page. Under reduced motion the loop stops and\n * the fill rests where it starts: a static status glyph, exactly as the spin and the pulse rest. */\nexport const motionActivityIndeterminate =\n \"animate-sherick-indeterminate [[dir=rtl]_&]:[--sui-indeterminate-direction:-1] motion-reduce:animate-none\";\n\n/** The state layer is a composited overlay, so its own opacity is the only thing that\n * moves. Shared here because four interaction states across the library ride it. */\n/** A row in a collection moves its highlight rather than fading it: a highlight is where the reader\n * is, and arrowing through a list with a soft fade on every row leaves a smear of half-lit rows.\n * The row's layer therefore changes in one step, for the pointer and the keyboard alike. */\nexport const motionRowLayer = \"before:transition-none\";\n\n/** A rim drawn as an overlay of its own — an empty selection mark's lip, a drop target's dashes —\n * carries its own feedback timing: it steps up on hover and fades as a selection fill arrives,\n * on the same press curve as the surface beneath it. */\nexport const motionRim =\n \"after:transition-[background-color,border-color,opacity] after:duration-press after:ease-press motion-reduce:after:transition-none\";\n\nexport const motionStateLayer =\n \"before:transition-opacity before:duration-release before:ease-release active:before:duration-tactile active:before:ease-press group-active:before:duration-tactile group-active:before:ease-press motion-reduce:before:transition-none\";\n\n/* `disclose` is the in-flow counterpart of presence: nothing mounts or unmounts, and nothing\n leaves the page — one region changes its own height where it sits. Base measures the panel and\n publishes that height, so the geometry is the primitive's and only the interpolation is here.\n The panel states the height it opens to; this recipe owns how it gets there, and reduced\n motion applies the layout state in one step rather than travelling through it. */\nexport const motionDisclose =\n \"transition-[height] duration-release ease-release data-[starting-style]:h-0 data-[ending-style]:h-0 data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit motion-reduce:transition-none\";\n\n/* A sheet is a surface that owns the viewport and is attached to one edge of it, so its presence is\n a slide out of that edge rather than the modal lift, and it never bounces. The component names the\n edge by setting exactly one of `--sui-sheet-from-x` / `--sui-sheet-from-y` to a full own-extent\n offset, because which edge a sheet is attached to is anatomy; how far it travels and how long it\n takes are not.\n\n The other axis is `0px`, and that default is load-bearing: a fallback of `100%` on the axis the\n component did not set would translate a side sheet on both axes at once, so a sheet attached to\n the right edge would enter from the bottom-right corner and travel diagonally instead of\n straight in. One edge means one axis. */\nexport const motionPresenceSheet = /* @__PURE__ */ cx(\n \"transition-[transform,opacity] duration-sheet ease-glide\",\n \"data-[ending-style]:duration-sheet-exit data-[ending-style]:ease-exit\",\n \"motion-reduce:transition-[opacity]\",\n \"data-[starting-style]:opacity-0\",\n \"data-[ending-style]:opacity-0\",\n \"data-[starting-style]:[transform:translate(var(--sui-sheet-from-x,0px),var(--sui-sheet-from-y,0px))]\",\n \"data-[ending-style]:[transform:translate(var(--sui-sheet-from-x,0px),var(--sui-sheet-from-y,0px))]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n\n/* A toast is a stack, not a single surface: several independent surfaces share one corner,\n re-flow when one of them leaves, and can each be flung away by the pointer. That is one\n spatial owner on one node, and this is it.\n\n The component owns where a toast rests — its stacked offset, its clamped height and the\n expanded fan are geometry — and sets `--sui-toast-from-y` to the direction the stack grows in.\n This recipe owns the entrance, the exit, the stack's re-flow, and the gesture: while\n `data-swiping` is set the node follows the pointer with no interpolation at all, and a\n dismissal carries the movement it was flung with so the toast keeps travelling the way it was\n already going instead of turning around. */\nexport const motionPresenceToast = /* @__PURE__ */ cx(\n \"transition-[transform,opacity,height] duration-overlay ease-glide\",\n \"data-[ending-style]:duration-overlay-exit data-[ending-style]:ease-exit\",\n \"data-[swiping]:transition-none\",\n \"motion-reduce:transition-[opacity]\",\n \"data-[starting-style]:opacity-0\",\n \"data-[ending-style]:opacity-0\",\n \"data-[starting-style]:[transform:translateY(var(--sui-toast-from-y,150%))]\",\n \"[&[data-ending-style]:not([data-swipe-direction])]:[transform:translateY(var(--sui-toast-from-y,150%))]\",\n \"data-[ending-style]:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y,0px)+150%))]\",\n \"data-[ending-style]:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y,0px)-150%))]\",\n \"data-[ending-style]:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x,0px)-150%))]\",\n \"data-[ending-style]:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x,0px)+150%))]\",\n \"motion-reduce:data-[starting-style]:transform-none\",\n \"motion-reduce:data-[ending-style]:transform-none\",\n);\n"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;;;;;AAsBiD;AAEjD;;;;AAI+E;AAc/E;;AAEmC;AAC5B,MAAM,cAAc,GACzB;AAEF;;;;;;;;;;;;;;;;;AAiBqE;AACrE;AAC+E;AAC/E,MAAM,aAAa,GACjB,wKAAwK;AAEnK,MAAM,aAAa,mBAAmB,EAAE,CAC7C,aAAa,EACb,0GAA0G;AAGrG,MAAM,iBAAiB,mBAAmB,EAAE,CACjD,aAAa,EACb,qEAAqE;AAGhE,MAAM,kBAAkB,mBAAmB,EAAE,CAClD,aAAa,EACb,2GAA2G;AAG7G;;;;;;;;AAQoE;AAC7D,MAAM,cAAc,GACzB;AAEF;;AAEe;AAEf;;;;;;;;AAQyF;AAEzF;;;;AAIqG;AAC9F,MAAM,YAAY,GACvB;AAEF;AACgE;AACzD,MAAM,YAAY,GACvB;AAEF;;;;;AAKqD;AAC9C,MAAM,cAAc,GACzB;AAEF;AACsE;AAC/D,MAAM,kBAAkB,GAC7B;AAEF;;;AAG4E;AACrE,MAAM,YAAY,GACvB;AAEF;;;;;;;;;AASoE;AAEpE,MAAM,gBAAgB,mBAAmB,EAAE,CACzC,4CAA4C,EAC5C,mCAAmC,EACnC,kDAAkD,EAClD,qGAAqG,EACrG,wGAAwG;AACxG;;;;;;;AAOwD;AACxD,qHAAqH,EACrH,0EAA0E,EAC1E,kHAAkH,EAClH,uEAAuE,CACxE;AAED;;;;AAIiC;AACjC,MAAM,YAAY,mBAAmB,EAAE,CACrC,iCAAiC,EACjC,4JAA4J,EAC5J,+BAA+B,EAC/B,0JAA0J,EAC1J,oDAAoD,EACpD,kDAAkD,CACnD;AAED,MAAM,SAAS,mBAAmB,EAAE,CAClC,iCAAiC,EACjC,gEAAgE,EAChE,+BAA+B,EAC/B,8DAA8D,EAC9D,oDAAoD,EACpD,kDAAkD,CACnD;AAED;;;;;;;AAOqF;MACxE,sBAAsB,mBAAmB,EAAE,CACtD,4DAA4D,EAC5D,yEAAyE,EACzE,oCAAoC,EACpC,iCAAiC,EACjC,gBAAgB,EAChB,YAAY;AAGd;;AAEe;MACF,qBAAqB,mBAAmB,EAAE,CACrD,4DAA4D,EAC5D,yEAAyE,EACzE,oCAAoC,EACpC,iCAAiC,EACjC,gBAAgB,EAChB,YAAY;AAGd;;AAE6F;AACtF,MAAM,mBAAmB,mBAAmB,EAAE,CACnD,4DAA4D,EAC5D,yEAAyE,EACzE,oCAAoC,EACpC,SAAS;AAGX;AACyE;AAClE,MAAM,mBAAmB,GAC9B;AAEF;AACsF;AAC/E,MAAM,kBAAkB,GAAG;AAC3B,MAAM,mBAAmB,GAAG;AAEnC;;;;;;AAMqG;AAC9F,MAAM,2BAA2B,GACtC;AAEF;AACqF;AACrF;;AAE6F;AACtF,MAAM,cAAc,GAAG;AAE9B;;AAEyD;AAClD,MAAM,SAAS,GACpB;AAEK,MAAM,gBAAgB,GAC3B;AAEF;;;;AAIoF;AAC7E,MAAM,cAAc,GACzB;AAEF;;;;;;;;;AAS2C;AACpC,MAAM,mBAAmB,mBAAmB,EAAE,CACnD,0DAA0D,EAC1D,uEAAuE,EACvE,oCAAoC,EACpC,iCAAiC,EACjC,+BAA+B,EAC/B,sGAAsG,EACtG,oGAAoG,EACpG,oDAAoD,EACpD,kDAAkD;AAGpD;;;;;;;;;AAS8C;AACvC,MAAM,mBAAmB,mBAAmB,EAAE,CACnD,mEAAmE,EACnE,yEAAyE,EACzE,gCAAgC,EAChC,oCAAoC,EACpC,iCAAiC,EACjC,+BAA+B,EAC/B,4EAA4E,EAC5E,yGAAyG,EACzG,sHAAsH,EACtH,oHAAoH,EACpH,sHAAsH,EACtH,uHAAuH,EACvH,oDAAoD,EACpD,kDAAkD;;"}
package/dist/esm/dev.js CHANGED
@@ -1,4 +1,4 @@
1
- export { currentDestination, density, detail, disclosure, edge, edgeTone, elevation, fieldLayout, fieldMessage, focusRing, focusRingDrag, focusRingHeld, focusRingInset, focusRingWithin, groupFocusRing, hitArea, iconSlot, list, material, matteInset, mediaCanvas, overlay, parentFocusRingInset, recessedTop, recipeAlphas, selectable, selectableRowSurface, shape, stacking, state, stateLayer, stateLayerQuietComposite, text, tone, type } from './components/ui.common.js';
2
- export { motionActivityIndeterminate, motionActivityPulse, motionActivitySpin, motionArrive, motionDirect, motionDisclose, motionFeedback, motionInkPress, motionOrient, motionPresenceAnchored, motionPresenceModal, motionPresenceScrim, motionPresenceSheet, motionPresenceToast, motionPresenceTooltip, motionRelocate, motionRelocateLong, motionRowLayer, motionStateLayer, motionTactile, motionTactileField, motionTactileWide } from './components/ui.motion.js';
1
+ export { currentDestination, density, detail, disclosure, edge, edgeTone, elevation, fieldLayout, fieldMessage, focusRing, focusRingDrag, focusRingHeld, focusRingInset, focusRingWithin, groupFocusRing, hitArea, iconSlot, list, material, matteInset, mediaCanvas, overlay, parentFocusRingInset, recessedTop, recipeAlphas, rim, selectable, selectableRowSurface, shape, stacking, state, stateLayer, stateLayerQuietComposite, text, tone, type } from './components/ui.common.js';
2
+ export { motionActivityIndeterminate, motionActivityPulse, motionActivitySpin, motionArrive, motionDirect, motionDisclose, motionFeedback, motionInkPress, motionOrient, motionPresenceAnchored, motionPresenceModal, motionPresenceScrim, motionPresenceSheet, motionPresenceToast, motionPresenceTooltip, motionRelocate, motionRelocateLong, motionRim, motionRowLayer, motionStateLayer, motionTactile, motionTactileField, motionTactileWide } from './components/ui.motion.js';
3
3
  export { cn } from './libs/utils.js';
4
4
  //# sourceMappingURL=dev.js.map
package/dist/styles.css CHANGED
@@ -11,6 +11,7 @@
11
11
  --sui-ink: 0.245 0.018 260;
12
12
  --sui-ink-muted: 0.480 0.018 260;
13
13
  --sui-detail: 0.600 0.016 258;
14
+ --sui-rim: 0.630 0.016 258;
14
15
  --sui-primary: 0.422 0.139 255;
15
16
  --sui-primary-strong: 0.402 0.143 257;
16
17
  --sui-primary-soft: 0.920 0.035 255;
@@ -41,7 +42,7 @@
41
42
  --sui-elevation-control: 0 1px 2px oklch(var(--sui-light-bottom) / 0.19), inset 0 1px 0 oklch(var(--sui-light-top) / 0.55);
42
43
  --sui-elevation-recessed: inset 0 1px 3px oklch(var(--sui-light-bottom) / 0.22), inset 0 -1px 0 oklch(var(--sui-light-top) / 0.50);
43
44
  --sui-elevation-recessed-top: inset 0 5px 8px -5px oklch(var(--sui-light-bottom) / 0.21);
44
- --sui-elevation-well: inset 0 3px 4px oklch(var(--sui-light-bottom) / 0.62), inset 0 -1px 0 oklch(var(--sui-light-top) / 0.50);
45
+ --sui-elevation-well: inset 0 2px 4px oklch(var(--sui-light-bottom) / 0.40), inset 0 -1px 0 oklch(var(--sui-light-top) / 0.50);
45
46
  --sui-glass-fill: 0.98;
46
47
  --sui-glass-blur: 28px;
47
48
  --sui-glass-saturation: 1.06;
@@ -78,6 +79,7 @@
78
79
  --sui-ink: 0.94 0.008 255;
79
80
  --sui-ink-muted: 0.76 0.014 255;
80
81
  --sui-detail: 0.600 0.014 256;
82
+ --sui-rim: 0.555 0.014 256;
81
83
  --sui-primary: 0.809 0.098 255;
82
84
  --sui-primary-strong: 0.734 0.139 257;
83
85
  --sui-primary-soft: 0.325 0.050 257;
@@ -108,7 +110,7 @@
108
110
  --sui-elevation-control: 0 1px 2px oklch(var(--sui-light-bottom) / 0.30), inset 0 1px 0 oklch(var(--sui-light-top) / 0.08);
109
111
  --sui-elevation-recessed: inset 0 1px 3px oklch(var(--sui-light-bottom) / 0.38), inset 0 -1px 0 oklch(var(--sui-light-top) / 0.06);
110
112
  --sui-elevation-recessed-top: inset 0 5px 8px -5px oklch(var(--sui-light-bottom) / 0.36);
111
- --sui-elevation-well: inset 0 1px 3px oklch(var(--sui-light-bottom) / 0.38), inset 0 -2px 3px oklch(var(--sui-light-top) / 0.40);
113
+ --sui-elevation-well: inset 0 2px 4px oklch(var(--sui-light-bottom) / 0.60), inset 0 -1px 0 oklch(var(--sui-light-top) / 0.06);
112
114
  --sui-glass-fill: 0.98;
113
115
  --sui-glass-blur: 32px;
114
116
  --sui-glass-saturation: 1.10;
@@ -146,6 +148,7 @@
146
148
  --sui-ink: 0.94 0.008 255;
147
149
  --sui-ink-muted: 0.76 0.014 255;
148
150
  --sui-detail: 0.600 0.014 256;
151
+ --sui-rim: 0.555 0.014 256;
149
152
  --sui-primary: 0.809 0.098 255;
150
153
  --sui-primary-strong: 0.734 0.139 257;
151
154
  --sui-primary-soft: 0.325 0.050 257;
@@ -176,7 +179,7 @@
176
179
  --sui-elevation-control: 0 1px 2px oklch(var(--sui-light-bottom) / 0.30), inset 0 1px 0 oklch(var(--sui-light-top) / 0.08);
177
180
  --sui-elevation-recessed: inset 0 1px 3px oklch(var(--sui-light-bottom) / 0.38), inset 0 -1px 0 oklch(var(--sui-light-top) / 0.06);
178
181
  --sui-elevation-recessed-top: inset 0 5px 8px -5px oklch(var(--sui-light-bottom) / 0.36);
179
- --sui-elevation-well: inset 0 1px 3px oklch(var(--sui-light-bottom) / 0.38), inset 0 -2px 3px oklch(var(--sui-light-top) / 0.40);
182
+ --sui-elevation-well: inset 0 2px 4px oklch(var(--sui-light-bottom) / 0.60), inset 0 -1px 0 oklch(var(--sui-light-top) / 0.06);
180
183
  --sui-glass-fill: 0.98;
181
184
  --sui-glass-blur: 32px;
182
185
  --sui-glass-saturation: 1.10;
@@ -206,6 +209,7 @@
206
209
 
207
210
  :root {
208
211
  --sui-font-mono: ui-monospace, "SF Mono", SFMono-Regular, "Cascadia Code", "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace;
212
+ --sui-rim-dashed: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' rx='16' fill='none' stroke='%23000' stroke-width='3' stroke-dasharray='7' stroke-linecap='round'/%3E%3C/svg%3E");
209
213
  --sui-duration-press: 150ms;
210
214
  --sui-duration-release: 200ms;
211
215
  --sui-duration-tactile: 80ms;
@@ -403,6 +407,10 @@
403
407
  margin-left: 1rem;
404
408
  margin-right: 1rem
405
409
  }
410
+ :where(.sui-scope).my-0\.5 {
411
+ margin-top: 0.125rem;
412
+ margin-bottom: 0.125rem
413
+ }
406
414
  :where(.sui-scope).my-1 {
407
415
  margin-top: 0.25rem;
408
416
  margin-bottom: 0.25rem
@@ -537,9 +545,9 @@
537
545
  width: 2.5rem;
538
546
  height: 2.5rem
539
547
  }
540
- :where(.sui-scope).size-2\.5 {
541
- width: 0.625rem;
542
- height: 0.625rem
548
+ :where(.sui-scope).size-2 {
549
+ width: 0.5rem;
550
+ height: 0.5rem
543
551
  }
544
552
  :where(.sui-scope).size-3\.5 {
545
553
  width: 0.875rem;
@@ -992,8 +1000,8 @@
992
1000
  :where(.sui-scope).rounded {
993
1001
  border-radius: 0.25rem
994
1002
  }
995
- :where(.sui-scope).rounded-\[0\.625rem\] {
996
- border-radius: 0.625rem
1003
+ :where(.sui-scope).rounded-\[0\.375rem\] {
1004
+ border-radius: 0.375rem
997
1005
  }
998
1006
  :where(.sui-scope).rounded-\[0\.75rem\] {
999
1007
  border-radius: 0.75rem
@@ -1035,6 +1043,9 @@
1035
1043
  :where(.sui-scope).border-0 {
1036
1044
  border-width: 0px
1037
1045
  }
1046
+ :where(.sui-scope).border-\[1\.5px\] {
1047
+ border-width: 1.5px
1048
+ }
1038
1049
  :where(.sui-scope).border-b {
1039
1050
  border-bottom-width: 1px
1040
1051
  }
@@ -1050,6 +1061,10 @@
1050
1061
  :where(.sui-scope).border-t {
1051
1062
  border-top-width: 1px
1052
1063
  }
1064
+ :where(.sui-scope).border-sherick-danger {
1065
+ --tw-border-opacity: 1;
1066
+ border-color: oklch(var(--sui-danger) / var(--tw-border-opacity, 1))
1067
+ }
1053
1068
  :where(.sui-scope).border-sherick-detail {
1054
1069
  --tw-border-opacity: 1;
1055
1070
  border-color: oklch(var(--sui-detail) / var(--tw-border-opacity, 1))
@@ -1063,9 +1078,17 @@
1063
1078
  :where(.sui-scope).border-sherick-edge\/\[0\.10\] {
1064
1079
  border-color: oklch(var(--sui-edge) / 0.10)
1065
1080
  }
1081
+ :where(.sui-scope).border-sherick-ink-muted {
1082
+ --tw-border-opacity: 1;
1083
+ border-color: oklch(var(--sui-ink-muted) / var(--tw-border-opacity, 1))
1084
+ }
1066
1085
  :where(.sui-scope).border-sherick-primary\/\[0\.45\] {
1067
1086
  border-color: oklch(var(--sui-primary) / 0.45)
1068
1087
  }
1088
+ :where(.sui-scope).border-sherick-rim {
1089
+ --tw-border-opacity: 1;
1090
+ border-color: oklch(var(--sui-rim) / var(--tw-border-opacity, 1))
1091
+ }
1069
1092
  :where(.sui-scope).border-e-transparent {
1070
1093
  border-inline-end-color: transparent
1071
1094
  }
@@ -1079,6 +1102,9 @@
1079
1102
  :where(.sui-scope).bg-sherick-canvas\/\[0\.28\] {
1080
1103
  background-color: oklch(var(--sui-canvas) / 0.28)
1081
1104
  }
1105
+ :where(.sui-scope).bg-sherick-canvas\/\[0\.7\] {
1106
+ background-color: oklch(var(--sui-canvas) / 0.7)
1107
+ }
1082
1108
  :where(.sui-scope).bg-sherick-danger {
1083
1109
  --tw-bg-opacity: 1;
1084
1110
  background-color: oklch(var(--sui-danger) / var(--tw-bg-opacity, 1))
@@ -1091,12 +1117,6 @@
1091
1117
  --tw-bg-opacity: 1;
1092
1118
  background-color: oklch(var(--sui-danger-soft) / var(--tw-bg-opacity, 1))
1093
1119
  }
1094
- :where(.sui-scope).bg-sherick-danger\/\[0\.075\] {
1095
- background-color: oklch(var(--sui-danger) / 0.075)
1096
- }
1097
- :where(.sui-scope).bg-sherick-danger\/\[0\.13\] {
1098
- background-color: oklch(var(--sui-danger) / 0.13)
1099
- }
1100
1120
  :where(.sui-scope).bg-sherick-detail {
1101
1121
  --tw-bg-opacity: 1;
1102
1122
  background-color: oklch(var(--sui-detail) / var(--tw-bg-opacity, 1))
@@ -1152,18 +1172,12 @@
1152
1172
  :where(.sui-scope).bg-sherick-surface-high\/\[0\.56\] {
1153
1173
  background-color: oklch(var(--sui-surface-high) / 0.56)
1154
1174
  }
1155
- :where(.sui-scope).bg-sherick-surface-high\/\[0\.66\] {
1156
- background-color: oklch(var(--sui-surface-high) / 0.66)
1157
- }
1158
1175
  :where(.sui-scope).bg-sherick-surface-high\/\[0\.72\] {
1159
1176
  background-color: oklch(var(--sui-surface-high) / 0.72)
1160
1177
  }
1161
1178
  :where(.sui-scope).bg-sherick-surface-high\/\[0\.82\] {
1162
1179
  background-color: oklch(var(--sui-surface-high) / 0.82)
1163
1180
  }
1164
- :where(.sui-scope).bg-sherick-surface-high\/\[0\.9\] {
1165
- background-color: oklch(var(--sui-surface-high) / 0.9)
1166
- }
1167
1181
  :where(.sui-scope).bg-sherick-surface-overlay\/\[var\(--sui-overlay-fill\)\] {
1168
1182
  background-color: oklch(var(--sui-surface-overlay) / var(--sui-overlay-fill))
1169
1183
  }
@@ -1302,6 +1316,10 @@
1302
1316
  padding-top: 0.5rem;
1303
1317
  padding-bottom: 0.5rem
1304
1318
  }
1319
+ :where(.sui-scope).py-2\.5 {
1320
+ padding-top: 0.625rem;
1321
+ padding-bottom: 0.625rem
1322
+ }
1305
1323
  :where(.sui-scope).py-3 {
1306
1324
  padding-top: 0.75rem;
1307
1325
  padding-bottom: 0.75rem
@@ -1663,8 +1681,8 @@
1663
1681
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1664
1682
  transition-duration: 150ms
1665
1683
  }
1666
- :where(.sui-scope).transition-\[background-color\2c color\2c box-shadow\2c opacity\] {
1667
- transition-property: background-color,color,box-shadow,opacity;
1684
+ :where(.sui-scope).transition-\[background-color\2c border-color\2c color\2c box-shadow\2c opacity\] {
1685
+ transition-property: background-color,border-color,color,box-shadow,opacity;
1668
1686
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1669
1687
  transition-duration: 150ms
1670
1688
  }
@@ -1897,6 +1915,10 @@
1897
1915
  --tw-content: '';
1898
1916
  content: var(--tw-content)
1899
1917
  }
1918
+ :where(.sui-scope).after\:pointer-events-none::after {
1919
+ content: var(--tw-content);
1920
+ pointer-events: none
1921
+ }
1900
1922
  :where(.sui-scope).after\:pointer-events-auto::after {
1901
1923
  content: var(--tw-content);
1902
1924
  pointer-events: auto
@@ -1905,14 +1927,66 @@
1905
1927
  content: var(--tw-content);
1906
1928
  position: absolute
1907
1929
  }
1930
+ :where(.sui-scope).after\:inset-0::after {
1931
+ content: var(--tw-content);
1932
+ inset: 0px
1933
+ }
1908
1934
  :where(.sui-scope).after\:inset-\[min\(0px\2c calc\(\(100\%-2\.75rem\)\/2\)\)\]::after {
1909
1935
  content: var(--tw-content);
1910
1936
  inset: min(0px, calc((100% - 2.75rem) / 2))
1911
1937
  }
1938
+ :where(.sui-scope).after\:box-border::after {
1939
+ content: var(--tw-content);
1940
+ box-sizing: border-box
1941
+ }
1942
+ :where(.sui-scope).after\:rounded-\[inherit\]::after {
1943
+ content: var(--tw-content);
1944
+ border-radius: inherit
1945
+ }
1946
+ :where(.sui-scope).after\:border-\[1\.5px\]::after {
1947
+ content: var(--tw-content);
1948
+ border-width: 1.5px
1949
+ }
1950
+ :where(.sui-scope).after\:border-sherick-rim::after {
1951
+ content: var(--tw-content);
1952
+ --tw-border-opacity: 1;
1953
+ border-color: oklch(var(--sui-rim) / var(--tw-border-opacity, 1))
1954
+ }
1955
+ :where(.sui-scope).after\:bg-sherick-rim::after {
1956
+ content: var(--tw-content);
1957
+ --tw-bg-opacity: 1;
1958
+ background-color: oklch(var(--sui-rim) / var(--tw-bg-opacity, 1))
1959
+ }
1960
+ :where(.sui-scope).after\:transition-\[background-color\2c border-color\2c opacity\]::after {
1961
+ content: var(--tw-content);
1962
+ transition-property: background-color,border-color,opacity;
1963
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1964
+ transition-duration: 150ms
1965
+ }
1966
+ :where(.sui-scope).after\:duration-press::after {
1967
+ content: var(--tw-content);
1968
+ transition-duration: var(--sui-duration-press)
1969
+ }
1970
+ :where(.sui-scope).after\:ease-press::after {
1971
+ content: var(--tw-content);
1972
+ transition-timing-function: var(--sui-ease-press)
1973
+ }
1912
1974
  :where(.sui-scope).after\:content-\[\'\'\]::after {
1913
1975
  --tw-content: '';
1914
1976
  content: var(--tw-content)
1915
1977
  }
1978
+ :where(.sui-scope).after\:\[mask-image\:var\(--sui-rim-dashed\)\]::after {
1979
+ content: var(--tw-content);
1980
+ mask-image: var(--sui-rim-dashed)
1981
+ }
1982
+ :where(.sui-scope).after\:\[mask-repeat\:no-repeat\]::after {
1983
+ content: var(--tw-content);
1984
+ mask-repeat: no-repeat
1985
+ }
1986
+ :where(.sui-scope).after\:\[mask-size\:100\%_100\%\]::after {
1987
+ content: var(--tw-content);
1988
+ mask-size: 100% 100%
1989
+ }
1916
1990
  :where(.sui-scope).first\:start-1:first-child {
1917
1991
  inset-inline-start: 0.25rem
1918
1992
  }
@@ -1925,15 +1999,16 @@
1925
1999
  :where(.sui-scope).last\:border-b-0:last-child {
1926
2000
  border-bottom-width: 0px
1927
2001
  }
1928
- :where(.sui-scope).hover\:bg-sherick-danger\/\[0\.10\]:hover {
1929
- background-color: oklch(var(--sui-danger) / 0.10)
2002
+ :where(.sui-scope).hover\:border-sherick-ink-muted:hover {
2003
+ --tw-border-opacity: 1;
2004
+ border-color: oklch(var(--sui-ink-muted) / var(--tw-border-opacity, 1))
2005
+ }
2006
+ :where(.sui-scope).hover\:bg-sherick-canvas\/\[0\.85\]:hover {
2007
+ background-color: oklch(var(--sui-canvas) / 0.85)
1930
2008
  }
1931
2009
  :where(.sui-scope).hover\:bg-sherick-ink\/\[0\.05\]:hover {
1932
2010
  background-color: oklch(var(--sui-ink) / 0.05)
1933
2011
  }
1934
- :where(.sui-scope).hover\:bg-sherick-surface-high\/\[0\.82\]:hover {
1935
- background-color: oklch(var(--sui-surface-high) / 0.82)
1936
- }
1937
2012
  :where(.sui-scope).hover\:text-sherick-ink:hover {
1938
2013
  --tw-text-opacity: 1;
1939
2014
  color: oklch(var(--sui-ink) / var(--tw-text-opacity, 1))
@@ -1941,11 +2016,18 @@
1941
2016
  :where(.sui-scope).hover\:decoration-sherick-primary:hover {
1942
2017
  text-decoration-color: oklch(var(--sui-primary) / 1)
1943
2018
  }
1944
- :where(.sui-scope).focus\:bg-sherick-danger\/\[0\.13\]:focus {
1945
- background-color: oklch(var(--sui-danger) / 0.13)
2019
+ :where(.sui-scope).hover\:after\:bg-sherick-ink-muted:hover::after {
2020
+ content: var(--tw-content);
2021
+ --tw-bg-opacity: 1;
2022
+ background-color: oklch(var(--sui-ink-muted) / var(--tw-bg-opacity, 1))
1946
2023
  }
1947
- :where(.sui-scope).focus\:bg-sherick-surface-high\/\[0\.9\]:focus {
1948
- background-color: oklch(var(--sui-surface-high) / 0.9)
2024
+ :where(.sui-scope).focus\:border-sherick-ink-muted:focus {
2025
+ --tw-border-opacity: 1;
2026
+ border-color: oklch(var(--sui-ink-muted) / var(--tw-border-opacity, 1))
2027
+ }
2028
+ :where(.sui-scope).focus\:bg-sherick-canvas:focus {
2029
+ --tw-bg-opacity: 1;
2030
+ background-color: oklch(var(--sui-canvas) / var(--tw-bg-opacity, 1))
1949
2031
  }
1950
2032
  :where(.sui-scope).focus\:outline-none:focus {
1951
2033
  outline: 2px solid transparent;
@@ -2050,6 +2132,20 @@
2050
2132
  content: var(--tw-content);
2051
2133
  transition-timing-function: var(--sui-ease-press)
2052
2134
  }
2135
+ :where(.sui-scope).group:not([data-disabled]):not([data-readonly]):not(:disabled):active :where(.sui-scope).group-\[\:not\(\[data-disabled\]\)\:not\(\[data-readonly\]\)\:not\(\:disabled\)\:active\]\:shadow-sherick-well {
2136
+ --tw-shadow: var(--sui-elevation-well);
2137
+ --tw-shadow-colored: var(--sui-elevation-well);
2138
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
2139
+ }
2140
+ :where(.sui-scope).group:not([data-disabled]):not([data-readonly]):not(:disabled):hover :where(.sui-scope).group-\[\:not\(\[data-disabled\]\)\:not\(\[data-readonly\]\)\:not\(\:disabled\)\:hover\]\:before\:opacity-\[0\.09\]::before {
2141
+ content: var(--tw-content);
2142
+ opacity: 0.09
2143
+ }
2144
+ :where(.sui-scope).group:not([data-disabled]):not([data-readonly]):not(:disabled):hover :where(.sui-scope).group-\[\:not\(\[data-disabled\]\)\:not\(\[data-readonly\]\)\:not\(\:disabled\)\:hover\]\:after\:border-sherick-ink-muted::after {
2145
+ content: var(--tw-content);
2146
+ --tw-border-opacity: 1;
2147
+ border-color: oklch(var(--sui-ink-muted) / var(--tw-border-opacity, 1))
2148
+ }
2053
2149
  :where(.sui-scope).group:not([data-disabled]) :where(.sui-scope).group-\[\:not\(\[data-disabled\]\)\]\:hover\:scale-110:hover {
2054
2150
  --tw-scale-x: 1.1;
2055
2151
  --tw-scale-y: 1.1;
@@ -2135,16 +2231,14 @@
2135
2231
  :where(.sui-scope).data-\[orientation\=vertical\]\:items-stretch[data-orientation="vertical"] {
2136
2232
  align-items: stretch
2137
2233
  }
2234
+ :where(.sui-scope).data-\[invalid\]\:border-sherick-danger[data-invalid] {
2235
+ --tw-border-opacity: 1;
2236
+ border-color: oklch(var(--sui-danger) / var(--tw-border-opacity, 1))
2237
+ }
2138
2238
  :where(.sui-scope).data-\[dragging\]\:bg-sherick-primary-strong[data-dragging] {
2139
2239
  --tw-bg-opacity: 1;
2140
2240
  background-color: oklch(var(--sui-primary-strong) / var(--tw-bg-opacity, 1))
2141
2241
  }
2142
- :where(.sui-scope).data-\[invalid\]\:bg-sherick-danger\/\[0\.075\][data-invalid] {
2143
- background-color: oklch(var(--sui-danger) / 0.075)
2144
- }
2145
- :where(.sui-scope).data-\[invalid\]\:bg-sherick-danger\/\[0\.13\][data-invalid] {
2146
- background-color: oklch(var(--sui-danger) / 0.13)
2147
- }
2148
2242
  :where(.sui-scope).data-\[dragging\]\:text-sherick-on-primary[data-dragging] {
2149
2243
  --tw-text-opacity: 1;
2150
2244
  color: oklch(var(--sui-on-primary) / var(--tw-text-opacity, 1))
@@ -2281,8 +2375,14 @@
2281
2375
  content: var(--tw-content);
2282
2376
  opacity: 0.05
2283
2377
  }
2284
- :where(.sui-scope).data-\[invalid\]\:hover\:bg-sherick-danger\/\[0\.10\]:hover[data-invalid] {
2285
- background-color: oklch(var(--sui-danger) / 0.10)
2378
+ :where(.sui-scope).data-\[dragging\]\:after\:bg-sherick-primary[data-dragging]::after {
2379
+ content: var(--tw-content);
2380
+ --tw-bg-opacity: 1;
2381
+ background-color: oklch(var(--sui-primary) / var(--tw-bg-opacity, 1))
2382
+ }
2383
+ :where(.sui-scope).data-\[invalid\]\:hover\:border-sherick-danger:hover[data-invalid] {
2384
+ --tw-border-opacity: 1;
2385
+ border-color: oklch(var(--sui-danger) / var(--tw-border-opacity, 1))
2286
2386
  }
2287
2387
  :where(.sui-scope).group[data-checked] :where(.sui-scope).group-data-\[checked\]\:h-6 {
2288
2388
  height: 1.5rem
@@ -2353,6 +2453,24 @@
2353
2453
  :where(.sui-scope).group\/field[data-disabled] :where(.sui-scope).group-data-\[disabled\]\/field\:opacity-100 {
2354
2454
  opacity: 1
2355
2455
  }
2456
+ :where(.sui-scope).group[data-checked] :where(.sui-scope).group-data-\[checked\]\:shadow-sherick-flat {
2457
+ --tw-shadow: var(--sui-elevation-flat);
2458
+ --tw-shadow-colored: var(--sui-elevation-flat);
2459
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
2460
+ }
2461
+ :where(.sui-scope).group[data-indeterminate] :where(.sui-scope).group-data-\[indeterminate\]\:shadow-sherick-flat {
2462
+ --tw-shadow: var(--sui-elevation-flat);
2463
+ --tw-shadow-colored: var(--sui-elevation-flat);
2464
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
2465
+ }
2466
+ :where(.sui-scope).group[data-checked] :where(.sui-scope).group-data-\[checked\]\:after\:opacity-0::after {
2467
+ content: var(--tw-content);
2468
+ opacity: 0
2469
+ }
2470
+ :where(.sui-scope).group[data-indeterminate] :where(.sui-scope).group-data-\[indeterminate\]\:after\:opacity-0::after {
2471
+ content: var(--tw-content);
2472
+ opacity: 0
2473
+ }
2356
2474
  @media (prefers-reduced-motion: reduce) {
2357
2475
  :where(.sui-scope).motion-reduce\:transform-none {
2358
2476
  transform: none
@@ -2372,6 +2490,10 @@
2372
2490
  content: var(--tw-content);
2373
2491
  transition-property: none
2374
2492
  }
2493
+ :where(.sui-scope).motion-reduce\:after\:transition-none::after {
2494
+ content: var(--tw-content);
2495
+ transition-property: none
2496
+ }
2375
2497
  :where(.sui-scope).group:active :where(.sui-scope).motion-reduce\:group-active\:scale-100 {
2376
2498
  --tw-scale-x: 1;
2377
2499
  --tw-scale-y: 1;
@@ -2425,11 +2547,17 @@
2425
2547
  outline-style: none
2426
2548
  }
2427
2549
  }
2428
- :where(.sui-scope).\[\&\&\]\:focus-within\:bg-sherick-surface-high\/\[0\.9\]:focus-within.\[\&\&\]\:focus-within\:bg-sherick-surface-high\/\[0\.9\]:focus-within {
2429
- background-color: oklch(var(--sui-surface-high) / 0.9)
2550
+ :where(.sui-scope).\[\&\&\]\:focus-within\:border-sherick-ink-muted:focus-within.\[\&\&\]\:focus-within\:border-sherick-ink-muted:focus-within {
2551
+ --tw-border-opacity: 1;
2552
+ border-color: oklch(var(--sui-ink-muted) / var(--tw-border-opacity, 1))
2430
2553
  }
2431
- :where(.sui-scope).\[\&\&\]\:data-\[invalid\]\:focus-within\:bg-sherick-danger\/\[0\.13\]:focus-within[data-invalid].\[\&\&\]\:data-\[invalid\]\:focus-within\:bg-sherick-danger\/\[0\.13\]:focus-within[data-invalid] {
2432
- background-color: oklch(var(--sui-danger) / 0.13)
2554
+ :where(.sui-scope).\[\&\&\]\:focus-within\:bg-sherick-canvas:focus-within.\[\&\&\]\:focus-within\:bg-sherick-canvas:focus-within {
2555
+ --tw-bg-opacity: 1;
2556
+ background-color: oklch(var(--sui-canvas) / var(--tw-bg-opacity, 1))
2557
+ }
2558
+ :where(.sui-scope).\[\&\&\]\:data-\[invalid\]\:focus-within\:border-sherick-danger:focus-within[data-invalid].\[\&\&\]\:data-\[invalid\]\:focus-within\:border-sherick-danger:focus-within[data-invalid] {
2559
+ --tw-border-opacity: 1;
2560
+ border-color: oklch(var(--sui-danger) / var(--tw-border-opacity, 1))
2433
2561
  }
2434
2562
  :where(.sui-scope).\[\&\:has\(\+div\:not\(\[data-open\]\)\:hover\)\]\:opacity-0:has(+div:not([data-open]):hover) {
2435
2563
  opacity: 0
@@ -2604,13 +2732,12 @@ div:not([data-open]):hover+:where(.sui-scope).\[div\:not\(\[data-open\]\)\:hover
2604
2732
  outline-offset: -2px;
2605
2733
  }
2606
2734
 
2607
- /* A *resting* mark is identified by the depth of its well, which forced colors flattens, so an
2608
- unchecked box and an unselected radio need a boundary of their own. It is CanvasText rather
2609
- than Highlight: this is component identity, not selection. */
2610
- :where(.sui-scope)[role="checkbox"][aria-checked="false"]:not(:focus-visible),
2735
+ /* A *resting* mark keeps its own rim, a real border that forced colors repaints in a system
2736
+ colour, so an unchecked box and an unselected radio need no extra boundary — and a radio's
2737
+ transparent utility outline, which forced colors would make opaque, must not become a second
2738
+ ring around that rim. */
2611
2739
  :where(.sui-scope)[role="radio"][aria-checked="false"]:not(:focus-visible) {
2612
- outline: 1px solid CanvasText;
2613
- outline-offset: -2px;
2740
+ outline: none;
2614
2741
  }
2615
2742
 
2616
2743
  /* A slider conveys its value through the fill of its groove and the depth of its handle, and
@@ -2620,6 +2747,21 @@ div:not([data-open]):hover+:where(.sui-scope).\[div\:not\(\[data-open\]\)\:hover
2620
2747
  border: 1px solid CanvasText;
2621
2748
  }
2622
2749
 
2750
+ /* A drop target's dashes are a masked fill, and forced colors would flatten that fill into the
2751
+ page. They keep a system colour, so the target still shows its boundary. */
2752
+ :where(.sui-scope)[data-sui-drop-target]::after {
2753
+ forced-color-adjust: none;
2754
+ background-color: CanvasText;
2755
+ }
2756
+
2757
+ /* A selected radio's thumb is a fill, and forced colors flattens it into its socket. It keeps a
2758
+ system colour of its own, so selection is a shape and not only the colour of the outline
2759
+ around the control. */
2760
+ :where(.sui-scope)[role="radio"][aria-checked="true"] :where(.sui-scope)[data-sui-radio-dot] {
2761
+ forced-color-adjust: none;
2762
+ background-color: Highlight;
2763
+ }
2764
+
2623
2765
  /* A progress bar says how far along the work is through the fill of its track alone, and
2624
2766
  forced colors flattens the fill into the track. The indicator carries a Sherick-owned marker
2625
2767
  for the same reason the slider thumb does: a primitive's own attributes are not component