@sableui/react 0.13.2 → 0.15.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 (203) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +172 -0
  3. package/CONTRIBUTING.md +6 -4
  4. package/DESIGN.md +10 -3
  5. package/dist/blocks/approval-block.js +93 -0
  6. package/dist/blocks/approval-block.meta.js +23 -0
  7. package/dist/blocks/index.d.ts +27 -1
  8. package/dist/blocks/index.js +8 -0
  9. package/dist/blocks/message-reactions-block.js +87 -0
  10. package/dist/blocks/message-reactions-block.meta.js +23 -0
  11. package/dist/components/accordion/accordion.meta.js +8 -2
  12. package/dist/components/area-chart/area-chart.meta.js +10 -3
  13. package/dist/components/attachment/attachment.meta.js +26 -0
  14. package/dist/components/bar-chart/bar-chart.meta.js +11 -4
  15. package/dist/components/bottom-nav/bottom-nav.js +3 -1
  16. package/dist/components/bottom-nav/bottom-nav.meta.js +32 -0
  17. package/dist/components/breadcrumbs/breadcrumbs.meta.js +26 -0
  18. package/dist/components/bubble/bubble.js +105 -5
  19. package/dist/components/bubble/bubble.meta.js +42 -6
  20. package/dist/components/bubble/bubble.variants.js +1 -1
  21. package/dist/components/bubble/index.js +2 -0
  22. package/dist/components/button/button.js +21 -4
  23. package/dist/components/button/button.meta.js +7 -7
  24. package/dist/components/calendar/calendar.js +18 -1
  25. package/dist/components/calendar/calendar.meta.js +38 -0
  26. package/dist/components/carousel/carousel.js +6 -4
  27. package/dist/components/carousel/carousel.meta.js +42 -0
  28. package/dist/components/chat-composer/chat-composer.js +21 -21
  29. package/dist/components/chat-composer/chat-composer.meta.js +38 -0
  30. package/dist/components/chat-composer/use-eased-growth.js +70 -0
  31. package/dist/components/checkbox/checkbox-mark.js +8 -1
  32. package/dist/components/checkbox/checkbox.js +3 -1
  33. package/dist/components/checkbox/checkbox.meta.js +32 -0
  34. package/dist/components/checkbox-card/checkbox-card.js +3 -0
  35. package/dist/components/checkbox-card/checkbox-card.meta.js +32 -0
  36. package/dist/components/code-block/code-block.js +14 -3
  37. package/dist/components/code-block/code-block.meta.js +28 -1
  38. package/dist/components/collapsible/collapsible.meta.js +32 -0
  39. package/dist/components/color-field/color-field.meta.js +26 -0
  40. package/dist/components/combobox/combobox.meta.js +44 -0
  41. package/dist/components/command-menu/command-menu.js +8 -3
  42. package/dist/components/command-menu/command-menu.meta.js +38 -0
  43. package/dist/components/confirm-button/confirm-button.js +179 -0
  44. package/dist/components/confirm-button/confirm-button.meta.js +143 -0
  45. package/dist/components/confirm-button/index.js +7 -0
  46. package/dist/components/data-table/data-table.js +6 -2
  47. package/dist/components/data-table/data-table.meta.js +32 -0
  48. package/dist/components/entity/entity.meta.js +26 -0
  49. package/dist/components/feedback/feedback.js +120 -47
  50. package/dist/components/feedback/feedback.meta.js +55 -4
  51. package/dist/components/input-group/input-group.meta.js +27 -1
  52. package/dist/components/like-button/index.js +7 -0
  53. package/dist/components/like-button/like-button.js +89 -0
  54. package/dist/components/like-button/like-button.meta.js +132 -0
  55. package/dist/components/line-chart/line-chart.meta.js +10 -3
  56. package/dist/components/middle-truncate/middle-truncate.meta.js +1 -1
  57. package/dist/components/note/note.meta.js +32 -0
  58. package/dist/components/notification-badge/notification-badge.js +17 -5
  59. package/dist/components/notification-badge/notification-badge.meta.js +34 -2
  60. package/dist/components/number-ticker/index.js +7 -0
  61. package/dist/components/number-ticker/number-ticker.js +246 -0
  62. package/dist/components/number-ticker/number-ticker.meta.js +159 -0
  63. package/dist/components/otp-field/otp-field.js +23 -3
  64. package/dist/components/otp-field/otp-field.meta.js +23 -2
  65. package/dist/components/panel-group/panel-group.meta.js +26 -0
  66. package/dist/components/panel-section/panel-section.js +37 -10
  67. package/dist/components/panel-section/panel-section.meta.js +32 -0
  68. package/dist/components/pie-chart/pie-chart.js +20 -11
  69. package/dist/components/pie-chart/pie-chart.meta.js +17 -4
  70. package/dist/components/pill/pill.meta.js +32 -0
  71. package/dist/components/radar-chart/radar-chart.js +4 -3
  72. package/dist/components/radar-chart/radar-chart.meta.js +10 -3
  73. package/dist/components/radial-chart/radial-chart.js +22 -22
  74. package/dist/components/radial-chart/radial-chart.meta.js +17 -4
  75. package/dist/components/radio/radio.meta.js +26 -0
  76. package/dist/components/radio-card/radio-card.meta.js +38 -0
  77. package/dist/components/reaction-picker/index.js +13 -0
  78. package/dist/components/reaction-picker/reaction-picker.js +104 -0
  79. package/dist/components/reaction-picker/reaction-picker.meta.js +156 -0
  80. package/dist/components/relative-time/relative-time.meta.js +32 -0
  81. package/dist/components/scroller/scroller.meta.js +32 -0
  82. package/dist/components/scrub-field/scrub-field.meta.js +32 -0
  83. package/dist/components/search-input/search-input.js +9 -7
  84. package/dist/components/search-input/search-input.meta.js +26 -0
  85. package/dist/components/show-more/show-more.js +1 -4
  86. package/dist/components/show-more/show-more.meta.js +38 -0
  87. package/dist/components/side-nav/side-nav.js +21 -1
  88. package/dist/components/side-nav/side-nav.meta.js +32 -0
  89. package/dist/components/side-nav/side-nav.variants.js +3 -1
  90. package/dist/components/sidebar/sidebar.js +31 -8
  91. package/dist/components/sidebar/sidebar.meta.js +38 -0
  92. package/dist/components/slider/slider.meta.js +26 -0
  93. package/dist/components/sparkline/sparkline.js +7 -4
  94. package/dist/components/sparkline/sparkline.meta.js +9 -2
  95. package/dist/components/table/table.meta.js +26 -0
  96. package/dist/components/tabs/tabs.js +27 -8
  97. package/dist/components/tabs/tabs.meta.js +46 -3
  98. package/dist/components/theme-selector/theme-selector.meta.js +32 -0
  99. package/dist/components/theme-switcher/theme-switcher.js +4 -1
  100. package/dist/components/theme-switcher/theme-switcher.meta.js +42 -0
  101. package/dist/components/toast/toast.js +25 -13
  102. package/dist/components/toast/toast.meta.js +7 -1
  103. package/dist/components/toggle/toggle.js +28 -5
  104. package/dist/components/toggle/toggle.meta.js +44 -2
  105. package/dist/components/tool-call/index.js +8 -0
  106. package/dist/components/tool-call/tool-call.js +117 -0
  107. package/dist/components/tool-call/tool-call.meta.js +147 -0
  108. package/dist/components/tool-call/tool-call.variants.js +33 -0
  109. package/dist/components/tooltip/index.js +3 -1
  110. package/dist/components/tooltip/tooltip.js +84 -0
  111. package/dist/components/tooltip/tooltip.meta.js +16 -1
  112. package/dist/components/tree/tree.js +71 -6
  113. package/dist/components/tree/tree.meta.js +32 -0
  114. package/dist/components/video/video.meta.js +32 -0
  115. package/dist/file-hashes.json +130 -104
  116. package/dist/foundations/motion.js +69 -3
  117. package/dist/icon-sets/reicon.js +11 -1
  118. package/dist/index.d.ts +907 -104
  119. package/dist/index.js +6 -1
  120. package/dist/lib/chart/cartesian.js +9 -10
  121. package/dist/lib/chart/chart-center.js +30 -0
  122. package/dist/lib/chart/chart-frame.js +15 -8
  123. package/dist/lib/chart/dim.js +13 -0
  124. package/dist/lib/chart/format.js +7 -1
  125. package/dist/lib/chart/motion.js +6 -4
  126. package/dist/lib/highlight-glide.js +68 -10
  127. package/dist/lib/taxonomy.js +5 -0
  128. package/dist/motion/Burst.js +79 -0
  129. package/dist/motion/MotionProvider.js +45 -3
  130. package/dist/motion/Reveal.js +1 -1
  131. package/dist/motion/TextReveal.js +1 -1
  132. package/dist/motion/index.js +17 -2
  133. package/dist/motion/useAutoSize.js +42 -0
  134. package/dist/motion/useShake.js +25 -0
  135. package/dist/styles.css +439 -5
  136. package/llms/blocks/approval-block.md +128 -0
  137. package/llms/blocks/message-reactions-block.md +116 -0
  138. package/llms/components/accordion.md +3 -2
  139. package/llms/components/area-chart.md +4 -3
  140. package/llms/components/attachment.md +7 -0
  141. package/llms/components/bar-chart.md +5 -4
  142. package/llms/components/bottom-nav.md +8 -0
  143. package/llms/components/breadcrumbs.md +7 -0
  144. package/llms/components/bubble.md +17 -7
  145. package/llms/components/button.md +6 -6
  146. package/llms/components/calendar.md +9 -0
  147. package/llms/components/carousel.md +17 -0
  148. package/llms/components/chat-composer.md +9 -0
  149. package/llms/components/checkbox-card.md +8 -0
  150. package/llms/components/checkbox.md +8 -0
  151. package/llms/components/code-block.md +8 -0
  152. package/llms/components/collapsible.md +8 -0
  153. package/llms/components/color-field.md +7 -0
  154. package/llms/components/combobox.md +10 -0
  155. package/llms/components/command-menu.md +9 -0
  156. package/llms/components/confirm-button.md +92 -0
  157. package/llms/components/data-table.md +8 -0
  158. package/llms/components/entity.md +7 -0
  159. package/llms/components/feedback.md +23 -3
  160. package/llms/components/input-group.md +8 -1
  161. package/llms/components/like-button.md +91 -0
  162. package/llms/components/line-chart.md +4 -3
  163. package/llms/components/middle-truncate.md +1 -1
  164. package/llms/components/note.md +8 -0
  165. package/llms/components/notification-badge.md +10 -2
  166. package/llms/components/number-ticker.md +86 -0
  167. package/llms/components/otp-field.md +15 -1
  168. package/llms/components/panel-group.md +7 -0
  169. package/llms/components/panel-section.md +8 -0
  170. package/llms/components/pie-chart.md +6 -4
  171. package/llms/components/pill.md +8 -0
  172. package/llms/components/radar-chart.md +4 -3
  173. package/llms/components/radial-chart.md +6 -4
  174. package/llms/components/radio-card.md +9 -0
  175. package/llms/components/radio.md +7 -0
  176. package/llms/components/reaction-picker.md +115 -0
  177. package/llms/components/relative-time.md +8 -0
  178. package/llms/components/scroller.md +8 -0
  179. package/llms/components/scrub-field.md +8 -0
  180. package/llms/components/search-input.md +7 -0
  181. package/llms/components/show-more.md +9 -0
  182. package/llms/components/side-nav.md +8 -0
  183. package/llms/components/sidebar.md +9 -0
  184. package/llms/components/slider.md +7 -0
  185. package/llms/components/sparkline.md +3 -2
  186. package/llms/components/table.md +7 -0
  187. package/llms/components/tabs.md +20 -2
  188. package/llms/components/theme-selector.md +8 -0
  189. package/llms/components/theme-switcher.md +17 -0
  190. package/llms/components/toast.md +2 -1
  191. package/llms/components/toggle.md +19 -2
  192. package/llms/components/tool-call.md +115 -0
  193. package/llms/components/tooltip.md +11 -1
  194. package/llms/components/tree.md +8 -0
  195. package/llms/components/video.md +8 -0
  196. package/llms/foundations/motion.md +64 -3
  197. package/llms/reference/utilities.md +26 -1
  198. package/llms/tasks/reviewing-motion.md +14 -0
  199. package/llms-full.txt +1337 -69
  200. package/llms.txt +19 -11
  201. package/package.json +1 -1
  202. package/registry.json +3040 -124
  203. package/targets/ios.json +45 -0
