@ethlete/components 1.0.0-next.77 → 1.0.0-next.79

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 (318) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/design/accordion.ts +73 -0
  3. package/design/avatar.ts +90 -0
  4. package/design/badge.ts +48 -0
  5. package/design/banner.ts +77 -0
  6. package/design/bracket.ts +457 -0
  7. package/design/breadcrumb.ts +145 -0
  8. package/design/button.ts +49 -0
  9. package/design/calendar.ts +306 -0
  10. package/design/card.ts +92 -0
  11. package/design/carousel.ts +240 -0
  12. package/design/chart.ts +512 -0
  13. package/design/checkbox.ts +275 -0
  14. package/design/chip.ts +64 -0
  15. package/design/config.json +22 -0
  16. package/design/control.ts +19 -0
  17. package/design/copy-button.ts +59 -0
  18. package/design/description-list.ts +41 -0
  19. package/design/dialog.ts +214 -0
  20. package/design/divider.ts +27 -0
  21. package/design/empty-state.ts +45 -0
  22. package/design/floating-action.ts +55 -0
  23. package/design/form-field.ts +40 -1
  24. package/design/grid.ts +148 -0
  25. package/design/icon-set.ts +19 -0
  26. package/design/icon.ts +9 -0
  27. package/design/input.ts +86 -0
  28. package/design/kbd.ts +19 -0
  29. package/design/loader.ts +152 -0
  30. package/design/masonry.ts +115 -0
  31. package/design/match.ts +131 -0
  32. package/design/menu.ts +143 -0
  33. package/design/notification.ts +129 -0
  34. package/design/otp-input.ts +107 -0
  35. package/design/pagination.ts +120 -0
  36. package/design/picture.ts +80 -0
  37. package/design/progress-steps.ts +79 -0
  38. package/design/query-error.ts +60 -0
  39. package/design/radio-group.ts +132 -0
  40. package/design/scheduler.ts +369 -0
  41. package/design/scrollable.ts +218 -0
  42. package/design/scrollbar.ts +47 -0
  43. package/design/sdk/assets/fallback.svg +1 -0
  44. package/design/sdk/assets/tall.svg +1 -0
  45. package/design/sdk/assets/wide.svg +1 -0
  46. package/design/sdk/components/accent-on-light/accent-on-light.css +35 -0
  47. package/design/sdk/components/accent-on-light/accent-on-light.ts +10 -0
  48. package/design/sdk/components/accent-on-light/shared/controls.ts +46 -0
  49. package/design/sdk/components/accordion/accordion.css +17 -0
  50. package/design/sdk/components/accordion/accordion.ts +64 -0
  51. package/design/sdk/components/avatar/avatar.css +14 -0
  52. package/design/sdk/components/avatar/avatar.ts +78 -0
  53. package/design/sdk/components/badge/badge.css +13 -0
  54. package/design/sdk/components/badge/badge.ts +52 -0
  55. package/design/sdk/components/banner/banner.css +18 -0
  56. package/design/sdk/components/banner/banner.ts +87 -0
  57. package/design/sdk/components/bracket/bracket.css +59 -0
  58. package/design/sdk/components/bracket/bracket.ts +143 -0
  59. package/design/sdk/components/breadcrumb/breadcrumb.css +25 -0
  60. package/design/sdk/components/breadcrumb/breadcrumb.ts +81 -0
  61. package/design/sdk/components/button/button.css +33 -0
  62. package/design/sdk/components/button/button.ts +82 -0
  63. package/design/sdk/components/calendar/calendar.css +33 -0
  64. package/design/sdk/components/calendar/calendar.ts +96 -0
  65. package/design/sdk/components/card/card.css +19 -0
  66. package/design/sdk/components/card/card.ts +61 -0
  67. package/design/sdk/components/carousel/carousel.css +44 -0
  68. package/design/sdk/components/carousel/carousel.ts +74 -0
  69. package/design/sdk/components/chart/chart.css +56 -0
  70. package/design/sdk/components/chart/chart.ts +98 -0
  71. package/design/sdk/components/chip/chip.css +18 -0
  72. package/design/sdk/components/chip/chip.ts +76 -0
  73. package/design/sdk/components/copy-button/copy-button.css +14 -0
  74. package/design/sdk/components/copy-button/copy-button.ts +59 -0
  75. package/design/sdk/components/description-list/description-list.css +7 -0
  76. package/design/sdk/components/description-list/description-list.ts +53 -0
  77. package/design/sdk/components/dialog/dialog.css +29 -0
  78. package/design/sdk/components/dialog/dialog.ts +78 -0
  79. package/design/sdk/components/divider/divider.css +26 -0
  80. package/design/sdk/components/divider/divider.ts +43 -0
  81. package/design/sdk/components/empty-state/empty-state.css +15 -0
  82. package/design/sdk/components/empty-state/empty-state.ts +56 -0
  83. package/design/sdk/components/floating-action/floating-action.css +51 -0
  84. package/design/sdk/components/floating-action/floating-action.ts +63 -0
  85. package/design/sdk/components/form-field/form-field.ts +118 -0
  86. package/design/sdk/components/grid/grid.css +17 -0
  87. package/design/sdk/components/grid/grid.ts +80 -0
  88. package/design/sdk/components/input/input.css +75 -0
  89. package/design/sdk/components/input/input.ts +79 -0
  90. package/design/sdk/components/kbd/kbd.css +25 -0
  91. package/design/sdk/components/kbd/kbd.ts +57 -0
  92. package/design/sdk/components/loader/loader.css +37 -0
  93. package/design/sdk/components/loader/loader.ts +68 -0
  94. package/design/sdk/components/masonry/masonry.css +7 -0
  95. package/design/sdk/components/masonry/masonry.ts +42 -0
  96. package/design/sdk/components/match/match.css +25 -0
  97. package/design/sdk/components/match/match.ts +76 -0
  98. package/design/sdk/components/menu/menu.css +22 -0
  99. package/design/sdk/components/menu/menu.ts +91 -0
  100. package/design/sdk/components/notification/notification.css +32 -0
  101. package/design/sdk/components/notification/notification.ts +106 -0
  102. package/design/sdk/components/otp-input/otp-input.css +35 -0
  103. package/design/sdk/components/otp-input/otp-input.ts +64 -0
  104. package/design/sdk/components/pagination/pagination.css +14 -0
  105. package/design/sdk/components/pagination/pagination.ts +75 -0
  106. package/design/sdk/components/picture/picture.css +37 -0
  107. package/design/sdk/components/picture/picture.ts +96 -0
  108. package/design/sdk/components/progress-steps/progress-steps.css +37 -0
  109. package/design/sdk/components/progress-steps/progress-steps.ts +91 -0
  110. package/design/sdk/components/query-error/query-error.css +33 -0
  111. package/design/sdk/components/query-error/query-error.ts +120 -0
  112. package/design/sdk/components/scheduler/scheduler.css +55 -0
  113. package/design/sdk/components/scheduler/scheduler.ts +239 -0
  114. package/design/sdk/components/scrollable/scrollable.css +58 -0
  115. package/design/sdk/components/scrollable/scrollable.ts +133 -0
  116. package/design/sdk/components/scrollbar/scrollbar.css +78 -0
  117. package/design/sdk/components/scrollbar/scrollbar.ts +123 -0
  118. package/design/sdk/components/select/select.css +5 -0
  119. package/design/sdk/components/select/select.ts +16 -0
  120. package/design/sdk/components/select/shared/select-part.ts +75 -0
  121. package/design/sdk/components/select-panel/select-panel.css +3 -0
  122. package/design/sdk/components/select-panel/select-panel.ts +124 -0
  123. package/design/sdk/components/skeleton/skeleton.css +22 -0
  124. package/design/sdk/components/skeleton/skeleton.ts +50 -0
  125. package/design/sdk/components/slider/slider.css +52 -0
  126. package/design/sdk/components/slider/slider.ts +86 -0
  127. package/design/sdk/components/standings/standings.css +33 -0
  128. package/design/sdk/components/standings/standings.ts +130 -0
  129. package/design/sdk/components/stat-tile/stat-tile.css +15 -0
  130. package/design/sdk/components/stat-tile/stat-tile.ts +84 -0
  131. package/design/sdk/components/stream/stream.css +48 -0
  132. package/design/sdk/components/stream/stream.ts +38 -0
  133. package/design/sdk/components/switch/switch.css +35 -0
  134. package/design/sdk/components/switch/switch.ts +63 -0
  135. package/design/sdk/components/table/table.css +67 -0
  136. package/design/sdk/components/table/table.ts +160 -0
  137. package/design/sdk/components/tabs/tabs.css +13 -0
  138. package/design/sdk/components/tabs/tabs.ts +74 -0
  139. package/design/sdk/components/textarea/textarea.css +116 -0
  140. package/design/sdk/components/textarea/textarea.ts +64 -0
  141. package/design/sdk/components/timeline/timeline.css +30 -0
  142. package/design/sdk/components/timeline/timeline.ts +87 -0
  143. package/design/sdk/components/toolbar/toolbar.css +24 -0
  144. package/design/sdk/components/toolbar/toolbar.ts +87 -0
  145. package/design/sdk/components/tooltip/tooltip.css +15 -0
  146. package/design/sdk/components/tooltip/tooltip.ts +28 -0
  147. package/design/sdk/components/tree/selected-tint.css +15 -0
  148. package/design/sdk/components/tree/tree.ts +70 -0
  149. package/design/sdk/fixtures.ts +0 -0
  150. package/design/sdk/foundations/colors/colors.css +632 -0
  151. package/design/sdk/foundations/colors/colors.ts +188 -0
  152. package/design/sdk/foundations/colors/overrides.json +19 -0
  153. package/design/sdk/foundations/colors/shared/contrast.ts +120 -0
  154. package/design/sdk/foundations/elevation/elevation.css +6 -0
  155. package/design/sdk/foundations/elevation/elevation.ts +11 -0
  156. package/design/sdk/foundations/elevation/shared/elevation/scene.css +101 -0
  157. package/design/sdk/foundations/elevation/shared/elevation/scene.ts +74 -0
  158. package/design/sdk/foundations/icons/icons.ts +119 -0
  159. package/design/select.ts +113 -28
  160. package/design/skeleton.ts +67 -0
  161. package/design/slider.ts +155 -0
  162. package/design/standings.ts +161 -0
  163. package/design/stat-tile.ts +109 -0
  164. package/design/stream.ts +92 -0
  165. package/design/switch.ts +83 -0
  166. package/design/table.ts +302 -0
  167. package/design/tabs.ts +75 -0
  168. package/design/textarea.ts +92 -0
  169. package/design/timeline.ts +52 -0
  170. package/design/toolbar.ts +95 -0
  171. package/design/tooltip.ts +87 -0
  172. package/design/tree.ts +106 -0
  173. package/fesm2022/ethlete-components.mjs +240 -199
  174. package/fesm2022/ethlete-components.mjs.map +1 -1
  175. package/package.json +1 -1
  176. package/src/lib/accordion/accordion.component.css +2 -1
  177. package/src/lib/avatar/avatar.component.css +10 -0
  178. package/src/lib/badge/badge.component.css +2 -2
  179. package/src/lib/banner/banner.component.css +3 -1
  180. package/src/lib/breadcrumb/breadcrumb-outlet.component.css +5 -0
  181. package/src/lib/breadcrumb/breadcrumb.component.css +5 -1
  182. package/src/lib/button/button.component.css +19 -0
  183. package/src/lib/button/icon-button.component.css +19 -20
  184. package/src/lib/button/split-button.component.css +5 -1
  185. package/src/lib/calendar/calendar.component.css +13 -3
  186. package/src/lib/card/card.component.css +4 -0
  187. package/src/lib/carousel/carousel-autoplay-styles.component.css +1 -1
  188. package/src/lib/carousel/carousel.component.css +2 -2
  189. package/src/lib/chart/chart-axis.component.css +3 -3
  190. package/src/lib/chip/chip.component.css +8 -2
  191. package/src/lib/description-list/description-list.component.css +2 -1
  192. package/src/lib/empty-state/empty-state.component.css +4 -0
  193. package/src/lib/floating-action/floating-action-styles.component.css +27 -0
  194. package/src/lib/focus-ring/focus-ring-styles.component.css +4 -1
  195. package/src/lib/forms/checkbox/checkbox.component.css +31 -5
  196. package/src/lib/forms/color-input/color-input.component.css +3 -1
  197. package/src/lib/forms/color-input/color-picker-panel.component.css +6 -2
  198. package/src/lib/forms/date-time/date-input/date-input.component.css +1 -1
  199. package/src/lib/forms/date-time/date-time-input/date-time-input.component.css +1 -1
  200. package/src/lib/forms/date-time/duration-input/duration-input.component.css +1 -1
  201. package/src/lib/forms/date-time/range-input-shell-styles.component.css +1 -1
  202. package/src/lib/forms/date-time/time-input/time-input.component.css +1 -1
  203. package/src/lib/forms/description/description.component.css +7 -0
  204. package/src/lib/forms/dropzone/dropzone.component.css +26 -0
  205. package/src/lib/forms/form-field/form-field-control-suffix-styles.component.css +4 -2
  206. package/src/lib/forms/form-field/form-field-text-shell-styles.component.css +74 -17
  207. package/src/lib/forms/form-field/form-field-textarea-styles.component.css +62 -0
  208. package/src/lib/forms/form-field/form-field.component.css +6 -0
  209. package/src/lib/forms/form-field/headless/label.directive.css +1 -1
  210. package/src/lib/forms/input/input.component.css +6 -2
  211. package/src/lib/forms/input/number-input.component.css +2 -2
  212. package/src/lib/forms/input/password-input.component.css +4 -3
  213. package/src/lib/forms/otp-input/otp-input.component.css +23 -4
  214. package/src/lib/forms/phone-input/phone-input.component.css +4 -3
  215. package/src/lib/forms/rating/rating.component.css +2 -1
  216. package/src/lib/forms/rich-text-editor/rich-text-editor.component.css +1 -1
  217. package/src/lib/forms/select/select-option-styles.component.css +3 -2
  218. package/src/lib/forms/selection-card-styles.component.css +3 -2
  219. package/src/lib/forms/selection-list/checkbox-group/checkbox-group-select-all.component.css +4 -2
  220. package/src/lib/forms/selection-list/checkbox-group/checkbox-option.component.css +4 -2
  221. package/src/lib/forms/selection-list/radio-group/radio.component.css +5 -2
  222. package/src/lib/forms/selection-list/segmented-button-group/segmented-button.component.css +2 -1
  223. package/src/lib/forms/slider/range-slider.component.css +98 -6
  224. package/src/lib/forms/slider/slider.component.css +96 -4
  225. package/src/lib/forms/switch/switch.component.css +47 -4
  226. package/src/lib/forms/tag-input/tag-input.component.css +2 -2
  227. package/src/lib/forms/textarea/textarea-autosize-styles.component.css +2 -3
  228. package/src/lib/forms/textarea/textarea.component.css +7 -2
  229. package/src/lib/grid/grid-item-toolbar.component.css +10 -0
  230. package/src/lib/grid/grid-item.component.css +6 -1
  231. package/src/lib/icon/headless/align-icons.ts +30 -0
  232. package/src/lib/icon/headless/arrow-out-up-right-icon.ts +17 -0
  233. package/src/lib/icon/headless/arrow-right-icon.ts +23 -0
  234. package/src/lib/icon/headless/arrow-up-icon.ts +30 -0
  235. package/src/lib/icon/headless/arrows-left-right-icon.ts +31 -0
  236. package/src/lib/icon/headless/bold-icon.ts +11 -0
  237. package/src/lib/icon/headless/calendar-icon.ts +21 -0
  238. package/src/lib/icon/headless/check-icon.ts +14 -0
  239. package/src/lib/icon/headless/chevron-icon.ts +14 -0
  240. package/src/lib/icon/headless/circle-check-icon.ts +14 -0
  241. package/src/lib/icon/headless/circle-info-icon.ts +14 -0
  242. package/src/lib/icon/headless/clipboard-check-icon.ts +28 -0
  243. package/src/lib/icon/headless/clock-icon.ts +21 -0
  244. package/src/lib/icon/headless/code-block-icon.ts +15 -0
  245. package/src/lib/icon/headless/code-icon.ts +14 -0
  246. package/src/lib/icon/headless/ellipsis-icon.ts +13 -0
  247. package/src/lib/icon/headless/ellipsis-vertical-icon.ts +13 -0
  248. package/src/lib/icon/headless/eye-icons.ts +27 -0
  249. package/src/lib/icon/headless/eyedropper-icon.ts +22 -0
  250. package/src/lib/icon/headless/file-icon.ts +16 -0
  251. package/src/lib/icon/headless/filter-icon.ts +11 -0
  252. package/src/lib/icon/headless/floppy-disk-icon.ts +27 -0
  253. package/src/lib/icon/headless/focus-frame-icon.ts +16 -0
  254. package/src/lib/icon/headless/grid-2x2-icon.ts +17 -0
  255. package/src/lib/icon/headless/heading-1-icon.ts +11 -0
  256. package/src/lib/icon/headless/heading-2-icon.ts +11 -0
  257. package/src/lib/icon/headless/heading-3-icon.ts +11 -0
  258. package/src/lib/icon/headless/icon-definition.ts +14 -0
  259. package/src/lib/icon/headless/image-icon.ts +14 -0
  260. package/src/lib/icon/headless/italic-icon.ts +19 -0
  261. package/src/lib/icon/headless/link-icon.ts +17 -0
  262. package/src/lib/icon/headless/list-bulleted-icon.ts +14 -0
  263. package/src/lib/icon/headless/list-numbered-icon.ts +14 -0
  264. package/src/lib/icon/headless/location-icon.ts +21 -0
  265. package/src/lib/icon/headless/lock-icon.ts +14 -0
  266. package/src/lib/icon/headless/minus-icon.ts +14 -0
  267. package/src/lib/icon/headless/paragraph-icon.ts +11 -0
  268. package/src/lib/icon/headless/pause-icon.ts +11 -0
  269. package/src/lib/icon/headless/pencil-icon.ts +21 -0
  270. package/src/lib/icon/headless/play-icon.ts +10 -0
  271. package/src/lib/icon/headless/plus-icon.ts +21 -0
  272. package/src/lib/icon/headless/quote-icon.ts +15 -0
  273. package/src/lib/icon/headless/rotate-right-icon.ts +16 -0
  274. package/src/lib/icon/headless/star-icon.ts +14 -0
  275. package/src/lib/icon/headless/strikethrough-icon.ts +18 -0
  276. package/src/lib/icon/headless/table-icon.ts +15 -0
  277. package/src/lib/icon/headless/thumbtack-icon.ts +18 -0
  278. package/src/lib/icon/headless/times-icon.ts +14 -0
  279. package/src/lib/icon/headless/trash-icon.ts +24 -0
  280. package/src/lib/icon/headless/triangle-exclamation-icon.ts +14 -0
  281. package/src/lib/icon/headless/trophy-icon.ts +24 -0
  282. package/src/lib/icon/headless/underline-icon.ts +12 -0
  283. package/src/lib/icon/headless/undo-redo-icons.ts +24 -0
  284. package/src/lib/icon/headless/upload-icon.ts +16 -0
  285. package/src/lib/loader/brand-loader/brand-loader.component.css +4 -1
  286. package/src/lib/loader/progress-bar/progress-bar.component.css +1 -1
  287. package/src/lib/loader/spinner/spinner-styles.component.css +1 -1
  288. package/src/lib/match/match-card.component.css +9 -3
  289. package/src/lib/match/match-score.component.css +4 -1
  290. package/src/lib/menu/menu-selection-item.component.css +1 -1
  291. package/src/lib/menu/menu.component.css +5 -0
  292. package/src/lib/overlay/overlay-container.component.css +4 -0
  293. package/src/lib/pagination/pagination.component.css +4 -0
  294. package/src/lib/progress-steps/progress-step.component.css +4 -4
  295. package/src/lib/query-error/query-error.component.css +4 -0
  296. package/src/lib/scheduler/scheduler-appointment-styles.component.css +21 -5
  297. package/src/lib/scheduler/scheduler-month-view.component.css +4 -2
  298. package/src/lib/scheduler/scheduler-time-grid-view.component.css +8 -2
  299. package/src/lib/scrollable/headless/scrollable-navigation.component.css +1 -1
  300. package/src/lib/standings/standings-pick.component.css +1 -1
  301. package/src/lib/standings/standings.component.css +10 -10
  302. package/src/lib/stat-tile/stat-tile-sparkline.component.css +1 -1
  303. package/src/lib/stream/consent/stream-consent.component.css +99 -0
  304. package/src/lib/stream/error/stream-player-error.component.css +100 -0
  305. package/src/lib/stream/loading/stream-player-loading.component.css +16 -0
  306. package/src/lib/stream/pip/pip-slot-placeholder.component.css +68 -0
  307. package/src/lib/stream/stream-player-slot-styles.component.css +4 -0
  308. package/src/lib/table/table-resize-grip.component.css +2 -1
  309. package/src/lib/table/table-select-cell.component.css +45 -15
  310. package/src/lib/table/table.component.css +15 -5
  311. package/src/lib/tabs/tab-bar-styles.component.css +1 -1
  312. package/src/lib/tabs/tabs/tab-group.component.css +111 -0
  313. package/src/lib/time-picker/time-picker.component.css +2 -1
  314. package/src/lib/timeline/timeline-item.component.css +5 -1
  315. package/src/lib/toolbar/toolbar.component.css +4 -0
  316. package/src/lib/tooltip/tooltip.component.css +14 -0
  317. package/src/lib/tree/tree.component.css +2 -2
  318. package/types/ethlete-components.d.ts +62 -53
