fluentui-svelte 0.5.0 → 0.7.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 (259) hide show
  1. package/dist/components/app-surface/app-surface.svelte +96 -0
  2. package/dist/components/app-surface/app-surface.svelte.d.ts +22 -0
  3. package/dist/components/app-surface/docs/llms.md +73 -0
  4. package/dist/components/app-surface/types.d.ts +19 -0
  5. package/dist/components/app-surface/types.js +1 -0
  6. package/dist/components/app-window/app-window.d.ts +3 -0
  7. package/dist/components/app-window/app-window.js +3 -0
  8. package/dist/components/app-window/app-window.svelte +193 -0
  9. package/dist/components/app-window/app-window.svelte.d.ts +25 -0
  10. package/dist/components/app-window/docs/llms.md +119 -0
  11. package/dist/components/app-window/types.d.ts +66 -0
  12. package/dist/components/app-window/types.js +1 -0
  13. package/dist/components/auto-suggest-box/auto-suggest-box.svelte +47 -31
  14. package/dist/components/auto-suggest-box/auto-suggest-box.svelte.d.ts +2 -2
  15. package/dist/components/auto-suggest-box/docs/llms.md +34 -33
  16. package/dist/components/auto-suggest-box/option.svelte +6 -4
  17. package/dist/components/auto-suggest-box/types.d.ts +13 -16
  18. package/dist/components/avatar/avatar.svelte +4 -3
  19. package/dist/components/avatar/docs/llms.md +1 -1
  20. package/dist/components/avatar/type.d.ts +1 -1
  21. package/dist/components/badge/badge-icon.svelte +2 -2
  22. package/dist/components/badge/badge.svelte +2 -2
  23. package/dist/components/badge/docs/llms.md +2 -2
  24. package/dist/components/badge/types.d.ts +2 -2
  25. package/dist/components/breadcrumb/breadcrumb-button.svelte +2 -2
  26. package/dist/components/breadcrumb/breadcrumb-divider.svelte +2 -2
  27. package/dist/components/breadcrumb/breadcrumb-item.svelte +2 -2
  28. package/dist/components/breadcrumb/breadcrumb.svelte +10 -5
  29. package/dist/components/breadcrumb/docs/llms.md +11 -11
  30. package/dist/components/breadcrumb/types.d.ts +7 -7
  31. package/dist/components/button/button.svelte +2 -2
  32. package/dist/components/button/docs/llms.md +17 -17
  33. package/dist/components/button/split-button.svelte +7 -7
  34. package/dist/components/button/types.d.ts +5 -5
  35. package/dist/components/calendar-date-picker/calendar-date-picker.svelte +98 -10
  36. package/dist/components/calendar-date-picker/calendar-date-picker.svelte.d.ts +1 -1
  37. package/dist/components/calendar-date-picker/docs/llms.md +19 -14
  38. package/dist/components/calendar-date-picker/types.d.ts +22 -8
  39. package/dist/components/calendar-view/calendar-view-days.svelte +3 -2
  40. package/dist/components/calendar-view/calendar-view-grid.js +8 -3
  41. package/dist/components/calendar-view/calendar-view-item.svelte +10 -4
  42. package/dist/components/calendar-view/calendar-view-months.svelte +3 -2
  43. package/dist/components/calendar-view/calendar-view-years.svelte +3 -2
  44. package/dist/components/calendar-view/calendar-view.svelte +11 -4
  45. package/dist/components/calendar-view/calendar-view.svelte.js +5 -0
  46. package/dist/components/calendar-view/docs/llms.md +20 -19
  47. package/dist/components/calendar-view/types.d.ts +6 -1
  48. package/dist/components/card/card-footer.svelte +2 -2
  49. package/dist/components/card/card-header.svelte +5 -4
  50. package/dist/components/card/card-preview.svelte +13 -2
  51. package/dist/components/card/card.svelte +5 -5
  52. package/dist/components/card/docs/llms.md +22 -21
  53. package/dist/components/card/types.d.ts +8 -4
  54. package/dist/components/checkbox/checkbox.svelte +47 -26
  55. package/dist/components/checkbox/checkbox.svelte.d.ts +3 -24
  56. package/dist/components/checkbox/docs/llms.md +24 -23
  57. package/dist/components/checkbox/types.d.ts +10 -23
  58. package/dist/components/date-picker/date-picker.svelte +98 -27
  59. package/dist/components/date-picker/date-picker.svelte.d.ts +1 -1
  60. package/dist/components/date-picker/docs/llms.md +23 -20
  61. package/dist/components/date-picker/types.d.ts +24 -15
  62. package/dist/components/dialog/dialog-actions.svelte +17 -2
  63. package/dist/components/dialog/dialog-content.svelte +2 -2
  64. package/dist/components/dialog/dialog-content.svelte.d.ts +1 -1
  65. package/dist/components/dialog/dialog-surface.svelte +130 -8
  66. package/dist/components/dialog/dialog-title.svelte +23 -6
  67. package/dist/components/dialog/dialog-trigger.svelte +8 -2
  68. package/dist/components/dialog/dialog-trigger.svelte.d.ts +1 -1
  69. package/dist/components/dialog/dialog.svelte +22 -11
  70. package/dist/components/dialog/docs/llms.md +56 -19
  71. package/dist/components/dialog/types.d.ts +31 -9
  72. package/dist/components/dialog/utils.d.ts +2 -0
  73. package/dist/components/dialog/utils.js +1 -0
  74. package/dist/components/divider/divider.svelte +6 -4
  75. package/dist/components/divider/types.d.ts +1 -1
  76. package/dist/components/dropdown/docs/llms.md +30 -28
  77. package/dist/components/dropdown/dropdown-option.svelte +17 -5
  78. package/dist/components/dropdown/dropdown.svelte +182 -84
  79. package/dist/components/dropdown/dropdown.svelte.d.ts +1 -1
  80. package/dist/components/dropdown/types.d.ts +26 -20
  81. package/dist/components/dropdown-select/docs/llms.md +24 -22
  82. package/dist/components/dropdown-select/dropdown-select-option.svelte +2 -2
  83. package/dist/components/dropdown-select/dropdown-select.svelte +42 -7
  84. package/dist/components/dropdown-select/types.d.ts +4 -4
  85. package/dist/components/expander/docs/llms.md +3 -3
  86. package/dist/components/expander/expander.svelte +13 -8
  87. package/dist/components/expander/types.d.ts +5 -5
  88. package/dist/components/flyout/docs/llms.md +1 -1
  89. package/dist/components/flyout/flyout.svelte +17 -6
  90. package/dist/components/flyout/types.d.ts +1 -1
  91. package/dist/components/hyperlink/docs/llms.md +6 -6
  92. package/dist/components/hyperlink/hyperlink.svelte +13 -4
  93. package/dist/components/hyperlink/types.d.ts +1 -1
  94. package/dist/components/info-bar/docs/llms.md +11 -10
  95. package/dist/components/info-bar/info-bar.svelte +3 -2
  96. package/dist/components/info-bar/types.d.ts +4 -0
  97. package/dist/components/label/docs/llms.md +75 -22
  98. package/dist/components/label/label-context.d.ts +14 -0
  99. package/dist/components/label/label-context.js +10 -0
  100. package/dist/components/label/label.svelte +153 -30
  101. package/dist/components/label/label.svelte.d.ts +1 -1
  102. package/dist/components/label/types.d.ts +48 -4
  103. package/dist/components/list-view/docs/llms.md +103 -33
  104. package/dist/components/list-view/list-view-item-branch.svelte +257 -0
  105. package/dist/components/list-view/list-view-item-branch.svelte.d.ts +4 -0
  106. package/dist/components/list-view/list-view-item.svelte +164 -46
  107. package/dist/components/list-view/list-view-item.svelte.d.ts +5 -5
  108. package/dist/components/list-view/list-view.svelte +73 -25
  109. package/dist/components/list-view/types.d.ts +71 -8
  110. package/dist/components/list-view/utils.d.ts +10 -0
  111. package/dist/components/list-view/utils.js +17 -1
  112. package/dist/components/menu/docs/llms.md +98 -15
  113. package/dist/components/menu/menu-command-bar-item.svelte +61 -0
  114. package/dist/components/menu/menu-command-bar-item.svelte.d.ts +14 -0
  115. package/dist/components/menu/menu-command-bar.svelte +218 -0
  116. package/dist/components/menu/menu-command-bar.svelte.d.ts +21 -0
  117. package/dist/components/menu/menu-group.svelte +6 -3
  118. package/dist/components/menu/menu-item-checkbox.svelte +5 -4
  119. package/dist/components/menu/menu-item-radio.svelte +5 -4
  120. package/dist/components/menu/menu-item-switch.svelte +5 -4
  121. package/dist/components/menu/menu-item.svelte +5 -5
  122. package/dist/components/menu/menu-item.svelte.d.ts +2 -3
  123. package/dist/components/menu/menu-list.svelte +10 -1
  124. package/dist/components/menu/menu-popover.svelte +9 -5
  125. package/dist/components/menu/menu-trigger.svelte +2 -1
  126. package/dist/components/menu/menu.svelte.js +1 -0
  127. package/dist/components/menu/types.d.ts +62 -7
  128. package/dist/components/number-box/docs/llms.md +6 -4
  129. package/dist/components/number-box/number-box.svelte +35 -29
  130. package/dist/components/number-box/number-box.svelte.d.ts +1 -1
  131. package/dist/components/number-box/types.d.ts +1 -1
  132. package/dist/components/persona/docs/llms.md +29 -25
  133. package/dist/components/persona/persona.svelte +8 -6
  134. package/dist/components/persona/types.d.ts +4 -3
  135. package/dist/components/progress-bar/docs/llms.md +13 -13
  136. package/dist/components/progress-bar/progress-bar.svelte +6 -6
  137. package/dist/components/progress-bar/types.d.ts +4 -4
  138. package/dist/components/progress-ring/docs/llms.md +14 -14
  139. package/dist/components/progress-ring/progress-ring.svelte +5 -5
  140. package/dist/components/progress-ring/types.d.ts +3 -3
  141. package/dist/components/radio-button/docs/llms.md +11 -8
  142. package/dist/components/radio-button/radio-button.svelte +38 -12
  143. package/dist/components/radio-button/radio-button.svelte.d.ts +1 -1
  144. package/dist/components/radio-button/types.d.ts +11 -8
  145. package/dist/components/rating/docs/llms.md +111 -0
  146. package/dist/components/rating/rating.svelte +247 -0
  147. package/dist/components/rating/rating.svelte.d.ts +19 -0
  148. package/dist/components/rating/types.d.ts +44 -0
  149. package/dist/components/rating/types.js +1 -0
  150. package/dist/components/side-nav/docs/llms.md +110 -0
  151. package/dist/components/side-nav/side-nav-branch.svelte +43 -0
  152. package/dist/components/side-nav/side-nav-branch.svelte.d.ts +4 -0
  153. package/dist/components/side-nav/side-nav-item.svelte +75 -0
  154. package/dist/components/side-nav/side-nav-item.svelte.d.ts +25 -0
  155. package/dist/components/side-nav/side-nav-list.svelte +32 -0
  156. package/dist/components/side-nav/side-nav-list.svelte.d.ts +7 -0
  157. package/dist/components/side-nav/side-nav.d.ts +2 -0
  158. package/dist/components/side-nav/side-nav.js +2 -0
  159. package/dist/components/side-nav/side-nav.svelte +355 -0
  160. package/dist/components/side-nav/side-nav.svelte.d.ts +24 -0
  161. package/dist/components/side-nav/types.d.ts +149 -0
  162. package/dist/components/side-nav/types.js +1 -0
  163. package/dist/components/skeleton/docs/llms.md +1 -1
  164. package/dist/components/skeleton/skeleton.svelte +2 -2
  165. package/dist/components/skeleton/types.d.ts +1 -1
  166. package/dist/components/slider/docs/llms.md +31 -28
  167. package/dist/components/slider/slider.svelte +126 -61
  168. package/dist/components/slider/slider.svelte.d.ts +1 -3
  169. package/dist/components/slider/types.d.ts +21 -14
  170. package/dist/components/tab-view/docs/llms.md +7 -7
  171. package/dist/components/tab-view/tab-view-tab.svelte +16 -14
  172. package/dist/components/tab-view/tab-view.svelte +16 -9
  173. package/dist/components/tab-view/types.d.ts +6 -6
  174. package/dist/components/table/docs/llms.md +38 -33
  175. package/dist/components/table/table-body.svelte +2 -2
  176. package/dist/components/table/table-cell-actions.svelte +8 -2
  177. package/dist/components/table/table-cell-layout.svelte +2 -2
  178. package/dist/components/table/table-cell.svelte +2 -2
  179. package/dist/components/table/table-header-cell.svelte +2 -2
  180. package/dist/components/table/table-header.svelte +2 -2
  181. package/dist/components/table/table-row.svelte +2 -2
  182. package/dist/components/table/table-selection-cell.svelte +6 -6
  183. package/dist/components/table/table.svelte +2 -2
  184. package/dist/components/table/types.d.ts +11 -11
  185. package/dist/components/tag/docs/llms.md +383 -0
  186. package/dist/components/tag/tag-group.d.ts +2 -0
  187. package/dist/components/tag/tag-group.js +2 -0
  188. package/dist/components/tag/tag-group.svelte +117 -0
  189. package/dist/components/tag/tag-group.svelte.d.ts +20 -0
  190. package/dist/components/tag/tag.svelte +459 -0
  191. package/dist/components/tag/tag.svelte.d.ts +19 -0
  192. package/dist/components/tag/types.d.ts +137 -0
  193. package/dist/components/tag/types.js +1 -0
  194. package/dist/components/tag-picker/docs/llms.md +298 -0
  195. package/dist/components/tag-picker/option-group.svelte +51 -0
  196. package/dist/components/tag-picker/option-group.svelte.d.ts +4 -0
  197. package/dist/components/tag-picker/option.svelte +82 -0
  198. package/dist/components/tag-picker/option.svelte.d.ts +4 -0
  199. package/dist/components/tag-picker/tag-picker.d.ts +2 -0
  200. package/dist/components/tag-picker/tag-picker.js +2 -0
  201. package/dist/components/tag-picker/tag-picker.svelte +716 -0
  202. package/dist/components/tag-picker/tag-picker.svelte.d.ts +21 -0
  203. package/dist/components/tag-picker/types.d.ts +142 -0
  204. package/dist/components/tag-picker/types.js +1 -0
  205. package/dist/components/text-box/docs/llms.md +31 -4
  206. package/dist/components/text-box/text-box-button.svelte +3 -3
  207. package/dist/components/text-box/text-box-button.svelte.d.ts +1 -1
  208. package/dist/components/text-box/text-box.svelte +41 -14
  209. package/dist/components/text-box/types.d.ts +5 -5
  210. package/dist/components/textarea/docs/llms.md +4 -3
  211. package/dist/components/textarea/textarea.svelte +14 -6
  212. package/dist/components/textarea/types.d.ts +2 -4
  213. package/dist/components/time-picker/docs/llms.md +18 -15
  214. package/dist/components/time-picker/time-picker.svelte +133 -33
  215. package/dist/components/time-picker/time-picker.svelte.d.ts +1 -1
  216. package/dist/components/time-picker/types.d.ts +23 -13
  217. package/dist/components/title-bar/docs/llms.md +382 -0
  218. package/dist/components/title-bar/title-bar-left-controls.svelte +215 -0
  219. package/dist/components/title-bar/title-bar-left-controls.svelte.d.ts +22 -0
  220. package/dist/components/title-bar/title-bar-right-controls.svelte +190 -0
  221. package/dist/components/title-bar/title-bar-right-controls.svelte.d.ts +27 -0
  222. package/dist/components/title-bar/title-bar.d.ts +3 -0
  223. package/dist/components/title-bar/title-bar.js +4 -0
  224. package/dist/components/title-bar/title-bar.svelte +224 -0
  225. package/dist/components/title-bar/title-bar.svelte.d.ts +26 -0
  226. package/dist/components/title-bar/types.d.ts +165 -0
  227. package/dist/components/title-bar/types.js +1 -0
  228. package/dist/components/toggle-switch/docs/llms.md +11 -9
  229. package/dist/components/toggle-switch/toggle-switch.svelte +23 -14
  230. package/dist/components/toggle-switch/toggle-switch.svelte.d.ts +1 -1
  231. package/dist/components/toggle-switch/types.d.ts +12 -10
  232. package/dist/components/tooltip/docs/llms.md +1 -1
  233. package/dist/components/tooltip/tooltip.svelte +5 -4
  234. package/dist/components/tooltip/types.d.ts +1 -1
  235. package/dist/components/top-nav/docs/llms.md +1 -1
  236. package/dist/components/top-nav/top-nav-item.svelte +2 -2
  237. package/dist/components/top-nav/top-nav.svelte +2 -2
  238. package/dist/components/top-nav/types.d.ts +2 -2
  239. package/dist/components/tree-view/docs/llms.md +11 -11
  240. package/dist/components/tree-view/tree-view-item-content.svelte +3 -3
  241. package/dist/components/tree-view/tree-view-item.svelte +13 -5
  242. package/dist/components/tree-view/tree-view.svelte +20 -5
  243. package/dist/components/tree-view/tree-view.svelte.d.ts +1 -1
  244. package/dist/components/tree-view/tree-view.svelte.js +31 -3
  245. package/dist/components/tree-view/types.d.ts +7 -3
  246. package/dist/index.d.ts +25 -0
  247. package/dist/index.js +32 -0
  248. package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte +26 -5
  249. package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte.d.ts +2 -0
  250. package/dist/internal/constants.d.ts +0 -4
  251. package/dist/internal/constants.js +0 -4002
  252. package/dist/internal/index.d.ts +1 -0
  253. package/dist/internal/index.js +1 -0
  254. package/dist/internal/native-field.svelte.d.ts +44 -0
  255. package/dist/internal/native-field.svelte.js +85 -0
  256. package/dist/internal/utils.d.ts +16 -2
  257. package/dist/internal/utils.js +25 -3
  258. package/dist/types/index.d.ts +3 -3
  259. package/package.json +51 -37