@@ -15,6 +15,7 @@ import {
15
15
  import { Icon } from "../../icon/index.js";
16
16
  import { cn } from "../../lib/cn.js";
17
17
  import { hitTargetMin } from "../../lib/hit-target.js";
18
+ import { motionAttribute, useMotionLevel } from "../../motion/MotionProvider.js";
18
19
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
20
  function treeIndent(depth) {
20
21
  return `calc(var(--tree-rail) + var(--tree-indent) * ${Math.max(0, depth)})`;
@@ -43,8 +44,39 @@ function useTreeItem(idProp) {
43
44
  claimFocus: () => ctx?.setFocusedId(id)
44
45
  };
45
46
  }
47
+ var ARRIVAL_CAP = 10;
48
+ var ARRIVAL_STEP_MS = 18;
49
+ function createArrival() {
50
+ const seen = /* @__PURE__ */ new Map();
51
+ return {
52
+ index(id) {
53
+ let at = seen.get(id);
54
+ if (at === void 0) {
55
+ at = seen.size;
56
+ seen.set(id, at);
57
+ }
58
+ return at;
59
+ }
60
+ };
61
+ }
62
+ var TreeArrivalContext = createContext(null);
63
+ var TreeMotionContext = createContext(void 0);
64
+ function arrivalProps(index) {
65
+ return {
66
+ className: "motion-arrive",
67
+ style: { "--motion-arrive-delay": `${Math.min(index, ARRIVAL_CAP) * ARRIVAL_STEP_MS}ms` }
68
+ };
69
+ }
70
+ function useArrival(id) {
71
+ const arrival = useContext(TreeArrivalContext);
72
+ const [props, setProps] = useState(() => arrival ? arrivalProps(arrival.index(id)) : {});
73
+ const onAnimationEnd = useCallback((event) => {
74
+ if (event.target === event.currentTarget && event.animationName === "sable-arrive") setProps({});
75
+ }, []);
76
+ return { ...props, onAnimationEnd };
77
+ }
46
78
  var ITEM_FOCUS = "focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring";
47
- function Tree({ className, children, onKeyDown, ...props }) {
79
+ function Tree({ className, children, onKeyDown, motion, ...props }) {
48
80
  const [focusedId, setFocusedId] = useState(null);
49
81
  const rootRef = useRef(null);
50
82
  const items = () => Array.from(rootRef.current?.querySelectorAll(ITEM) ?? []).filter(
@@ -120,17 +152,18 @@ function Tree({ className, children, onKeyDown, ...props }) {
120
152
  break;
121
153
  }
122
154
  };
123
- return /* @__PURE__ */ jsx(TreeContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
155
+ return /* @__PURE__ */ jsx(TreeContext.Provider, { value: context, children: /* @__PURE__ */ jsx(TreeMotionContext.Provider, { value: motion, children: /* @__PURE__ */ jsx(
124
156
  "div",
125
157
  {
126
158
  ref: rootRef,
127
159
  role: "tree",
160
+ "data-motion": motionAttribute(motion),
128
161
  onKeyDown: handleKeyDown,
129
162
  className: cn("flex flex-col py-1", className),
130
163
  ...props,
131
164
  children
132
165
  }
133
- ) });
166
+ ) }) });
134
167
  }
