@human-kit/svelte-components 1.0.0-alpha.2 → 1.0.0-alpha.4

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 (217) hide show
  1. package/dist/FOCUS_STATE_CONTRACT.md +63 -0
  2. package/dist/FOCUS_STATE_REVIEW_TEMPLATE.md +70 -0
  3. package/dist/calendar/README.md +2 -1
  4. package/dist/calendar/TODO.md +21 -107
  5. package/dist/calendar/body-cell/README.md +15 -0
  6. package/dist/calendar/body-cell/calendar-body-cell.svelte +116 -41
  7. package/dist/calendar/grid/README.md +13 -0
  8. package/dist/calendar/grid-body/README.md +13 -0
  9. package/dist/calendar/grid-header/README.md +13 -0
  10. package/dist/calendar/header-cell/README.md +14 -0
  11. package/dist/calendar/heading/README.md +13 -0
  12. package/dist/calendar/root/README.md +24 -0
  13. package/dist/calendar/root/calendar-root-test.svelte +4 -0
  14. package/dist/calendar/root/calendar-root-test.svelte.d.ts +1 -0
  15. package/dist/calendar/root/calendar-root.svelte +3 -0
  16. package/dist/calendar/root/calendar-root.svelte.d.ts +1 -0
  17. package/dist/calendar/root/context.d.ts +4 -0
  18. package/dist/calendar/root/context.js +28 -25
  19. package/dist/calendar/root/date-utils.d.ts +1 -1
  20. package/dist/calendar/root/date-utils.js +16 -26
  21. package/dist/calendar/trigger-next/README.md +14 -0
  22. package/dist/calendar/trigger-previous/README.md +14 -0
  23. package/dist/clock/README.md +75 -0
  24. package/dist/clock/axis/README.md +24 -0
  25. package/dist/clock/axis/clock-axis.svelte +37 -0
  26. package/dist/clock/axis/clock-axis.svelte.d.ts +8 -0
  27. package/dist/clock/hooks/use-wheel-scroll.svelte.d.ts +16 -0
  28. package/dist/clock/hooks/use-wheel-scroll.svelte.js +336 -0
  29. package/dist/clock/index.d.ts +10 -0
  30. package/dist/clock/index.js +10 -0
  31. package/dist/clock/index.parts.d.ts +4 -0
  32. package/dist/clock/index.parts.js +4 -0
  33. package/dist/clock/root/README.md +38 -0
  34. package/dist/clock/root/clock-root-test.svelte +62 -0
  35. package/dist/clock/root/clock-root-test.svelte.d.ts +14 -0
  36. package/dist/clock/root/clock-root.svelte +329 -0
  37. package/dist/clock/root/clock-root.svelte.d.ts +25 -0
  38. package/dist/clock/root/context.d.ts +22 -0
  39. package/dist/clock/root/context.js +15 -0
  40. package/dist/clock/root/resolve-visible-columns.d.ts +7 -0
  41. package/dist/clock/root/resolve-visible-columns.js +16 -0
  42. package/dist/clock/root/time-utils.d.ts +48 -0
  43. package/dist/clock/root/time-utils.js +314 -0
  44. package/dist/clock/root/wheel-options.d.ts +17 -0
  45. package/dist/clock/root/wheel-options.js +63 -0
  46. package/dist/clock/wheel-column/README.md +25 -0
  47. package/dist/clock/wheel-column/clock-wheel-column-bindable-test.svelte +16 -0
  48. package/dist/clock/wheel-column/clock-wheel-column-bindable-test.svelte.d.ts +3 -0
  49. package/dist/clock/wheel-column/clock-wheel-column-custom-snippet-test.svelte +29 -0
  50. package/dist/clock/wheel-column/clock-wheel-column-custom-snippet-test.svelte.d.ts +6 -0
  51. package/dist/clock/wheel-column/clock-wheel-column-default-height-test.svelte +11 -0
  52. package/dist/clock/wheel-column/clock-wheel-column-default-height-test.svelte.d.ts +3 -0
  53. package/dist/clock/wheel-column/clock-wheel-column-test.svelte +38 -0
  54. package/dist/clock/wheel-column/clock-wheel-column-test.svelte.d.ts +12 -0
  55. package/dist/clock/wheel-column/clock-wheel-column-tp-test.svelte +38 -0
  56. package/dist/clock/wheel-column/clock-wheel-column-tp-test.svelte.d.ts +12 -0
  57. package/dist/clock/wheel-column/clock-wheel-column-untagged-snippet-test.svelte +29 -0
  58. package/dist/clock/wheel-column/clock-wheel-column-untagged-snippet-test.svelte.d.ts +6 -0
  59. package/dist/clock/wheel-column/clock-wheel-column.svelte +499 -0
  60. package/dist/clock/wheel-column/clock-wheel-column.svelte.d.ts +17 -0
  61. package/dist/clock/wheel-item/README.md +17 -0
  62. package/dist/clock/wheel-item/clock-wheel-item.svelte +49 -0
  63. package/dist/clock/wheel-item/clock-wheel-item.svelte.d.ts +17 -0
  64. package/dist/combobox/TODO.md +28 -175
  65. package/dist/combobox/button/combobox-button.svelte +2 -0
  66. package/dist/combobox/root/combobox.svelte +30 -0
  67. package/dist/datepicker/README.md +100 -0
  68. package/dist/datepicker/TODO.md +28 -0
  69. package/dist/datepicker/calendar/README.md +19 -0
  70. package/dist/datepicker/calendar/date-picker-calendar-unsafe-props-test.svelte +60 -0
  71. package/dist/datepicker/calendar/date-picker-calendar-unsafe-props-test.svelte.d.ts +3 -0
  72. package/dist/datepicker/calendar/date-picker-calendar.svelte +65 -0
  73. package/dist/datepicker/calendar/date-picker-calendar.svelte.d.ts +10 -0
  74. package/dist/datepicker/index.d.ts +18 -0
  75. package/dist/datepicker/index.js +18 -0
  76. package/dist/datepicker/index.parts.d.ts +14 -0
  77. package/dist/datepicker/index.parts.js +14 -0
  78. package/dist/datepicker/input/README.md +15 -0
  79. package/dist/datepicker/input/date-picker-input.svelte +108 -0
  80. package/dist/datepicker/input/date-picker-input.svelte.d.ts +11 -0
  81. package/dist/datepicker/internal/strict-props.d.ts +2 -0
  82. package/dist/datepicker/internal/strict-props.js +28 -0
  83. package/dist/datepicker/popover/README.md +20 -0
  84. package/dist/datepicker/popover/date-picker-popover-handler-test.svelte +57 -0
  85. package/dist/datepicker/popover/date-picker-popover-handler-test.svelte.d.ts +3 -0
  86. package/dist/datepicker/popover/date-picker-popover-unsafe-props-test.svelte +45 -0
  87. package/dist/datepicker/popover/date-picker-popover-unsafe-props-test.svelte.d.ts +18 -0
  88. package/dist/datepicker/popover/date-picker-popover.svelte +87 -0
  89. package/dist/datepicker/popover/date-picker-popover.svelte.d.ts +7 -0
  90. package/dist/datepicker/root/README.md +38 -0
  91. package/dist/datepicker/root/context.d.ts +43 -0
  92. package/dist/datepicker/root/context.js +15 -0
  93. package/dist/datepicker/root/date-picker-bindable-empty-test.svelte +24 -0
  94. package/dist/datepicker/root/date-picker-bindable-empty-test.svelte.d.ts +3 -0
  95. package/dist/datepicker/root/date-picker-bindable-test.svelte +41 -0
  96. package/dist/datepicker/root/date-picker-bindable-test.svelte.d.ts +3 -0
  97. package/dist/datepicker/root/date-picker-empty-test.svelte +47 -0
  98. package/dist/datepicker/root/date-picker-empty-test.svelte.d.ts +3 -0
  99. package/dist/datepicker/root/date-picker-locale-typing-test.svelte +47 -0
  100. package/dist/datepicker/root/date-picker-locale-typing-test.svelte.d.ts +3 -0
  101. package/dist/datepicker/root/date-picker-open-cancel-test.svelte +54 -0
  102. package/dist/datepicker/root/date-picker-open-cancel-test.svelte.d.ts +8 -0
  103. package/dist/datepicker/root/date-picker-root.svelte +495 -0
  104. package/dist/datepicker/root/date-picker-root.svelte.d.ts +24 -0
  105. package/dist/datepicker/root/date-picker-test.svelte +86 -0
  106. package/dist/datepicker/root/date-picker-test.svelte.d.ts +13 -0
  107. package/dist/datepicker/root/date-utils.d.ts +17 -0
  108. package/dist/datepicker/root/date-utils.js +138 -0
  109. package/dist/datepicker/root/draft-evaluation.d.ts +13 -0
  110. package/dist/datepicker/root/draft-evaluation.js +56 -0
  111. package/dist/datepicker/root/focus-controller.d.ts +3 -0
  112. package/dist/datepicker/root/focus-controller.js +15 -0
  113. package/dist/datepicker/root/open-change.d.ts +5 -0
  114. package/dist/datepicker/root/open-change.js +13 -0
  115. package/dist/datepicker/root/open-controller.d.ts +7 -0
  116. package/dist/datepicker/root/open-controller.js +15 -0
  117. package/dist/datepicker/root/segment-controller.d.ts +8 -0
  118. package/dist/datepicker/root/segment-controller.js +53 -0
  119. package/dist/datepicker/root/segment-state.d.ts +18 -0
  120. package/dist/datepicker/root/segment-state.js +134 -0
  121. package/dist/datepicker/root/value-commit.d.ts +4 -0
  122. package/dist/datepicker/root/value-commit.js +8 -0
  123. package/dist/datepicker/segment/README.md +14 -0
  124. package/dist/datepicker/segment/date-picker-segment.svelte +319 -0
  125. package/dist/datepicker/segment/date-picker-segment.svelte.d.ts +9 -0
  126. package/dist/datepicker/trigger/README.md +14 -0
  127. package/dist/datepicker/trigger/date-picker-trigger.svelte +110 -0
  128. package/dist/datepicker/trigger/date-picker-trigger.svelte.d.ts +9 -0
  129. package/dist/dialog/content/dialog-content.svelte +6 -6
  130. package/dist/dialog/root/context.d.ts +2 -1
  131. package/dist/dialog/root/dialog-root.svelte +9 -2
  132. package/dist/index.d.ts +8 -0
  133. package/dist/index.js +8 -0
  134. package/dist/listbox/root/listbox.svelte +44 -0
  135. package/dist/popover/README.md +10 -0
  136. package/dist/popover/content/popover-content-standalone-test.svelte +28 -0
  137. package/dist/popover/content/popover-content-standalone-test.svelte.d.ts +6 -0
  138. package/dist/popover/content/popover-content-test.svelte +2 -1
  139. package/dist/popover/content/popover-content-test.svelte.d.ts +2 -1
  140. package/dist/popover/content/popover-content.svelte +91 -18
  141. package/dist/popover/content/popover-content.svelte.d.ts +5 -1
  142. package/dist/popover/index.d.ts +1 -1
  143. package/dist/popover/index.js +1 -3
  144. package/dist/popover/root/README.md +10 -15
  145. package/dist/popover/root/context.d.ts +16 -7
  146. package/dist/popover/root/context.js +0 -2
  147. package/dist/popover/root/focus-state.d.ts +4 -0
  148. package/dist/popover/root/focus-state.js +33 -0
  149. package/dist/popover/root/popover-root.svelte +90 -17
  150. package/dist/popover/root/popover-root.svelte.d.ts +2 -1
  151. package/dist/popover/root/popover-test.svelte +2 -1
  152. package/dist/popover/root/popover-test.svelte.d.ts +2 -1
  153. package/dist/popover/trigger/popover-trigger-button.svelte +4 -4
  154. package/dist/popover/trigger/popover-trigger.svelte +1 -1
  155. package/dist/portal/portal.svelte +3 -1
  156. package/dist/primitives/click-outside.d.ts +1 -1
  157. package/dist/primitives/click-outside.js +1 -1
  158. package/dist/primitives/focus-trap.d.ts +7 -2
  159. package/dist/primitives/focus-trap.js +50 -17
  160. package/dist/primitives/index.d.ts +1 -0
  161. package/dist/primitives/index.js +1 -0
  162. package/dist/primitives/input-modality.d.ts +7 -0
  163. package/dist/primitives/input-modality.js +125 -0
  164. package/dist/test-utils/focus-contract.d.ts +3 -0
  165. package/dist/test-utils/focus-contract.js +26 -0
  166. package/dist/timepicker/IMPLEMENTATION_PLAN.md +254 -0
  167. package/dist/timepicker/README.md +97 -0
  168. package/dist/timepicker/TODO.md +86 -0
  169. package/dist/timepicker/clock/README.md +14 -0
  170. package/dist/timepicker/clock/time-picker-clock-test.svelte +45 -0
  171. package/dist/timepicker/clock/time-picker-clock-test.svelte.d.ts +11 -0
  172. package/dist/timepicker/clock/time-picker-clock.svelte +65 -0
  173. package/dist/timepicker/clock/time-picker-clock.svelte.d.ts +10 -0
  174. package/dist/timepicker/index.d.ts +14 -0
  175. package/dist/timepicker/index.js +14 -0
  176. package/dist/timepicker/index.parts.d.ts +8 -0
  177. package/dist/timepicker/index.parts.js +8 -0
  178. package/dist/timepicker/input/README.md +15 -0
  179. package/dist/timepicker/input/time-picker-input-forwarding-test.svelte +40 -0
  180. package/dist/timepicker/input/time-picker-input-forwarding-test.svelte.d.ts +3 -0
  181. package/dist/timepicker/input/time-picker-input.svelte +109 -0
  182. package/dist/timepicker/input/time-picker-input.svelte.d.ts +11 -0
  183. package/dist/timepicker/internal/strict-props.d.ts +4 -0
  184. package/dist/timepicker/internal/strict-props.js +51 -0
  185. package/dist/timepicker/popover/README.md +20 -0
  186. package/dist/timepicker/popover/time-picker-popover-unsafe-props-test.svelte +22 -0
  187. package/dist/timepicker/popover/time-picker-popover-unsafe-props-test.svelte.d.ts +3 -0
  188. package/dist/timepicker/popover/time-picker-popover.svelte +89 -0
  189. package/dist/timepicker/popover/time-picker-popover.svelte.d.ts +7 -0
  190. package/dist/timepicker/root/README.md +42 -0
  191. package/dist/timepicker/root/context.d.ts +51 -0
  192. package/dist/timepicker/root/context.js +15 -0
  193. package/dist/timepicker/root/time-picker-12h-test.svelte +22 -0
  194. package/dist/timepicker/root/time-picker-12h-test.svelte.d.ts +3 -0
  195. package/dist/timepicker/root/time-picker-bindable-test.svelte +25 -0
  196. package/dist/timepicker/root/time-picker-bindable-test.svelte.d.ts +3 -0
  197. package/dist/timepicker/root/time-picker-empty-test.svelte +20 -0
  198. package/dist/timepicker/root/time-picker-empty-test.svelte.d.ts +3 -0
  199. package/dist/timepicker/root/time-picker-root.svelte +625 -0
  200. package/dist/timepicker/root/time-picker-root.svelte.d.ts +28 -0
  201. package/dist/timepicker/root/time-picker-test.svelte +72 -0
  202. package/dist/timepicker/root/time-picker-test.svelte.d.ts +15 -0
  203. package/dist/timepicker/root/time-utils.d.ts +1 -0
  204. package/dist/timepicker/root/time-utils.js +3 -0
  205. package/dist/timepicker/segment/README.md +14 -0
  206. package/dist/timepicker/segment/time-picker-segment.svelte +365 -0
  207. package/dist/timepicker/segment/time-picker-segment.svelte.d.ts +9 -0
  208. package/dist/timepicker/trigger/README.md +14 -0
  209. package/dist/timepicker/trigger/time-picker-trigger-forwarding-test.svelte +35 -0
  210. package/dist/timepicker/trigger/time-picker-trigger-forwarding-test.svelte.d.ts +3 -0
  211. package/dist/timepicker/trigger/time-picker-trigger.svelte +122 -0
  212. package/dist/timepicker/trigger/time-picker-trigger.svelte.d.ts +9 -0
  213. package/dist/utils/date-only.d.ts +11 -0
  214. package/dist/utils/date-only.js +53 -0
  215. package/dist/utils/index.d.ts +1 -0
  216. package/dist/utils/index.js +1 -0
  217. package/package.json +16 -1