@@ -1,14 +1,17 @@
1
1
  <script lang="ts">
2
+ import { claimLabel } from '../label/label-context.js';
2
3
  import type { TimePickerProps } from './types.js';
3
4
  import { Flyout, Button, Divider } from '../../index.js';
4
5
  import { on } from 'svelte/events';
5
6
  import { tick } from 'svelte';
6
7
  import { PREFIX } from '../../internal/constants.js';
7
- import { floating } from '../../internal/index.js';
8
+ import { dispatchFieldEvents, floating, invokeHandlers, NativeField } from '../../internal/index.js';
8
9
  import { flip, hide, offset, shift } from '@floating-ui/dom';
9
10
  import DynamicCarousel from '../../internal/components/dynamic-carousel/dynamic-carousel.svelte';
10
11
  import { CheckmarkRegular, DismissRegular } from 'fluentui-icons-svelte';
11
12
 
13
+ const labelContext = claimLabel(() => id);
14
+
12
15
  let {
13
16
  format = 24,
14
17
  value = $bindable(''),
@@ -16,24 +19,44 @@
16
19
  hideHours = false,
17
20
  hideMinutes = false,
18
21
  hideSeconds = false,
19
- element = $bindable(),
20
- wrapperRef = $bindable(),
22
+ id = labelContext?.fieldId,
23
+ name = id,
24
+ ref = $bindable(null),
25
+ buttonRef = $bindable(null),
26
+ buttonAttributes,
27
+ wrapperRef = $bindable(null),
21
28
  wrapperAttributes,
22
- inputElement = $bindable(),
23
- inputProps,
29
+ disabled,
30
+ readonly,
31
+ step,
32
+ onfocus,
33
+ onblur,
24
34
  popupLabel = 'Choose a time',
35
+ columnLabels,
25
36
  ...attributes
26
37
  }: TimePickerProps = $props();