@@ -0,0 +1,78 @@
1
+ import { alertDialog, dialog, dialogStyles, overlayBackdrop } from '@ethlete/components/design/dialog';
2
+ import { definePart, drawing } from '@design-system';
3
+ import edge from './dialog.css?inline';
4
+
5
+ type Interaction = 'hover' | 'active' | 'focus-visible';
6
+
7
+ type Props = {
8
+ kind: 'dialog' | 'alert';
9
+ long?: boolean;
10
+ close?: Interaction;
11
+ confirm?: Interaction;
12
+ cancel?: Interaction;
13
+ };
14
+
15
+ const PANE = 'data-et-surface-fill';
16
+
17
+ const mark = (control: string, interaction?: Interaction) =>
18
+ [`data-et-control="${control}" data-can-animate`, interaction && `data-et-force="${interaction}"`]
19
+ .filter(Boolean)
20
+ .join(' ');
21
+
22
+ const SHORT = '<p>Kick-off moves to 18:30. Both teams and the referee get an email with the new time.</p>';
23
+
24
+ const LONG = Array.from(
25
+ { length: 8 },
26
+ (_, index) =>
27
+ `<p>Round ${index + 1}: every match of this round moves by one week. Teams that already confirmed get asked again, and open predictions stay open until the new kick-off.</p>`,
28
+ ).join('');
29
+
30
+ const render = ({ kind, long, close, confirm, cancel }: Props) =>
31
+ kind === 'alert'
32
+ ? alertDialog({
33
+ kind: 'confirm',
34
+ title: 'Delete this match?',
35
+ message: 'The match, its result and every prediction on it are removed. This cannot be undone.',
36
+ confirmLabel: 'Delete',
37
+ confirmAttributes: mark('confirm', confirm),
38
+ cancelAttributes: mark('cancel', cancel),
39
+ attributes: PANE,
40
+ })
41
+ : dialog({
42
+ title: long ? 'Move the season' : 'Move kick-off',
43
+ body: long ? LONG : SHORT,
44
+ close: mark('close', close),
45
+ dividers: long ? 'dynamic' : false,
46
+ actions: [
47
+ { label: 'Cancel', variant: 'outline', attributes: mark('cancel', cancel) },
48
+ { label: 'Save', attributes: mark('confirm', confirm) },
49
+ ],
50
+ attributes: PANE,
51
+ });
52
+
53
+ export default definePart({
54
+ note: 'Decided rules only',
55
+ madeBy: ['claude-opus-5-5'],
56
+ states: {
57
+ default: { kind: 'dialog' },
58
+ 'close-hover': { kind: 'dialog', close: 'hover' },
59
+ 'close-focus-visible': { kind: 'dialog', close: 'focus-visible' },
60
+ 'confirm-focus-visible': { kind: 'dialog', confirm: 'focus-visible' },
61
+ 'cancel-focus-visible': { kind: 'dialog', cancel: 'focus-visible' },
62
+ alert: { kind: 'alert' },
63
+ 'alert-cancel-focus-visible': { kind: 'alert', cancel: 'focus-visible' },
64
+ 'alert-confirm-focus-visible': { kind: 'alert', confirm: 'focus-visible' },
65
+ 'long-body': { kind: 'dialog', long: true },
66
+ },
67
+ widths: [480],
68
+ controls: {
69
+ close: { kind: 'button', input: ['pointer', 'keyboard'] },
70
+ cancel: { kind: 'button', input: ['pointer', 'keyboard'] },
71
+ confirm: { kind: 'button', input: ['pointer', 'keyboard'] },
72
+ },
73
+ render: (props: Props) =>
74
+ drawing({
75
+ body: `<div class="dialog-frame">${overlayBackdrop(render(props))}</div>`,
76
+ styles: [dialogStyles, edge].join('\n'),
77
+ }),
78
+ });
@@ -0,0 +1,26 @@
1
+ .divider-frame {
2
+ padding: 2.4rem 1.6rem;
3
+ background: var(--et-surface-background-solid);
4
+ color: var(--et-surface-color-solid);
5
+ font-size: 1.4rem;
6
+ }
7
+
8
+ .divider-frame p {
9
+ margin: 0;
10
+ }
11
+
12
+ .divider-frame-row {
13
+ display: flex;
14
+ align-items: center;
15
+ block-size: 2.4rem;
16
+ }
17
+
18
+ .divider-frame-list {
19
+ display: flex;
20
+ flex-direction: column;
21
+ --et-divider-inset: 16px;
22
+ }
23
+
24
+ .divider-frame-list > span {
25
+ padding: 0.4rem 1.6rem;
26
+ }
@@ -0,0 +1,43 @@
1
+ import { divider, dividerStyles } from '@ethlete/components/design/divider';
2
+ import { definePart, drawing } from '@design-system';
3
+ import frame from './divider.css?inline';
4
+
5
+ type Props = {
6
+ set?: 'horizontal' | 'vertical' | 'list';
7
+ };
8
+
9
+ const horizontal = () =>
10
+ `<p>Match starts at 18:00. Doors open an hour earlier.</p>${divider()}<p>Tickets are sent by email after payment.</p>`;
11
+
12
+ const vertical = () =>
13
+ `<div class="divider-frame-row"><span>Overview</span>${divider({ orientation: 'vertical' })}<span>Squad</span>${divider({ orientation: 'vertical', decorative: true })}<span>Fixtures</span></div>`;
14
+
15
+ const list = () =>
16
+ `<div class="divider-frame-list"><span>Account</span>${divider({ decorative: true })}<span>Notifications</span>${divider({ decorative: true })}<span>Privacy</span></div>`;
17
+
18
+ const body = (props: Props) => {
19
+ switch (props.set) {
20
+ case 'vertical':
21
+ return vertical();
22
+ case 'list':
23
+ return list();
24
+ default:
25
+ return horizontal();
26
+ }
27
+ };
28
+
29
+ export default definePart({
30
+ note: "Today's look",
31
+ madeBy: ['claude-opus-5-5'],
32
+ states: {
33
+ default: {},
34
+ vertical: { set: 'vertical' },
35
+ list: { set: 'list' },
36
+ },
37
+ widths: [480],
38
+ render: (props: Props) =>
39
+ drawing({
40
+ body: `<div class="divider-frame">${body(props)}</div>`,
41
+ styles: [dividerStyles, frame].join('\n'),
42
+ }),
43
+ });
@@ -0,0 +1,15 @@
1
+ .empty-state-frame {
2
+ padding: 2.4rem 1.6rem;
3
+ background: var(--et-surface-background-solid);
4
+ color: var(--et-surface-color-solid);
5
+ }
6
+
7
+ @layer components {
8
+ .et-empty-state .et-focus-ring {
9
+ --_et-focus-ring-color: var(--et-theme-color-ink-solid);
10
+ }
11
+
12
+ .et-empty-state .et-button[data-variant='filled'] {
13
+ --et-button-shadow: inset 0 0 0 1px var(--et-theme-color-ink-solid);
14
+ }
15
+ }
@@ -0,0 +1,56 @@
1
+ import { emptyState, emptyStateStyles } from '@ethlete/components/design/empty-state';
2
+ import { definePart, drawing } from '@design-system';
3
+ import frame from './empty-state.css?inline';
4
+
5
+ type Interaction = 'hover' | 'active' | 'focus-visible';
6
+
7
+ type Props = {
8
+ form: 'default' | 'without-action' | 'errored' | 'heading-only';
9
+ action?: Interaction;
10
+ };
11
+
12
+ const mark = (interaction?: Interaction) =>
13
+ [`data-et-control="action" data-can-animate`, interaction && `data-et-force="${interaction}"`]
14
+ .filter(Boolean)
15
+ .join(' ');
16
+
17
+ const COPY = {
18
+ default: {
19
+ heading: 'No results',
20
+ description: 'Try a different search term or clear your filters.',
21
+ action: 'Clear filters',
22
+ },
23
+ 'without-action': { heading: 'No results', description: 'Try a different search term or clear your filters.' },
24
+ errored: {
25
+ icon: 'triangle',
26
+ heading: 'Something went wrong',
27
+ description: 'We could not load this data. Please try again.',
28
+ action: 'Try again',
29
+ },
30
+ 'heading-only': { icon: false, heading: 'Nothing here yet' },
31
+ } as const;
32
+
33
+ const render = ({ form, action }: Props) => emptyState({ ...COPY[form], actionAttributes: mark(action) });
34
+
35
+ export default definePart({
36
+ note: 'Decided rules only',
37
+ madeBy: ['claude-opus-5-5'],
38
+ states: {
39
+ default: { form: 'default' },
40
+ 'without-action': { form: 'without-action' },
41
+ errored: { form: 'errored' },
42
+ 'heading-only': { form: 'heading-only' },
43
+ 'action-hover': { form: 'default', action: 'hover' },
44
+ 'action-active': { form: 'default', action: 'active' },
45
+ 'action-focus-visible': { form: 'default', action: 'focus-visible' },
46
+ },
47
+ widths: [480],
48
+ controls: {
49
+ action: { kind: 'button', input: ['pointer', 'keyboard'] },
50
+ },
51
+ render: (props: Props) =>
52
+ drawing({
53
+ body: `<div class="empty-state-frame">${render(props)}</div>`,
54
+ styles: [emptyStateStyles, frame].join('\n'),
55
+ }),
56
+ });
@@ -0,0 +1,51 @@
1
+ .fa-frame {
2
+ position: relative;
3
+ overflow: hidden;
4
+ box-sizing: border-box;
5
+ block-size: 400px;
6
+ transform: translate(0);
7
+ background: var(--et-surface-background-solid);
8
+ color: var(--et-surface-color-solid);
9
+ font-size: 1.4rem;
10
+
11
+ .fa-page {
12
+ padding: 2.4rem;
13
+ }
14
+
15
+ .et-floating-action {
16
+ display: flex;
17
+ flex-direction: column;
18
+ gap: 1.6rem;
19
+ }
20
+
21
+ p {
22
+ margin: 0;
23
+ }
24
+
25
+ .fa-heading {
26
+ margin: 0;
27
+ font-size: 2rem;
28
+ font-weight: 600;
29
+ }
30
+
31
+ .fa-rows {
32
+ display: flex;
33
+ flex-direction: column;
34
+ gap: 0.8rem;
35
+ margin: 0;
36
+ padding: 0;
37
+ }
38
+
39
+ .fa-row {
40
+ padding: 1.2rem;
41
+ border-radius: 8px;
42
+ background: color-mix(in srgb, var(--et-surface-color-solid) 8%, transparent);
43
+ list-style: none;
44
+ }
45
+ }
46
+
47
+ @layer components {
48
+ .et-floating-action .et-floating-action-trigger:where([data-floating-action-state='floating']) {
49
+ --et-button-shadow: inset 0 0 0 1px light-dark(var(--et-theme-color-ink-solid), transparent);
50
+ }
51
+ }
@@ -0,0 +1,63 @@
1
+ import { floatingAction, floatingActionStyles } from '@ethlete/components/design/floating-action';
2
+ import { definePart, drawing } from '@design-system';
3
+ import frame from './floating-action.css?inline';
4
+
5
+ type Interaction = 'hover' | 'active' | 'focus-visible';
6
+
7
+ type Props = {
8
+ state?: 'inline' | 'floating' | 'hidden';
9
+ interaction?: Interaction;
10
+ filterIcon?: boolean;
11
+ color?: string;
12
+ inset?: number;
13
+ overRow?: boolean;
14
+ };
15
+
16
+ const SCROLL = { inline: 0, floating: 236, hidden: 980 };
17
+ const OVER_ROW_SCROLL = 252;
18
+ const PARAGRAPH =
19
+ 'Pick a competition and a season, then narrow the list down by team, venue or kick-off time to find the match you are after.';
20
+
21
+ const rows = Array.from({ length: 12 }, (_, index) => `<li class="fa-row">Result ${index + 1}</li>`).join('');
22
+ const paragraphs = (count: number) => Array.from({ length: count }, () => `<p>${PARAGRAPH}</p>`).join('');
23
+
24
+ const render = ({ state = 'inline', interaction, filterIcon, color, inset }: Props) =>
25
+ floatingAction({
26
+ state,
27
+ filterIcon,
28
+ trigger: { label: 'Filter (2)', color },
29
+ triggerAttributes: interaction ? `data-et-force="${interaction}"` : undefined,
30
+ heldSize: { inlineSize: filterIcon ? 132 : 104, blockSize: 40 },
31
+ before: `${paragraphs(2)}<h2 class="fa-heading">Results</h2>`,
32
+ scope: `<ul class="fa-rows">${rows}</ul>`,
33
+ after: paragraphs(8),
34
+ attributes:
35
+ inset === undefined
36
+ ? undefined
37
+ : `style="--et-floating-action-inset-inline-end: ${inset}px; --et-floating-action-inset-block-end: ${inset}px"`,
38
+ });
39
+
40
+ export default definePart({
41
+ note: 'Q138: the floating trigger gets the Q99a 1px inset ink edge in light only, so it reaches 3:1 on a light grey row (4.68) and the page (5.48); dark unchanged.',
42
+ madeBy: ['claude-opus-5-5'],
43
+ states: {
44
+ inline: {},
45
+ floating: { state: 'floating' },
46
+ 'floating-hover': { state: 'floating', interaction: 'hover' },
47
+ 'floating-active': { state: 'floating', interaction: 'active' },
48
+ 'floating-focus-visible': { state: 'floating', interaction: 'focus-visible' },
49
+ 'inline-focus-visible': { interaction: 'focus-visible' },
50
+ 'floating-icon': { state: 'floating', filterIcon: true },
51
+ 'floating-inset': { state: 'floating', inset: 12 },
52
+ 'floating-danger': { state: 'floating', color: 'danger' },
53
+ 'floating-danger-hover': { state: 'floating', color: 'danger', interaction: 'hover' },
54
+ 'floating-over-row': { state: 'floating', overRow: true },
55
+ hidden: { state: 'hidden' },
56
+ },
57
+ widths: [480],
58
+ render: (props: Props) =>
59
+ drawing({
60
+ body: `<div class="fa-frame" data-et-skip="CLIPPED"><div class="fa-page" style="margin-block-start: -${props.overRow ? OVER_ROW_SCROLL : SCROLL[props.state ?? 'inline']}px">${render(props)}</div></div>`,
61
+ styles: [floatingActionStyles, frame].join('\n'),
62
+ }),
63
+ });
@@ -0,0 +1,118 @@
1
+ import {
2
+ formField,
3
+ formFieldStyles,
4
+ input,
5
+ textarea,
6
+ type FormFieldMockOptions,
7
+ } from '@ethlete/components/design/form-field';
8
+ import { definePart, drawing, interactionRows } from '@design-system';
9
+
10
+ type FieldInteraction = 'hover' | 'focus-visible';
11
+
12
+ type FieldControl = 'input' | 'textarea';
13
+
14
+ type Axes = Pick<FormFieldMockOptions, 'appearance' | 'fill' | 'labelMode' | 'size'>;
15
+
16
+ type Props = Axes & {
17
+ control?: FieldControl;
18
+ value?: string;
19
+ textAlign?: 'center' | 'end';
20
+ hint?: string;
21
+ error?: string;
22
+ focused?: boolean;
23
+ disabled?: boolean;
24
+ interaction?: FieldInteraction;
25
+ };
26
+
27
+ const multiLine = 'Ada Lovelace\nAnalytical Engine notes';
28
+
29
+ const axisRow: Props = { value: 'Ada Lovelace' };
30
+
31
+ const AXES = {
32
+ appearance: ['box', 'underline'],
33
+ fill: ['transparent', 'filled'],
34
+ labelMode: ['static', 'inline', 'floating-inside', 'floating-outside'],
35
+ size: ['sm', 'md', 'lg'],
36
+ } as const satisfies { [K in keyof Axes]-?: readonly NonNullable<Axes[K]>[] };
37
+
38
+ const axisRows = Object.fromEntries(
39
+ Object.entries(AXES).flatMap(([axis, values]) =>
40
+ values.map((value) => [`${axis}-${value}`, { ...axisRow, [axis]: value }]),
41
+ ),
42
+ ) as Record<string, Props>;
43
+
44
+ const interactive = interactionRows(
45
+ {
46
+ empty: { hint: 'Shown on your profile' },
47
+ filled: { value: 'Ada Lovelace' },
48
+ error: { error: 'This field is required' },
49
+ 'textarea-empty': { control: 'textarea', hint: 'Shown on your profile' },
50
+ 'textarea-filled': { control: 'textarea', value: multiLine },
51
+ 'textarea-error': { control: 'textarea', error: 'This field is required' },
52
+ ...axisRows,
53
+ } satisfies Record<string, Props>,
54
+ {
55
+ interactions: ['hover', 'focus-visible'],
56
+ force: (props: Props, interaction: FieldInteraction): Props => ({ ...props, interaction }),
57
+ },
58
+ );
59
+
60
+ const ALIGNMENTS = ['center', 'end'] as const;
61
+
62
+ const alignStates = Object.fromEntries(
63
+ ALIGNMENTS.map((textAlign) => [`text-align-${textAlign}`, { ...axisRow, textAlign }]),
64
+ ) as Record<`text-align-${(typeof ALIGNMENTS)[number]}`, Props>;
65
+
66
+ const states = { ...interactive.states, ...alignStates };
67
+ const grid = {
68
+ columns: interactive.grid.columns,
69
+ rows: {
70
+ ...interactive.grid.rows,
71
+ ...Object.fromEntries(
72
+ ALIGNMENTS.map((textAlign) => [`textAlign ${textAlign}`, { rest: `text-align-${textAlign}` as const }]),
73
+ ),
74
+ },
75
+ };
76
+
77
+ const markControl = (markup: string, control: FieldControl, interaction: FieldInteraction | undefined) => {
78
+ const frame = ['data-et-control-part', interaction && `data-et-force="${interaction}"`].filter(Boolean);
79
+ const native = control === 'input' ? '<input class="et-input-native"' : '<textarea class="et-textarea-native"';
80
+
81
+ return markup
82
+ .replace('<et-form-field ', `<et-form-field data-et-control="${control}" `)
83
+ .replace('<div class="et-form-field-control-frame"', `<div class="et-form-field-control-frame" ${frame.join(' ')}`)
84
+ .replace(native, native.replace(' class=', ' data-et-control-part class='));
85
+ };
86
+
87
+ export default definePart<Props>({
88
+ note: 'scale of the decided shape, Q182, lead merge',
89
+ madeBy: ['claude-opus-5-5'],
90
+ states: {
91
+ ...states,
92
+ focused: { value: 'Ada', focused: true },
93
+ disabled: { value: 'Ada Lovelace', disabled: true },
94
+ 'textarea-focused': { control: 'textarea', value: 'Ada', focused: true },
95
+ 'textarea-disabled': { control: 'textarea', value: multiLine, disabled: true },
96
+ },
97
+ grid,
98
+ widths: [320],
99
+ controls: {
100
+ input: { kind: 'field', input: ['pointer', 'keyboard'], disabled: true },
101
+ textarea: { kind: 'field', input: ['pointer', 'keyboard'], disabled: true },
102
+ },
103
+ render: ({ control = 'input', value, textAlign, interaction, ...field }) =>
104
+ drawing({
105
+ body: markControl(
106
+ formField({
107
+ id: 'name',
108
+ label: 'Name',
109
+ errorColor: 'danger',
110
+ control: control === 'input' ? input({ value, textAlign }) : textarea({ value }),
111
+ ...field,
112
+ }),
113
+ control,
114
+ interaction,
115
+ ),
116
+ styles: formFieldStyles,
117
+ }),
118
+ });
@@ -0,0 +1,17 @@
1
+ .t-frame {
2
+ box-sizing: border-box;
3
+ padding: 1.6rem;
4
+ background: var(--et-surface-background-solid);
5
+ color: var(--et-surface-color-solid);
6
+ font-size: 1.4rem;
7
+ }
8
+
9
+ @layer components {
10
+ .et-grid-item:focus-visible {
11
+ outline-color: var(--et-theme-color-ink-solid);
12
+ }
13
+
14
+ .et-grid-item-toolbar .et-focus-ring {
15
+ --_et-focus-ring-color: var(--et-theme-color-ink-solid);
16
+ }
17
+ }
@@ -0,0 +1,80 @@
1
+ import { grid, GridMockItem, gridStyles } from '@ethlete/components/design/grid';
2
+ import { definePart, drawing } from '@design-system';
3
+ import frame from './grid.css?inline';
4
+
5
+ type Props = {
6
+ layout: 'rest' | 'spans';
7
+ actions?: boolean;
8
+ item?: Partial<GridMockItem> & { id: string };
9
+ drag?: boolean;
10
+ resize?: boolean;
11
+ longTitle?: boolean;
12
+ };
13
+
14
+ const REST: (GridMockItem & { id: string })[] = [
15
+ { id: 'revenue', col: 0, row: 0, colSpan: 2, rowSpan: 1, title: 'Revenue', subtitle: 'Last 30 days' },
16
+ { id: 'visitors', col: 2, row: 0, colSpan: 2, rowSpan: 1, title: 'Visitors', subtitle: 'This week' },
17
+ { id: 'orders', col: 0, row: 1, colSpan: 2, rowSpan: 1, title: 'Orders', subtitle: 'Today' },
18
+ { id: 'refunds', col: 2, row: 1, colSpan: 2, rowSpan: 1, title: 'Refunds', subtitle: 'Today' },
19
+ ];
20
+
21
+ const SPANS: (GridMockItem & { id: string })[] = [
22
+ { id: 'revenue', col: 0, row: 0, colSpan: 2, rowSpan: 1, title: 'Revenue', subtitle: 'Last 30 days' },
23
+ { id: 'visitors', col: 2, row: 0, colSpan: 2, rowSpan: 2, title: 'Visitors', subtitle: 'This week' },
24
+ { id: 'orders', col: 0, row: 1, colSpan: 1, rowSpan: 1, title: 'Orders', subtitle: 'Today' },
25
+ { id: 'refunds', col: 1, row: 1, colSpan: 1, rowSpan: 1, title: 'Refunds', subtitle: 'Today' },
26
+ { id: 'activity', col: 0, row: 2, colSpan: 4, rowSpan: 1, title: 'Activity', subtitle: 'Latest events' },
27
+ ];
28
+
29
+ const LONG_TITLE = 'Revenue by region and sales channel';
30
+
31
+ const itemsOf = (props: Props) => {
32
+ const items = (props.layout === 'rest' ? REST : SPANS).map((item) =>
33
+ props.item?.id === item.id ? { ...item, ...props.item } : item,
34
+ );
35
+
36
+ if (props.drag) {
37
+ return items.map((item) => {
38
+ if (item.id === 'orders') return { ...item, state: 'dragging' as const, offset: { x: 70, y: 18 } };
39
+ if (item.id === 'refunds') return { ...item, col: 0 };
40
+ return item;
41
+ });
42
+ }
43
+
44
+ if (props.resize) {
45
+ return items.map((item) =>
46
+ item.id === 'activity' ? { ...item, rowSpan: 2, state: 'resizing' as const, activeEdge: 's' as const } : item,
47
+ );
48
+ }
49
+
50
+ if (props.longTitle) return items.map((item) => (item.id === 'revenue' ? { ...item, title: LONG_TITLE } : item));
51
+
52
+ return items;
53
+ };
54
+
55
+ export default definePart({
56
+ note: 'Decided rules only',
57
+ madeBy: ['claude-opus-5-5'],
58
+ states: {
59
+ rest: { layout: 'rest' },
60
+ spans: { layout: 'spans' },
61
+ 'item-hover': { layout: 'spans', item: { id: 'visitors', force: 'hover' } },
62
+ 'item-focus-visible': { layout: 'spans', item: { id: 'visitors', force: 'focus-visible' } },
63
+ actions: { layout: 'spans', actions: true },
64
+ 'action-hover': { layout: 'spans', actions: true, item: { id: 'revenue', removeForce: 'hover' } },
65
+ 'action-focus-visible': { layout: 'spans', actions: true, item: { id: 'revenue', removeForce: 'focus-visible' } },
66
+ dragging: { layout: 'spans', drag: true },
67
+ resizing: { layout: 'spans', resize: true },
68
+ 'long-title': { layout: 'spans', actions: true, longTitle: true },
69
+ },
70
+ widths: [480],
71
+ render: (props: Props) =>
72
+ drawing({
73
+ body: `<div class="t-frame">${grid({
74
+ items: itemsOf(props),
75
+ actions: props.actions,
76
+ ghost: props.drag ? { col: 1, row: 1, colSpan: 1, rowSpan: 1 } : undefined,
77
+ })}</div>`,
78
+ styles: [gridStyles, frame].join('\n'),
79
+ }),
80
+ });
@@ -0,0 +1,75 @@
1
+ .t-frame {
2
+ box-sizing: border-box;
3
+ display: grid;
4
+ gap: 1.6rem;
5
+ padding: 1.6rem;
6
+ background: var(--et-surface-background-solid);
7
+ color: var(--et-surface-color-solid);
8
+ font-size: 1.4rem;
9
+ }
10
+
11
+ @layer components {
12
+ et-form-field[data-text-shell] {
13
+ --_et-form-field-frame-border: var(--et-surface-interaction-solid);
14
+ --_et-form-field-frame-border-hover: color-mix(
15
+ in srgb,
16
+ var(--et-surface-interaction-solid) 75%,
17
+ var(--et-surface-color-solid)
18
+ );
19
+ --_et-form-field-frame-focus: var(--et-surface-color-solid);
20
+ }
21
+
22
+ et-form-field[data-text-shell][data-error] {
23
+ --_et-form-field-frame-border: var(--et-theme-color-primary-solid);
24
+ --_et-form-field-frame-border-hover: light-dark(
25
+ rgb(var(--et-color-primary-hover, var(--et-color-primary))),
26
+ rgb(
27
+ var(
28
+ --et-color-primary-ink-active,
29
+ var(
30
+ --et-color-primary-ink-focus,
31
+ var(
32
+ --et-color-primary-ink-hover,
33
+ var(
34
+ --et-color-primary-ink,
35
+ var(
36
+ --et-color-primary-active,
37
+ var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)))
38
+ )
39
+ )
40
+ )
41
+ )
42
+ )
43
+ )
44
+ );
45
+ --_et-form-field-frame-focus: var(--et-theme-color-ink-solid);
46
+ }
47
+
48
+ et-form-field[data-text-shell]:is([data-focused], :has(:focus-visible)):not([data-readonly])
49
+ .et-form-field-control-frame {
50
+ border-color: var(--_et-form-field-frame-focus);
51
+ box-shadow: inset 0 0 0 1px var(--_et-form-field-frame-focus);
52
+ }
53
+
54
+ et-form-field[data-text-shell][data-readonly] .et-form-field-control-frame {
55
+ border-style: dashed;
56
+ }
57
+
58
+ et-form-field[data-text-shell][data-readonly]:is([data-focused], :has(:focus-visible)) .et-form-field-control-frame {
59
+ border-color: transparent;
60
+ outline: 2px dashed var(--_et-form-field-frame-focus);
61
+ outline-offset: -2px;
62
+ }
63
+
64
+ et-form-field[data-text-shell] .et-form-field-prefix:not(:has(svg)) {
65
+ margin-inline-end: calc(4px - var(--et-form-field-control-affix-gap));
66
+ }
67
+
68
+ et-form-field et-label .et-label-required-marker {
69
+ color: var(--et-theme-color-ink-solid);
70
+ }
71
+
72
+ et-input .et-input-native::placeholder {
73
+ color: color-mix(in srgb, currentColor 60%, transparent);
74
+ }
75
+ }