@@ -0,0 +1,15 @@
1
+ # DatePicker Input
2
+
3
+ ## API reference
4
+
5
+ ### DatePicker.Input
6
+
7
+ Name: `DatePicker.Input`
8
+ Description: Segmented date input group tied to `DatePicker.Root` value and focus management.
9
+
10
+ | Prop | Type | Default | Description |
11
+ | -------------- | ---------------------------------- | ----------- | ----------------------------------------------------- |
12
+ | `children` | `Snippet<[DatePickerSegmentPart]>` | `undefined` | Optional custom renderer for each date segment part. |
13
+ | `class` | `string` | `''` | CSS class names for the input group element. |
14
+ | `aria-label` | `string` | `undefined` | Accessible label for the segmented input group. |
15
+ | `...restProps` | `HTMLAttributes<HTMLDivElement>` | `-` | Additional attributes forwarded to the group element. |
@@ -0,0 +1,108 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { useDatePickerContext, type DatePickerSegmentPart } from '../root/context';
5
+ import DatePickerSegment from '../segment/date-picker-segment.svelte';
6
+ import {
7
+ shouldShowFocusVisible,
8
+ trackInteractionModality
9
+ } from '../../primitives/input-modality';
10
+
11
+ type DatePickerInputProps = Omit<
12
+ HTMLAttributes<HTMLDivElement>,
13
+ | 'children'
14
+ | 'class'
15
+ | 'id'
16
+ | 'role'
17
+ | 'tabindex'
18
+ | 'onmousedown'
19
+ | 'onfocus'
20
+ | 'onblur'
21
+ | 'onkeydown'
22
+ > & {
23
+ children?: Snippet<[DatePickerSegmentPart]>;
24
+ class?: string;
25
+ 'aria-label'?: string;
26
+ };
27
+
28
+ let {
29
+ children,
30
+ class: className = '',
31
+ 'aria-label': ariaLabel,
32
+ ...restProps
33
+ }: DatePickerInputProps = $props();
34
+
35
+ const datePicker = useDatePickerContext();
36
+ const segments = $derived(datePicker.getSegments());
37
+ const inputId = $derived(`${datePicker.id}-input`);
38
+
39
+ function handleMouseDown(event: MouseEvent) {
40
+ if (datePicker.isDisabled) return;
41
+ trackInteractionModality(event, event.currentTarget as HTMLElement);
42
+ datePicker.setFocusVisible(false);
43
+
44
+ const target = event.target as HTMLElement | null;
45
+ if (target?.closest('[data-date-picker-segment="true"]')) {
46
+ return;
47
+ }
48
+
49
+ event.preventDefault();
50
+ datePicker.focusNextPlaceholderOrLastSegment();
51
+ }
52
+
53
+ function handleFocus(event: FocusEvent) {
54
+ if (datePicker.isDisabled) return;
55
+ datePicker.syncFocusWithin();
56
+ datePicker.setFocusVisible(shouldShowFocusVisible(event.target as HTMLElement | null));
57
+ const target = event.target as HTMLElement | null;
58
+ if (target?.closest('[data-date-picker-segment="true"]')) {
59
+ return;
60
+ }
61
+ datePicker.focusNextPlaceholderOrLastSegment();
62
+ }
63
+
64
+ function handleBlur() {
65
+ queueMicrotask(() => {
66
+ datePicker.syncFocusWithin();
67
+ });
68
+ }
69
+
70
+ function handleKeydown(event: KeyboardEvent) {
71
+ if (datePicker.isDisabled) return;
72
+ if (event.key !== 'Enter' && event.key !== ' ') return;
73
+ trackInteractionModality(event, event.currentTarget as HTMLElement);
74
+ datePicker.setFocusVisible(true);
75
+ event.preventDefault();
76
+ datePicker.focusNextPlaceholderOrLastSegment();
77
+ }
78
+ </script>
79
+
80
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
81
+ <!-- svelte-ignore a11y_role_supports_aria_props -->
82
+ <div
83
+ id={inputId}
84
+ class={className}
85
+ {...restProps}
86
+ role="group"
87
+ aria-label={ariaLabel}
88
+ aria-invalid={datePicker.isInvalidDraft || undefined}
89
+ tabindex={datePicker.isDisabled ? -1 : 0}
90
+ data-disabled={datePicker.isDisabled || undefined}
91
+ data-readonly={datePicker.isReadOnly || undefined}
92
+ data-open={datePicker.open || undefined}
93
+ data-focus-visible={datePicker.focusVisible || undefined}
94
+ data-focus-within={datePicker.focusWithin || undefined}
95
+ data-invalid={datePicker.isInvalidDraft || undefined}
96
+ onmousedown={handleMouseDown}
97
+ onfocus={handleFocus}
98
+ onblur={handleBlur}
99
+ onkeydown={handleKeydown}
100
+ >
101
+ {#each segments as segment, index (index)}
102
+ {#if children}
103
+ {@render children(segment)}
104
+ {:else}
105
+ <DatePickerSegment {segment} />
106
+ {/if}
107
+ {/each}
108
+ </div>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { type DatePickerSegmentPart } from '../root/context';
4
+ type DatePickerInputProps = Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'class' | 'id' | 'role' | 'tabindex' | 'onmousedown' | 'onfocus' | 'onblur' | 'onkeydown'> & {
5
+ children?: Snippet<[DatePickerSegmentPart]>;
6
+ class?: string;
7
+ 'aria-label'?: string;
8
+ };
9
+ declare const DatePickerInput: import("svelte").Component<DatePickerInputProps, {}, "">;
10
+ type DatePickerInput = ReturnType<typeof DatePickerInput>;
11
+ export default DatePickerInput;
@@ -0,0 +1,2 @@
1
+ export declare function sanitizeDatePickerProps(componentName: string, props: Record<string, unknown>, forbiddenProps: string[]): Record<string, unknown>;
2
+ export declare function composeEventHandlers<TEvent extends Event>(internalHandler: ((event: TEvent) => void) | undefined, externalHandler: ((event: TEvent) => void) | undefined): (event: TEvent) => void;
@@ -0,0 +1,28 @@
1
+ const warnedMessages = new Set();
2
+ function warnOnce(message) {
3
+ if (!import.meta.env.DEV)
4
+ return;
5
+ if (warnedMessages.has(message))
6
+ return;
7
+ warnedMessages.add(message);
8
+ console.warn(message);
9
+ }
10
+ export function sanitizeDatePickerProps(componentName, props, forbiddenProps) {
11
+ if (props === null || typeof props !== 'object')
12
+ return {};
13
+ const sanitized = {};
14
+ for (const [key, value] of Object.entries(props)) {
15
+ if (forbiddenProps.includes(key)) {
16
+ warnOnce(`[DatePicker.${componentName}]: Prop "${key}" is controlled by DatePicker.Root and has been ignored.`);
17
+ continue;
18
+ }
19
+ sanitized[key] = value;
20
+ }
21
+ return sanitized;
22
+ }
23
+ export function composeEventHandlers(internalHandler, externalHandler) {
24
+ return (event) => {
25
+ internalHandler?.(event);
26
+ externalHandler?.(event);
27
+ };
28
+ }
@@ -0,0 +1,20 @@
1
+ # DatePicker Popover
2
+
3
+ ## API reference
4
+
5
+ ### DatePicker.Popover
6
+
7
+ Name: `DatePicker.Popover`
8
+ Description: Popover content wrapper for calendar and optional time controls, synchronized with `DatePicker.Root` open state.
9
+
10
+ | Prop | Type | Default | Description |
11
+ | -------------- | ---------------------------------------- | ------------ | ---------------------------------------------------------------- |
12
+ | `aria-label` | `string` | `'Calendar'` | Accessible name for the popover content. |
13
+ | `initialFocus` | `() => HTMLElement \| null \| undefined` | `active day` | Optional initial focus resolver for popover open. |
14
+ | `class` | `string` | `''` | CSS class names for popover content. |
15
+ | `...restProps` | `ComponentProps<typeof Popover.Content>` | `-` | Forwarded popover content props, excluding root-controlled keys. |
16
+
17
+ ### Notes
18
+
19
+ Name: Root-controlled props
20
+ Description: `open`, `triggerRef`, `onOpenChange`, and `id` are controlled by `DatePicker.Root` and ignored when passed to this part.
@@ -0,0 +1,57 @@
1
+ <script lang="ts">
2
+ import DatePicker from '../index';
3
+
4
+ let pointerDownCalls = $state(0);
5
+ let keydownCaptureCalls = $state(0);
6
+ let selectedValue = $state<string | null>('');
7
+ </script>
8
+
9
+ <DatePicker.Root
10
+ defaultValue="2026-02-10"
11
+ onChange={(nextValue) => {
12
+ selectedValue = nextValue;
13
+ }}
14
+ >
15
+ <DatePicker.Input class="date-picker-input" aria-label="Date input">
16
+ {#snippet children(segment)}
17
+ <DatePicker.Segment class="date-picker-segment" {segment} />
18
+ {/snippet}
19
+ </DatePicker.Input>
20
+ <DatePicker.Trigger class="date-picker-trigger">Open calendar</DatePicker.Trigger>
21
+
22
+ <DatePicker.Popover
23
+ class="date-picker-popover"
24
+ onmousedown={() => {
25
+ pointerDownCalls += 1;
26
+ }}
27
+ onkeydowncapture={() => {
28
+ keydownCaptureCalls += 1;
29
+ }}
30
+ >
31
+ <DatePicker.Calendar class="date-picker-calendar">
32
+ <div class="flex items-center justify-between gap-2 p-2">
33
+ <DatePicker.TriggerPrevious />
34
+ <DatePicker.Heading />
35
+ <DatePicker.TriggerNext />
36
+ </div>
37
+ <DatePicker.Grid>
38
+ <DatePicker.GridHeader>
39
+ {#snippet children(dayLabel: string)}
40
+ <DatePicker.HeaderCell>
41
+ {dayLabel}
42
+ </DatePicker.HeaderCell>
43
+ {/snippet}
44
+ </DatePicker.GridHeader>
45
+ <DatePicker.GridBody>
46
+ {#snippet children(date: string)}
47
+ <DatePicker.BodyCell {date} />
48
+ {/snippet}
49
+ </DatePicker.GridBody>
50
+ </DatePicker.Grid>
51
+ </DatePicker.Calendar>
52
+ </DatePicker.Popover>
53
+ </DatePicker.Root>
54
+
55
+ <p data-testid="pointer-down-calls">{pointerDownCalls}</p>
56
+ <p data-testid="keydown-capture-calls">{keydownCaptureCalls}</p>
57
+ <p data-testid="selected-value">{selectedValue}</p>
@@ -0,0 +1,3 @@
1
+ declare const DatePickerPopoverHandlerTest: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type DatePickerPopoverHandlerTest = ReturnType<typeof DatePickerPopoverHandlerTest>;
3
+ export default DatePickerPopoverHandlerTest;
@@ -0,0 +1,45 @@
1
+ <script lang="ts">
2
+ import DatePicker from '../index';
3
+
4
+ const unsafePopoverProps: Record<string, unknown> = {
5
+ id: 'unsafe-popover-id',
6
+ open: false,
7
+ triggerRef: null,
8
+ onOpenChange: () => {
9
+ // no-op
10
+ }
11
+ };
12
+ </script>
13
+
14
+ <DatePicker.Root defaultOpen={true}>
15
+ <DatePicker.Input class="date-picker-input" aria-label="Date input">
16
+ {#snippet children(segment)}
17
+ <DatePicker.Segment class="date-picker-segment" {segment} />
18
+ {/snippet}
19
+ </DatePicker.Input>
20
+ <DatePicker.Trigger class="date-picker-trigger">Open calendar</DatePicker.Trigger>
21
+
22
+ <DatePicker.Popover class="date-picker-popover" {...unsafePopoverProps}>
23
+ <DatePicker.Calendar class="date-picker-calendar">
24
+ <div class="flex items-center justify-between gap-2 p-2">
25
+ <DatePicker.TriggerPrevious />
26
+ <DatePicker.Heading />
27
+ <DatePicker.TriggerNext />
28
+ </div>
29
+ <DatePicker.Grid>
30
+ <DatePicker.GridHeader>
31
+ {#snippet children(dayLabel: string)}
32
+ <DatePicker.HeaderCell>
33
+ {dayLabel}
34
+ </DatePicker.HeaderCell>
35
+ {/snippet}
36
+ </DatePicker.GridHeader>
37
+ <DatePicker.GridBody>
38
+ {#snippet children(date: string)}
39
+ <DatePicker.BodyCell {date} />
40
+ {/snippet}
41
+ </DatePicker.GridBody>
42
+ </DatePicker.Grid>
43
+ </DatePicker.Calendar>
44
+ </DatePicker.Popover>
45
+ </DatePicker.Root>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const DatePickerPopoverUnsafePropsTest: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type DatePickerPopoverUnsafePropsTest = InstanceType<typeof DatePickerPopoverUnsafePropsTest>;
18
+ export default DatePickerPopoverUnsafePropsTest;
@@ -0,0 +1,87 @@
1
+ <script lang="ts">
2
+ import type { ComponentProps } from 'svelte';
3
+ import { useDatePickerContext } from '../root/context';
4
+ import { Popover } from '../../popover';
5
+ import type { PopoverOpenChangeDetails } from '../../popover/root/context';
6
+ import { composeEventHandlers, sanitizeDatePickerProps } from '../internal/strict-props';
7
+ import { trackInteractionModality } from '../../primitives/input-modality';
8
+
9
+ type ForbiddenPopoverProp = 'open' | 'triggerRef' | 'onOpenChange' | 'id';
10
+
11
+ type DatePickerPopoverProps = Omit<ComponentProps<typeof Popover.Content>, ForbiddenPopoverProp>;
12
+
13
+ const forbiddenPopoverProps: ForbiddenPopoverProp[] = [
14
+ 'open',
15
+ 'triggerRef',
16
+ 'onOpenChange',
17
+ 'id'
18
+ ];
19
+
20
+ let {
21
+ class: className = '',
22
+ children,
23
+ 'aria-label': ariaLabel = 'Calendar',
24
+ initialFocus,
25
+ onmousedown: onMouseDownExternal,
26
+ onkeydowncapture: onKeydownCaptureExternal,
27
+ ...unsafeRestProps
28
+ }: DatePickerPopoverProps = $props();
29
+
30
+ const datePicker = useDatePickerContext();
31
+ const dialogId = `${datePicker.id}-popover`;
32
+ const restProps = $derived.by(
33
+ () =>
34
+ sanitizeDatePickerProps(
35
+ 'Popover',
36
+ unsafeRestProps as Record<string, unknown>,
37
+ forbiddenPopoverProps
38
+ ) as Omit<ComponentProps<typeof Popover.Content>, ForbiddenPopoverProp>
39
+ );
40
+ const resolvedInitialFocus = $derived.by(() => {
41
+ if (typeof initialFocus === 'function') {
42
+ return () => initialFocus() ?? resolveInitialCalendarFocus();
43
+ }
44
+ if (initialFocus !== undefined) {
45
+ return initialFocus;
46
+ }
47
+ return resolveInitialCalendarFocus;
48
+ });
49
+
50
+ function handleOpenChange(nextOpen: boolean, details: PopoverOpenChangeDetails) {
51
+ datePicker.onOpenChange(nextOpen, details);
52
+ }
53
+
54
+ function resolveInitialCalendarFocus(): HTMLElement | null {
55
+ const dialog = document.getElementById(dialogId);
56
+ const activeDayCell = dialog?.querySelector<HTMLElement>('[role="gridcell"][tabindex="0"]');
57
+ return activeDayCell ?? null;
58
+ }
59
+
60
+ function handlePointerDown(event: MouseEvent) {
61
+ trackInteractionModality(event);
62
+ }
63
+
64
+ function handleKeydown(event: KeyboardEvent) {
65
+ trackInteractionModality(event);
66
+ }
67
+ </script>
68
+
69
+ <Popover.Root
70
+ open={datePicker.open}
71
+ triggerRef={datePicker.triggerRef}
72
+ onOpenChange={handleOpenChange}
73
+ >
74
+ <Popover.Content
75
+ id={dialogId}
76
+ class={className}
77
+ aria-label={ariaLabel}
78
+ onmousedown={composeEventHandlers(handlePointerDown, onMouseDownExternal ?? undefined)}
79
+ onkeydowncapture={composeEventHandlers(handleKeydown, onKeydownCaptureExternal ?? undefined)}
80
+ initialFocus={resolvedInitialFocus}
81
+ {...restProps}
82
+ >
83
+ {#if children}
84
+ {@render children()}
85
+ {/if}
86
+ </Popover.Content>
87
+ </Popover.Root>
@@ -0,0 +1,7 @@
1
+ import type { ComponentProps } from 'svelte';
2
+ import { Popover } from '../../popover';
3
+ type ForbiddenPopoverProp = 'open' | 'triggerRef' | 'onOpenChange' | 'id';
4
+ type DatePickerPopoverProps = Omit<ComponentProps<typeof Popover.Content>, ForbiddenPopoverProp>;
5
+ declare const DatePickerPopover: import("svelte").Component<DatePickerPopoverProps, {}, "">;
6
+ type DatePickerPopover = ReturnType<typeof DatePickerPopover>;
7
+ export default DatePickerPopover;
@@ -0,0 +1,38 @@
1
+ # DatePicker Root
2
+
3
+ ## API reference
4
+
5
+ ### DatePicker.Root
6
+
7
+ Name: `DatePicker.Root`
8
+ Description: State container for segmented date input, popover lifecycle, calendar selection, and validation constraints.
9
+
10
+ | Prop | Type | Default | Description |
11
+ | ------------------- | ---------------------------------------------- | ----------- | --------------------------------------------------------- |
12
+ | `value` | `DatePickerDateValue \| null` | `bindable` | Controlled ISO date value (`YYYY-MM-DD`). |
13
+ | `defaultValue` | `DatePickerDateValue \| null` | `undefined` | Initial date value for uncontrolled mode. |
14
+ | `onChange` | `(value: DatePickerDateValue \| null) => void` | `undefined` | Called when committed date value changes. |
15
+ | `open` | `boolean` | `bindable` | Controlled open state for the popover panel. |
16
+ | `defaultOpen` | `boolean` | `false` | Initial open state in uncontrolled mode. |
17
+ | `onOpenChange` | `(open: boolean, details) => void` | `undefined` | Called on open-state transitions (supports cancellation). |
18
+ | `closeOnSelect` | `boolean` | `true` | Closes the popover after calendar selection. |
19
+ | `minValue` | `DatePickerDateValue` | `undefined` | Optional lower bound for selectable dates. |
20
+ | `maxValue` | `DatePickerDateValue` | `undefined` | Optional upper bound for selectable dates. |
21
+ | `isDateUnavailable` | `(date: DatePickerDateValue) => boolean` | `undefined` | Optional predicate to block unavailable dates. |
22
+ | `isDisabled` | `boolean` | `false` | Disables interaction and selection. |
23
+ | `isReadOnly` | `boolean` | `false` | Prevents value changes while preserving navigation. |
24
+ | `children` | `Snippet` | `undefined` | Composed `DatePicker` parts. |
25
+ | `class` | `string` | `''` | CSS class names for root wrapper. |
26
+ | `aria-label` | `string` | `undefined` | Accessible label for the root wrapper. |
27
+
28
+ ### Context utilities
29
+
30
+ Name: `setDatePickerContext` / `getDatePickerContext` / `useDatePickerContext`
31
+ Description: Context helpers for internal/public `DatePicker` part composition.
32
+
33
+ | Prop | Type | Default | Description |
34
+ | ---------------------- | -------------------------------------- | ------- | --------------------------------------------------- |
35
+ | `setDatePickerContext` | `(ctx: DatePickerContext) => void` | `-` | Publishes root context. |
36
+ | `getDatePickerContext` | `() => DatePickerContext \| undefined` | `-` | Reads context when available. |
37
+ | `useDatePickerContext` | `() => DatePickerContext` | `-` | Reads context and throws outside `DatePicker.Root`. |
38
+ | `DatePickerContext` | `type` | `-` | Shared context contract for all datepicker parts. |
@@ -0,0 +1,43 @@
1
+ import type { DatePickerDateValue, DatePickerEditableSegmentType, DatePickerSegmentPart, DatePickerSegmentType } from './date-utils';
2
+ import type { PopoverChangeReason, PopoverOpenChangeDetails } from '../../popover/root/context';
3
+ export type DatePickerOpenChangeReason = PopoverChangeReason;
4
+ export type DatePickerOpenChangeDetails = PopoverOpenChangeDetails;
5
+ export type DatePickerContext = {
6
+ id: string;
7
+ isDisabled: boolean;
8
+ isReadOnly: boolean;
9
+ open: boolean;
10
+ focusVisible: boolean;
11
+ focusWithin: boolean;
12
+ isInvalidDraft: boolean;
13
+ activeSegment: Exclude<DatePickerSegmentType, 'literal'> | null;
14
+ value: DatePickerDateValue | null;
15
+ locale: string;
16
+ triggerRef: HTMLElement | null;
17
+ setTriggerRef: (element: HTMLElement | null) => void;
18
+ setFocusVisible: (visible: boolean) => void;
19
+ syncFocusWithin: () => void;
20
+ setActiveSegment: (segment: Exclude<DatePickerSegmentType, 'literal'> | null) => void;
21
+ openPopover: (reason?: DatePickerOpenChangeReason, event?: Event) => void;
22
+ closePopover: (reason?: DatePickerOpenChangeReason, event?: Event) => void;
23
+ togglePopover: (reason?: DatePickerOpenChangeReason, event?: Event) => void;
24
+ onOpenChange: (open: boolean, details: DatePickerOpenChangeDetails) => void;
25
+ setValue: (nextValue: DatePickerDateValue, source?: 'calendar' | 'input') => void;
26
+ typeSegmentDigit: (type: Exclude<DatePickerSegmentType, 'literal'>, digit: string) => boolean;
27
+ adjustSegmentValue: (type: Exclude<DatePickerSegmentType, 'literal'>, step: number) => void;
28
+ isDateOutOfRange: (value: DatePickerDateValue) => boolean;
29
+ isDateUnavailable: (value: DatePickerDateValue) => boolean;
30
+ getSegments: () => DatePickerSegmentPart[];
31
+ getSegmentValue: (type: Exclude<DatePickerSegmentType, 'literal'>) => string;
32
+ setSegmentValue: (type: Exclude<DatePickerSegmentType, 'literal'>, nextValue: string) => void;
33
+ getSegmentLabel: (type: DatePickerEditableSegmentType) => string;
34
+ registerSegmentRef: (type: DatePickerEditableSegmentType, element: HTMLElement | null) => void;
35
+ focusNextPlaceholderOrLastSegment: () => boolean;
36
+ focusNextSegment: (type: DatePickerEditableSegmentType) => boolean;
37
+ focusPreviousSegment: (type: DatePickerEditableSegmentType) => boolean;
38
+ focusLastSegment: () => boolean;
39
+ };
40
+ export declare function setDatePickerContext(context: DatePickerContext): void;
41
+ export declare function getDatePickerContext(): DatePickerContext | undefined;
42
+ export declare function useDatePickerContext(): DatePickerContext;
43
+ export type { DatePickerSegmentPart, DatePickerSegmentType };
@@ -0,0 +1,15 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const KEY = Symbol('date-picker');
3
+ export function setDatePickerContext(context) {
4
+ setContext(KEY, context);
5
+ }
6
+ export function getDatePickerContext() {
7
+ return getContext(KEY);
8
+ }
9
+ export function useDatePickerContext() {
10
+ const context = getDatePickerContext();
11
+ if (!context) {
12
+ throw new Error('DatePicker components must be used within DatePicker.Root.');
13
+ }
14
+ return context;
15
+ }
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import DatePicker from '../index';
3
+
4
+ let value = $state<string | null | undefined>(undefined);
5
+ let onChangeCalls = $state(0);
6
+ </script>
7
+
8
+ <DatePicker.Root
9
+ bind:value
10
+ onChange={() => {
11
+ onChangeCalls += 1;
12
+ }}
13
+ >
14
+ <DatePicker.Input class="date-picker-input" aria-label="Date input">
15
+ {#snippet children(segment)}
16
+ <DatePicker.Segment class="date-picker-segment" {segment} />
17
+ {/snippet}
18
+ </DatePicker.Input>
19
+ </DatePicker.Root>
20
+
21
+ <p data-testid="bind-value-state">
22
+ {value === undefined ? 'undefined' : value === null ? 'null' : value}
23
+ </p>
24
+ <p data-testid="on-change-calls">{onChangeCalls}</p>
@@ -0,0 +1,3 @@
1
+ declare const DatePickerBindableEmptyTest: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type DatePickerBindableEmptyTest = ReturnType<typeof DatePickerBindableEmptyTest>;
3
+ export default DatePickerBindableEmptyTest;
@@ -0,0 +1,41 @@
1
+ <script lang="ts">
2
+ import DatePicker from '../index';
3
+
4
+ let value = $state<string | null | undefined>('2026-02-10');
5
+ let open = $state(false);
6
+ </script>
7
+
8
+ <DatePicker.Root bind:value bind:open>
9
+ <DatePicker.Input class="date-picker-input" aria-label="Date input">
10
+ {#snippet children(segment)}
11
+ <DatePicker.Segment class="date-picker-segment" {segment} />
12
+ {/snippet}
13
+ </DatePicker.Input>
14
+ <DatePicker.Trigger class="date-picker-trigger">Open calendar</DatePicker.Trigger>
15
+ <DatePicker.Popover class="date-picker-popover">
16
+ <DatePicker.Calendar class="date-picker-calendar">
17
+ <div class="flex items-center justify-between gap-2 p-2">
18
+ <DatePicker.TriggerPrevious />
19
+ <DatePicker.Heading />
20
+ <DatePicker.TriggerNext />
21
+ </div>
22
+ <DatePicker.Grid>
23
+ <DatePicker.GridHeader>
24
+ {#snippet children(dayLabel: string)}
25
+ <DatePicker.HeaderCell>
26
+ {dayLabel}
27
+ </DatePicker.HeaderCell>
28
+ {/snippet}
29
+ </DatePicker.GridHeader>
30
+ <DatePicker.GridBody>
31
+ {#snippet children(date: string)}
32
+ <DatePicker.BodyCell {date} />
33
+ {/snippet}
34
+ </DatePicker.GridBody>
35
+ </DatePicker.Grid>
36
+ </DatePicker.Calendar>
37
+ </DatePicker.Popover>
38
+ </DatePicker.Root>
39
+
40
+ <p data-testid="bind-value">{value}</p>
41
+ <p data-testid="bind-open">{String(open)}</p>
@@ -0,0 +1,3 @@
1
+ declare const DatePickerBindableTest: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type DatePickerBindableTest = ReturnType<typeof DatePickerBindableTest>;
3
+ export default DatePickerBindableTest;
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ import { LocaleProvider } from '../../locale-provider';
3
+ import DatePicker from '../index';
4
+
5
+ let selectedValue = $state<string | null>('');
6
+ </script>
7
+
8
+ <LocaleProvider locale="en-GB">
9
+ <DatePicker.Root
10
+ onChange={(nextValue) => {
11
+ selectedValue = nextValue;
12
+ }}
13
+ >
14
+ <DatePicker.Input class="date-picker-input" aria-label="Date input">
15
+ {#snippet children(segment)}
16
+ <DatePicker.Segment class="date-picker-segment" {segment} />
17
+ {/snippet}
18
+ </DatePicker.Input>
19
+ <DatePicker.Trigger class="date-picker-trigger">Open calendar</DatePicker.Trigger>
20
+
21
+ <DatePicker.Popover class="date-picker-popover">
22
+ <DatePicker.Calendar class="date-picker-calendar">
23
+ <div class="flex items-center justify-between gap-2 p-2">
24
+ <DatePicker.TriggerPrevious />
25
+ <DatePicker.Heading />
26
+ <DatePicker.TriggerNext />
27
+ </div>
28
+ <DatePicker.Grid>
29
+ <DatePicker.GridHeader>
30
+ {#snippet children(dayLabel: string)}
31
+ <DatePicker.HeaderCell>
32
+ {dayLabel}
33
+ </DatePicker.HeaderCell>
34
+ {/snippet}
35
+ </DatePicker.GridHeader>
36
+ <DatePicker.GridBody>
37
+ {#snippet children(date: string)}
38
+ <DatePicker.BodyCell {date} />
39
+ {/snippet}
40
+ </DatePicker.GridBody>
41
+ </DatePicker.Grid>
42
+ </DatePicker.Calendar>
43
+ </DatePicker.Popover>
44
+ </DatePicker.Root>
45
+ </LocaleProvider>
46
+
47
+ <p data-testid="date-picker-value">{selectedValue}</p>
@@ -0,0 +1,3 @@
1
+ declare const DatePickerEmptyTest: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type DatePickerEmptyTest = ReturnType<typeof DatePickerEmptyTest>;
3
+ export default DatePickerEmptyTest;