27
38
 
28
39
  const FALLBACK_ID = $props.id();
29
40
  const POPUP_ID = `${PREFIX}timepicker-${FALLBACK_ID}-popup`;
30
41
 
31
- let popupRef: HTMLElement | undefined = $state();
42
+ let popupRef: HTMLElement | null = $state(null);
43
+
44
+ const native = new NativeField(
45
+ () => ref,
46
+ () => buttonRef,
47
+ labelContext
48
+ );
32
49
 
33
50
  /** Closing always hands the focus back, so the keyboard never lands nowhere. */
34
51
  function closePopup() {
35
52
  open = false;
36
- element?.focus();
53
+ buttonRef?.focus();
54
+ }
55
+
56
+ /** A label activates the native input it belongs to, which hands the activation to the button. */
57
+ function openFromField() {
58
+ buttonRef?.focus();
59
+ open = !readonly;
37
60
  }
38
61
 
39
62
  // Escape has to work from inside the popup too, and the popup is not a descendant
@@ -64,19 +87,23 @@
64
87
  const HOURS_12 = Array.from({ length: 12 }, (_, i) => pad(i === 0 ? 12 : i)); // 12, 01 … 11
65
88
  const SIXTY = Array.from({ length: 60 }, (_, i) => pad(i));
66
89
  const MERIDIEM = ['AM', 'PM'];