135
168
  Tree.displayName = "Tree";
136
169
  function TreeSection({ title, hint, action, className, children, ...props }) {
@@ -199,10 +232,26 @@ function TreeRow({
199
232
  };
200
233
  const item = useTreeItem(idProp);
201
234
  const nameId = useId();
235
+ const arrivalOwn = useArrival(item.id);
236
+ const inheritedArrival = useContext(TreeArrivalContext);
237
+ const motionLevel = useMotionLevel(useContext(TreeMotionContext));
238
+ const [seenExpanded, setSeenExpanded] = useState(expanded);
239
+ const [arrival, setArrival] = useState(null);
240
+ if (seenExpanded !== expanded) {
241
+ setSeenExpanded(expanded);
242
+ setArrival(expanded && subtree !== void 0 && motionLevel.expressive ? createArrival() : null);
243
+ }
244
+ useEffect(() => {
245
+ if (arrival) setArrival(null);
246
+ }, [arrival]);
202
247
  const row = /* @__PURE__ */ jsxs(
203
248
  "div",
204
249
  {
205
250
  ...props,
251
+ onAnimationEnd: (event) => {
252
+ arrivalOwn.onAnimationEnd(event);
253
+ props.onAnimationEnd?.(event);
254
+ },
206
255
  id: item.inTree ? item.id : idProp,
207
256
  "data-selected": selected || void 0,
208
257
  role: item.inTree ? "treeitem" : void 0,
@@ -217,9 +266,10 @@ function TreeRow({
217
266
  onFocus?.(event);
218
267
  },
219
268
  onClick: onClick ?? (expandable ? () => setExpanded(!expanded) : void 0),
220
- style: { paddingInlineStart: treeIndent(depth), ...style },
269
+ style: { paddingInlineStart: treeIndent(depth), ...arrivalOwn.style, ...style },
221
270
  className: cn(
222
271
  "group relative flex h-(--control-xs) items-center gap-1.5 rounded-xs pe-1 motion-interactive",
272
+ arrivalOwn.className,
223
273
  selected ? "bg-panel-raised" : "hover:bg-panel-raised/60",
224
274
  item.inTree && ITEM_FOCUS,
225
275
  dimmed && "opacity-50",
@@ -253,6 +303,8 @@ function TreeRow({
253
303
  // The drawn box stays on --tree-column because that column is also
254
304
  // the indent step; a bigger button moves every name in the tree.
255
305
  hitTargetMin,
306
+ // motion-interactive lists `rotate` (what -rotate-90 writes), so the
307
+ // chevron turns with the rows arriving under it instead of snapping.
256
308
  "rounded-xs text-muted-foreground motion-interactive hover:text-foreground",
257
309
  !expanded && "-rotate-90"
258
310
  ),
@@ -268,7 +320,7 @@ function TreeRow({
268
320
  if (subtree === void 0) return row;
269
321
  return /* @__PURE__ */ jsxs(Fragment, { children: [
270
322
  row,
271
- expanded ? /* @__PURE__ */ jsx(TreeDepthContext.Provider, { value: depth + 1, children: subtree }) : null
323
+ expanded ? /* @__PURE__ */ jsx(TreeDepthContext.Provider, { value: depth + 1, children: /* @__PURE__ */ jsx(TreeArrivalContext.Provider, { value: arrival ?? inheritedArrival, children: subtree }) }) : null
272
324
  ] });
273
325
  }
274
326
  TreeRow.displayName = "TreeRow";
@@ -283,6 +335,7 @@ function TreeEmpty({
283
335
  }) {
284
336
  const inheritedDepth = useContext(TreeDepthContext);
285
337
  const depth = depthProp ?? inheritedDepth;
338
+ const arrival = useArrival(useId());
286
339
  return /* @__PURE__ */ jsxs(
287
340
  "div",
288
341
  {
@@ -290,9 +343,15 @@ function TreeEmpty({
290
343
  className: cn(
291
344
  "flex flex-col",
292
345
  dropTarget && "mx-2 my-1 gap-1 rounded-sm border border-dashed border-hairline-strong p-2",
346
+ arrival.className,
293
347
  className
294
348
  ),
295
349
  ...props,
350
+ onAnimationEnd: (event) => {
351
+ arrival.onAnimationEnd(event);
352
+ props.onAnimationEnd?.(event);
353
+ },
354
+ style: arrival.style ? { ...arrival.style, ...props.style } : props.style,
296
355
  children: [
297
356
  /* @__PURE__ */ jsx(
298
357
  "p",
@@ -325,11 +384,16 @@ function TreeAddRow({
325
384
  const inheritedDepth = useContext(TreeDepthContext);
326
385
  const depth = depthProp ?? inheritedDepth;
327
386
  const item = useTreeItem(idProp);
387
+ const arrival = useArrival(item.id);
328
388
  return /* @__PURE__ */ jsxs(
329
389
  "button",
330
390
  {
331
391
  type: "button",
332
392
  ...props,
393
+ onAnimationEnd: (event) => {
394
+ arrival.onAnimationEnd(event);
395
+ props.onAnimationEnd?.(event);
396
+ },
333
397
  id: item.inTree ? item.id : idProp,
334
398
  role: item.inTree ? "treeitem" : void 0,
335
399
  "aria-level": item.inTree ? depth + 1 : void 0,
@@ -338,9 +402,10 @@ function TreeAddRow({
338
402
  item.claimFocus();
339
403
  onFocus?.(event);
340
404
  },
341
- style: { paddingInlineStart: treeIndent(depth), ...style },
405
+ style: { paddingInlineStart: treeIndent(depth), ...arrival.style, ...style },
342
406
  className: cn(
343
407
  "group flex h-(--control-xs) w-full items-center gap-1.5 rounded-xs pe-1 motion-interactive",
408
+ arrival.className,
344
409
  "text-ui-md text-muted-foreground hover:bg-panel-raised/60 hover:text-foreground",
345
410
  ITEM_FOCUS,
346
411
  className
@@ -167,6 +167,12 @@ var treeMeta = {
167
167
  name: "label",
168
168
  type: "ReactNode",
169
169
  description: "TreeAddRow's visible label. Name what gets added \u2014 'Add effect', not 'Add'."
170
+ },
171
+ {
172
+ name: "motion",
173
+ type: '"full" | "subtle" | "off"',
174
+ default: '"full"',
175
+ description: "On Tree. How much motion this component uses: `full` (default) inherits the app's policy, `subtle` keeps feedback and drops the flourish, `off` stills it. It can only turn motion down \u2014 it never overrides a reader's reduce-motion setting. Under `subtle` expanded rows appear at once instead of unfolding; the chevron still turns."
170
176
  }
171
177
  ],
172
178
  subcomponents: [
@@ -208,6 +214,32 @@ var treeMeta = {
208
214
  "Right-rail controls that appear on hover must also appear on focus-visible, or they are unreachable by keyboard."
209
215
  ],
210
216
  tokensUsed: ["panel-raised", "hairline", "foreground", "muted-foreground", "primary", "ring"],
217
+ motion: [
218
+ {
219
+ slot: "arrival",
220
+ recipe: "motion-arrive",
221
+ part: "TreeRow",
222
+ why: "Rows a user's expand reveals fade down into place in document order (a capped 18ms stagger), so the eye can follow where the children came from. An animation (motion-arrive) rather than a transition, because the rows already wear motion-interactive and a second transition list would fight it. Only on a user expand of a `subtree` \u2014 a tree that mounts open shows its rows at once, and rows added later to an open folder do not cascade. Expressive: `subtle` shows them at once."
223
+ },
224
+ {
225
+ slot: "response",
226
+ recipe: "motion-interactive",
227
+ part: "TreeRow",
228
+ why: "Hover and selection fills ease, so sweeping the pointer down a dense panel reads as a highlight following it rather than rows flickering."
229
+ },
230
+ {
231
+ slot: "transition",
232
+ recipe: "motion-interactive",
233
+ part: "Disclosure",
234
+ why: "The chevron turns with the rows arriving under it; motion-interactive lists `rotate`, which is what -rotate-90 writes, so it no longer flips in one frame."
235
+ },
236
+ {
237
+ slot: "activity",
238
+ recipe: "none",
239
+ part: "Tree",
240
+ why: "A tree has no indeterminate state of its own; a branch that loads its children should render a TreeEmpty or a loading row inside it."
241
+ }
242
+ ],
211
243
  examples: [
212
244
  {
213
245
  label: "File tree",
@@ -57,6 +57,38 @@ var videoMeta = {
57
57
  }
58
58
  ],
59
59
  tokensUsed: ["border", "overlay", "overlay-foreground", "ring"],
60
+ motion: [
61
+ {
62
+ slot: "arrival",
63
+ recipe: "none",
64
+ part: "Root",
65
+ why: "The frame arrives with its page. Once there is a source, the poster and controls are the browser's."
66
+ },
67
+ {
68
+ slot: "response",
69
+ recipe: "motion-interactive",
70
+ part: "Play button",
71
+ why: "With `onRequestPlay`, the play disc firms its scrim on hover, eased, so the mark reads as pressable over any image."
72
+ },
73
+ {
74
+ slot: "response",
75
+ recipe: "motion-press",
76
+ part: "Play button",
77
+ why: "Loading a source can take a moment; the settle on press confirms the tap before the player appears."
78
+ },
79
+ {
80
+ slot: "transition",
81
+ recipe: "none",
82
+ part: "Root",
83
+ why: "Placeholder to player is a swap of elements: the native video mounts where the poster was. Animating the swap would delay the playback the person just asked for."
84
+ },
85
+ {
86
+ slot: "activity",
87
+ recipe: "none",
88
+ part: "Root",
89
+ why: "Buffering belongs to the native controls, which draw their own indicator. A second loader over the frame would compete with the browser's."
90
+ }
91
+ ],
60
92
  a11y: [
61
93
  "Mounts a native <video> element, preserving built-in keyboard controls when controls is enabled.",
62
94
  'Without onRequestPlay the placeholder play mark is decorative (aria-hidden) \u2014 nothing on the frame pretends to be pressable. With it, the mark is a native button named "Play video".'