67
- const LABELS: Record<Column, string> = {
90
+ // Name the columns on the trigger while there is no time, and the listboxes of the popup.
91
+ const labels: Record<Column, string> = $derived({
68
92
  hour: 'Hour',
69
93
  minute: 'Minute',
70
94
  second: 'Second',
71
- meridiem: 'AM/PM'
72
- };
95
+ meridiem: 'AM/PM',
96
+ ...columnLabels
97
+ });
73
98
 
74
99
  const hour12 = $derived(format === 12);
75
100
 
76
101
  // Working selection — canonical 24h values, synced with `value` while the popup is closed.
77
- let hour = $state(new Date().getHours()); // 0-23
78
- let minute = $state(new Date().getMinutes()); // 0-59
79
- let second = $state(new Date().getSeconds()); // 0-59
102
+ // It starts from `value`, so a popup rendered open on the server shows it too.
103
+ const initial = parseValue(value);
104
+ let hour = $state(initial.h); // 0-23
105
+ let minute = $state(initial.mi); // 0-59
106
+ let second = $state(initial.s); // 0-59
80
107
 
81
108
  const isPM = $derived(hour >= 12);
82
109
  // 12h wheel index: hour % 12 (0 → "12", 1 → "01", …, 11 → "11").
@@ -94,6 +121,9 @@
94
121
 
95
122
  const hasValue = $derived(/^\d{2}:\d{2}(:\d{2})?$/.test(value ?? ''));
96
123
 
124
+ // Parsed committed value: the closed trigger reads it, since the working selection only catches up in an effect.
125
+ const committed = $derived(parseValue(value));
126
+
97
127
  function parseValue(v: string) {
98
128
  const m = /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(v ?? '');
99
129
  const t = new Date();
@@ -127,7 +157,11 @@
127
157
  }
128
158
 
129
159
  function confirm() {
130
- value = `${pad(hour)}:${pad(minute)}${hideSeconds ? '' : `:${pad(second)}`}`;
160
+ const next = `${pad(hour)}:${pad(minute)}${hideSeconds ? '' : `:${pad(second)}`}`;
161
+ if (next !== value) {
162
+ value = next;
163
+ dispatchFieldEvents(ref);
164
+ }
131
165
  closePopup();
132
166
  }
133
167
 
@@ -138,24 +172,29 @@
138
172
  // Trigger label per column: the live selection while open, the committed value once set,
139
173
  // otherwise the placeholder column name.
140
174
  function display(col: Column): string {
141
- if (!open && !hasValue) return LABELS[col];
142
- if (col === 'hour') return hour12 ? HOURS_12[hour12Index] : pad(hour);
143
- if (col === 'minute') return pad(minute);
144
- if (col === 'second') return pad(second);
145
- return isPM ? 'PM' : 'AM';
175
+ if (!open && !hasValue) return labels[col];
176
+ const { h, mi, s } = open ? { h: hour, mi: minute, s: second } : committed;
177
+ if (col === 'hour') return hour12 ? HOURS_12[h % 12] : pad(h);
178
+ if (col === 'minute') return pad(mi);
179
+ if (col === 'second') return pad(s);
180
+ return h >= 12 ? 'PM' : 'AM';
146
181
  }
147
182
  </script>
148
183
 
149
- <div class="fs-time-picker-wrapper" bind:this={wrapperRef} {...wrapperAttributes}>
184
+ <div {...wrapperAttributes} class={['fs-time-picker-wrapper', wrapperAttributes?.class]} bind:this={wrapperRef}>
150
185
  <button
186
+ {...buttonAttributes}
187
+ {...native.aria(attributes, buttonAttributes, 'button')}
151
188
  type="button"
152
- class="fs-time-picker"
189
+ class={['fs-time-picker', buttonAttributes?.class]}
190
+ {disabled}
153
191
  aria-haspopup="dialog"
154
192
  aria-expanded={open}
155
193
  aria-controls={open ? POPUP_ID : undefined}
156
- onclick={() => (open = !open)}
157
- bind:this={element}
158
- {...attributes}
194
+ onclick={(e) => invokeHandlers(e, [], [() => (open = !readonly && !open), buttonAttributes?.onclick])}
195
+ onfocus={(e) => invokeHandlers(e, [], [onfocus, buttonAttributes?.onfocus])}
196
+ onblur={(e) => invokeHandlers(e, [], [onblur, buttonAttributes?.onblur])}
197
+ bind:this={buttonRef}
159
198
  >
160
199
  {#each columns as col, idx (col)}
161
200
  {#if idx > 0}
@@ -165,13 +204,29 @@
165
204
  {/each}
166
205
  </button>
167
206
 
168
- <!-- Carries the value into a form. -->
169
- <input type="time" hidden step={hideSeconds ? undefined : 1} {value} bind:this={inputElement} {...inputProps} />
207
+ <!-- The field of the form: submitted, validated and reset like any time input,
208
+ behind the button and out of the tab order, since the button is what people use. See `NativeField`.
209
+ Seconds need a step of one to be a valid value. -->
210
+ <input
211
+ {...attributes}
212
+ {id}
213
+ {name}
214
+ class="native-field"
215
+ aria-hidden={native.reported ? undefined : 'true'}
216
+ type="time"
217
+ tabindex={-1}
218
+ step={step ?? (hideSeconds ? undefined : 1)}
219
+ {disabled}
220
+ {readonly}
221
+ bind:value
222
+ bind:this={ref}
223
+ onclick={openFromField}
224
+ />
170
225
  </div>
171
226
 
172
227
  {#if open}
173
228
  <Flyout
174
- {@attach floating(element, {
229
+ {@attach floating(buttonRef, {
175
230
  placement: 'bottom',
176
231
  middleware: [
177
232
  offset(({ rects }) => {
@@ -183,7 +238,7 @@
183
238
  ],
184
239
  strategy: 'fixed'
185
240
  })}
186
- reference={element}
241
+ reference={buttonRef}
187
242
  id={POPUP_ID}
188
243
  role="dialog"
189
244
  aria-modal="true"
@@ -198,16 +253,37 @@
198
253
  <div class="carousel-col col-{col}">
199
254
  {#if col === 'hour'}
200
255
  {#if hour12}
201
- <DynamicCarousel values={HOURS_12} selectedIndex={hour12Index} onSelected={(_, i) => setHour12(i)} />
256
+ <DynamicCarousel
257
+ label={labels.hour}
258
+ values={HOURS_12}
259
+ selectedIndex={hour12Index}
260
+ onSelected={(_, i) => setHour12(i)}
261
+ />
202
262
  {:else}
203
- <DynamicCarousel values={HOURS_24} selectedIndex={hour} onSelected={(_, i) => (hour = i)} />
263
+ <DynamicCarousel
264
+ label={labels.hour}
265
+ values={HOURS_24}
266
+ selectedIndex={hour}
267
+ onSelected={(_, i) => (hour = i)}
268
+ />
204
269
  {/if}
205
270
  {:else if col === 'minute'}
206
- <DynamicCarousel values={SIXTY} selectedIndex={minute} onSelected={(_, i) => (minute = i)} />
271
+ <DynamicCarousel
272
+ label={labels.minute}
273
+ values={SIXTY}
274
+ selectedIndex={minute}
275
+ onSelected={(_, i) => (minute = i)}
276
+ />
207
277
  {:else if col === 'second'}
208
- <DynamicCarousel values={SIXTY} selectedIndex={second} onSelected={(_, i) => (second = i)} />
278
+ <DynamicCarousel
279
+ label={labels.second}
280
+ values={SIXTY}
281
+ selectedIndex={second}
282
+ onSelected={(_, i) => (second = i)}
283
+ />
209
284
  {:else}
210
285
  <DynamicCarousel
286
+ label={labels.meridiem}
211
287
  values={MERIDIEM}
212
288
  selectedIndex={isPM ? 1 : 0}
213
289
  infinite={false}
@@ -230,11 +306,34 @@
230
306
  {/if}
231
307
 
232
308
  <style>
309
+ /* The box of the button, which the native field covers so its validation message points at the button. */
233
310
  .fs-time-picker-wrapper {
234
- display: contents;
311
+ display: flex;
312
+ position: relative;
313
+ inline-size: fit-content;
314
+ }
315
+ .fs-time-picker-wrapper:has(> .native-field:is(:user-invalid, [aria-invalid='true'])) {
316
+ & .picker-content {
317
+ color: var(--fs-system-critical);
318
+ }
319
+ & .fs-time-picker::after,
320
+ & :global(.fs-divider) {
321
+ background: var(--fs-system-critical);
322
+ }
323
+ }
324
+ .native-field {
325
+ position: absolute;
326
+ inset: 0;
327
+ inline-size: 100%;
328
+ block-size: 100%;
329
+ margin: 0;
330
+ box-sizing: border-box;
331
+ opacity: 0;
332
+ pointer-events: none;
235
333
  }
236
334
  .fs-time-picker {
237
335
  display: flex;
336
+ flex: 1 1 auto;
238
337
  position: relative;
239
338
  border-radius: var(--fs-control-border-radius);
240
339
  font-size: var(--fs-body-font-size);
@@ -291,6 +390,7 @@
291
390
  position: fixed !important;
292
391
  top: 0;
293
392
  left: 0;
393
+ z-index: 110;
294
394
  max-width: min-content;
295
395
  padding: 0 !important;
296
396
  & .wrapper {
@@ -1,4 +1,4 @@
1
1
  import type { TimePickerProps } from './types.ts';
2
- declare const TimePicker: import("svelte").Component<TimePickerProps, {}, "value" | "element" | "wrapperRef" | "open" | "inputElement">;
2
+ declare const TimePicker: import("svelte").Component<TimePickerProps, {}, "ref" | "value" | "open" | "wrapperRef" | "buttonRef">;
3
3
  type TimePicker = ReturnType<typeof TimePicker>;
4
4
  export default TimePicker;
@@ -1,4 +1,5 @@
1
1
  import type { HTMLAttributes, HTMLButtonAttributes, HTMLInputAttributes } from 'svelte/elements';
2
+ import type { NativeFieldAttributes } from '../../internal/index.js';
2
3
  /** @propsmith TimePickerProps */
3
4
  export type TimePickerProps = {
4
5
  /** Selected time as 24h `HH:mm` or `HH:mm:ss` (matches `<input type="time">`).
@@ -27,28 +28,37 @@ export type TimePickerProps = {
27
28
  * @default false
28
29
  */
29
30
  hideSeconds?: boolean;
30
- /** The DOM reference of the trigger button.
31
+ /** The DOM reference of the native time input that holds the value. The other attributes of the picker are applied to it.
31
32
  * @bindable
32
33
  */
33
- element?: HTMLButtonElement;
34
- /** The DOM reference of the element wrapping the trigger and its input.
34
+ ref?: HTMLInputElement | null;
35
+ /** The DOM reference of the button that opens the picker.
35
36
  * @bindable
36
37
  */
37
- wrapperRef?: HTMLDivElement;
38
- /** The attributes to spread on the wrapper element.
39
- * @type HTMLAttributes
38
+ buttonRef?: HTMLButtonElement | null;
39
+ /** The attributes to spread on the button that opens the picker.
40
+ * @type HTMLButtonAttributes
40
41
  */
41
- wrapperAttributes?: HTMLAttributes<HTMLDivElement>;
42
- /** The DOM reference of the underlying input element.
42
+ buttonAttributes?: HTMLButtonAttributes;
43
+ /** The DOM reference of the element wrapping the button and the native input.
43
44
  * @bindable
44
45
  */
45
- inputElement?: HTMLInputElement;
46
- /** HTML attributes for the underlying input element. Give it a `name` to submit the
47
- * value with a form.
46
+ wrapperRef?: HTMLDivElement | null;
47
+ /** The attributes to spread on the wrapper element.
48
+ * @type HTMLAttributes
48
49
  */
49
- inputProps?: HTMLInputAttributes;
50
+ wrapperAttributes?: HTMLAttributes<HTMLDivElement>;
50
51
  /** The accessible name of the popup, which is announced as a dialog.
51
52
  * @default 'Choose a time'
52
53
  */
53
54
  popupLabel?: string;
54
- } & HTMLButtonAttributes;
55
+ /** The names of the hour, minute, second and AM/PM columns: shown on the trigger while there is no time, and given to the lists of the popup.
56
+ * @default { hour: 'Hour', minute: 'Minute', second: 'Second', meridiem: 'AM/PM' }
57
+ */
58
+ columnLabels?: {
59
+ hour?: string;
60
+ minute?: string;
61
+ second?: string;
62
+ meridiem?: string;
63
+ };
64
+ } & NativeFieldAttributes<HTMLInputAttributes>;