material-plus-ui 1.4.0 → 1.6.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 (211) hide show
  1. package/.fix.py +92 -0
  2. package/README.md +1 -1
  3. package/dist/components/accordion/MPAccordion.js +1 -1
  4. package/dist/components/alert/MPAlert.js +1 -1
  5. package/dist/components/animate-lighting/MPAnimateLighting.js +1 -1
  6. package/dist/components/aspect-ratio/MPAspectRatio.js +1 -1
  7. package/dist/components/avatar/MPAvatar.js +1 -1
  8. package/dist/components/avatar-group/MPAvatarGroup.js +1 -1
  9. package/dist/components/badge/MPBadge.js +1 -1
  10. package/dist/components/blockquote/MPBlockquote.js +1 -1
  11. package/dist/components/bottom-navigation/MPBottomNavigation.d.ts +17 -0
  12. package/dist/components/bottom-navigation/MPBottomNavigation.js +1 -1
  13. package/dist/components/breadcrumb/MPBreadcrumb.js +1 -1
  14. package/dist/components/button/MPButton.d.ts +49 -3
  15. package/dist/components/button/MPButton.js +1 -1
  16. package/dist/components/calendar/MPCalendar.d.ts +160 -0
  17. package/dist/components/calendar/MPCalendar.js +2 -0
  18. package/dist/components/calendar/index.d.ts +2 -0
  19. package/dist/components/calendar/index.js +1 -0
  20. package/dist/components/card/MPCard.js +1 -1
  21. package/dist/components/carousel/MPCarousel.js +1 -1
  22. package/dist/components/chat-bubble/MPChatBubble.js +1 -1
  23. package/dist/components/checkbox/MPCheckbox.d.ts +6 -0
  24. package/dist/components/checkbox/MPCheckbox.js +1 -1
  25. package/dist/components/chip/MPChip.d.ts +21 -6
  26. package/dist/components/chip/MPChip.js +1 -1
  27. package/dist/components/collapsible/MPCollapsible.js +1 -1
  28. package/dist/components/color-picker/MPColorPicker.js +1 -1
  29. package/dist/components/combobox/MPCombobox.d.ts +52 -3
  30. package/dist/components/combobox/MPCombobox.js +1 -1
  31. package/dist/components/command-palette/MPCommandPalette.d.ts +1 -1
  32. package/dist/components/command-palette/MPCommandPalette.js +1 -1
  33. package/dist/components/config/MPConfigProvider.d.ts +124 -0
  34. package/dist/components/config/MPConfigProvider.js +2 -0
  35. package/dist/components/config/index.d.ts +2 -0
  36. package/dist/components/config/index.js +1 -0
  37. package/dist/components/confirm/MPConfirmProvider.d.ts +143 -0
  38. package/dist/components/confirm/MPConfirmProvider.js +2 -0
  39. package/dist/components/confirm/index.d.ts +2 -0
  40. package/dist/components/confirm/index.js +1 -0
  41. package/dist/components/container/MPContainer.js +1 -1
  42. package/dist/components/date-picker/MPDatePicker.d.ts +53 -2
  43. package/dist/components/date-picker/MPDatePicker.js +1 -1
  44. package/dist/components/date-picker/index.d.ts +1 -1
  45. package/dist/components/date-range-picker/MPDateRangePicker.js +1 -1
  46. package/dist/components/date-time-picker/MPDateTimePicker.js +1 -1
  47. package/dist/components/dialog/MPDialog.d.ts +16 -3
  48. package/dist/components/dialog/MPDialog.js +1 -1
  49. package/dist/components/divider/MPDivider.js +1 -1
  50. package/dist/components/drawer/MPDrawer.d.ts +1 -1
  51. package/dist/components/drawer/MPDrawer.js +1 -1
  52. package/dist/components/empty/MPEmpty.js +1 -1
  53. package/dist/components/file-picker/MPFilePicker.d.ts +6 -0
  54. package/dist/components/file-picker/MPFilePicker.js +1 -1
  55. package/dist/components/floating-action-button/MPFloatingActionButton.js +1 -1
  56. package/dist/components/footer/MPFooter.js +1 -1
  57. package/dist/components/grid/MPGrid.d.ts +23 -1
  58. package/dist/components/grid/MPGrid.js +1 -1
  59. package/dist/components/header/MPHeader.js +1 -1
  60. package/dist/components/image/MPImage.d.ts +112 -0
  61. package/dist/components/image/MPImage.js +2 -0
  62. package/dist/components/image/index.d.ts +2 -0
  63. package/dist/components/image/index.js +1 -0
  64. package/dist/components/list/MPList.d.ts +28 -0
  65. package/dist/components/list/MPList.js +1 -1
  66. package/dist/components/menu/MPMenu.d.ts +25 -4
  67. package/dist/components/menu/MPMenu.js +1 -1
  68. package/dist/components/menubar/MPMenubar.d.ts +8 -1
  69. package/dist/components/menubar/MPMenubar.js +1 -1
  70. package/dist/components/navigation-menu/MPNavigationMenu.d.ts +8 -1
  71. package/dist/components/navigation-menu/MPNavigationMenu.js +1 -1
  72. package/dist/components/number-field/MPNumberField.d.ts +9 -3
  73. package/dist/components/number-field/MPNumberField.js +1 -1
  74. package/dist/components/otp-field/MPOtpField.js +1 -1
  75. package/dist/components/overlay/MPOverlay.d.ts +1 -1
  76. package/dist/components/overlay/MPOverlay.js +1 -1
  77. package/dist/components/pagination/MPPagination.js +1 -1
  78. package/dist/components/panes/MPPanes.js +1 -1
  79. package/dist/components/pill/MPPill.js +1 -1
  80. package/dist/components/popconfirm/MPPopconfirm.d.ts +92 -0
  81. package/dist/components/popconfirm/MPPopconfirm.js +2 -0
  82. package/dist/components/popconfirm/index.d.ts +2 -0
  83. package/dist/components/popconfirm/index.js +1 -0
  84. package/dist/components/popover/MPPopover.d.ts +1 -1
  85. package/dist/components/popover/MPPopover.js +1 -1
  86. package/dist/components/progress-box/MPProgressBox.js +1 -1
  87. package/dist/components/progress-circular/MPProgressCircular.js +1 -1
  88. package/dist/components/progress-linear/MPProgressLinear.js +1 -1
  89. package/dist/components/radio-group/MPRadioGroup.d.ts +12 -0
  90. package/dist/components/radio-group/MPRadioGroup.js +1 -1
  91. package/dist/components/rating/MPRating.js +1 -1
  92. package/dist/components/segmented-button/MPSegmentedButton.d.ts +7 -0
  93. package/dist/components/segmented-button/MPSegmentedButton.js +1 -1
  94. package/dist/components/select/MPSelect.d.ts +9 -2
  95. package/dist/components/select/MPSelect.js +1 -1
  96. package/dist/components/shortcut/MPShortcut.js +1 -1
  97. package/dist/components/sidebar/MPSidebar.js +1 -1
  98. package/dist/components/skeleton/MPSkeleton.js +1 -1
  99. package/dist/components/slider/MPSlider.d.ts +33 -0
  100. package/dist/components/slider/MPSlider.js +1 -1
  101. package/dist/components/snackbar/MPSnackbar.d.ts +20 -1
  102. package/dist/components/snackbar/MPSnackbar.js +1 -1
  103. package/dist/components/spoiler/MPSpoiler.js +1 -1
  104. package/dist/components/stepper/MPStepper.d.ts +153 -0
  105. package/dist/components/stepper/MPStepper.js +2 -0
  106. package/dist/components/stepper/index.d.ts +2 -0
  107. package/dist/components/stepper/index.js +1 -0
  108. package/dist/components/switch/MPSwitch.d.ts +6 -0
  109. package/dist/components/switch/MPSwitch.js +1 -1
  110. package/dist/components/table/MPTable.d.ts +1 -1
  111. package/dist/components/table/MPTable.js +1 -1
  112. package/dist/components/tabs/MPTabs.js +1 -1
  113. package/dist/components/text-field/MPTextField.d.ts +46 -14
  114. package/dist/components/text-field/MPTextField.js +1 -1
  115. package/dist/components/time-picker/MPTimePicker.js +1 -1
  116. package/dist/components/timeline/MPTimeline.d.ts +10 -2
  117. package/dist/components/timeline/MPTimeline.js +1 -1
  118. package/dist/components/toggle/MPToggle.js +1 -1
  119. package/dist/components/transfer/MPTransfer.js +1 -1
  120. package/dist/components/typography/MPTypography.d.ts +7 -0
  121. package/dist/components/typography/MPTypography.js +1 -2
  122. package/dist/components/visually-hidden/MPVisuallyHidden.d.ts +60 -0
  123. package/dist/components/visually-hidden/MPVisuallyHidden.js +2 -0
  124. package/dist/components/visually-hidden/index.d.ts +2 -0
  125. package/dist/components/visually-hidden/index.js +1 -0
  126. package/dist/constants/glyphs.d.ts +2 -0
  127. package/dist/constants/glyphs.js +1 -1
  128. package/dist/constants/icons.d.ts +1 -0
  129. package/dist/constants/icons.js +1 -1
  130. package/dist/hooks/index.d.ts +23 -0
  131. package/dist/hooks/index.js +1 -0
  132. package/dist/hooks/useMPColorScheme.d.ts +135 -0
  133. package/dist/hooks/useMPColorScheme.js +1 -0
  134. package/dist/hooks/useMPReducedMotion.d.ts +32 -0
  135. package/dist/hooks/useMPReducedMotion.js +1 -0
  136. package/dist/hooks/useMPShortcut.d.ts +105 -0
  137. package/dist/hooks/useMPShortcut.js +2 -0
  138. package/dist/hooks/useMPWindowClass.d.ts +48 -0
  139. package/dist/hooks/useMPWindowClass.js +1 -0
  140. package/dist/index.d.ts +8 -0
  141. package/dist/index.js +1 -1
  142. package/dist/internal/Calendar.d.ts +19 -4
  143. package/dist/internal/Calendar.js +1 -1
  144. package/dist/internal/Picker.d.ts +15 -3
  145. package/dist/internal/Picker.js +1 -1
  146. package/dist/internal/color-scheme.d.ts +28 -0
  147. package/dist/internal/color-scheme.js +2 -0
  148. package/dist/internal/config.d.ts +43 -0
  149. package/dist/internal/config.js +2 -0
  150. package/dist/internal/date.d.ts +50 -3
  151. package/dist/internal/date.js +1 -1
  152. package/dist/internal/i18n.d.ts +26 -1
  153. package/dist/internal/messages/confirm.d.ts +3 -0
  154. package/dist/internal/messages/confirm.js +1 -0
  155. package/dist/internal/messages/picker.js +1 -1
  156. package/dist/internal/progress.d.ts +14 -0
  157. package/dist/internal/step.d.ts +71 -0
  158. package/dist/internal/step.js +1 -0
  159. package/dist/internal/window-class.d.ts +21 -0
  160. package/dist/internal/window-class.js +2 -0
  161. package/dist/locales/ar.js +1 -1
  162. package/dist/locales/de.js +1 -1
  163. package/dist/locales/es.js +1 -1
  164. package/dist/locales/fr.js +1 -1
  165. package/dist/locales/hi.js +1 -1
  166. package/dist/locales/id.js +1 -1
  167. package/dist/locales/it.js +1 -1
  168. package/dist/locales/ja.js +1 -1
  169. package/dist/locales/ko.js +1 -1
  170. package/dist/locales/nl.js +1 -1
  171. package/dist/locales/pl.js +1 -1
  172. package/dist/locales/pt.js +1 -1
  173. package/dist/locales/ru.js +1 -1
  174. package/dist/locales/th.js +1 -1
  175. package/dist/locales/tr.js +1 -1
  176. package/dist/locales/vi.js +1 -1
  177. package/dist/locales/zh-hans.js +1 -1
  178. package/dist/locales/zh-hant.js +1 -1
  179. package/dist/styles/accordion.css +1 -1
  180. package/dist/styles/animate-lighting.css +1 -1
  181. package/dist/styles/aspect-ratio.css +1 -1
  182. package/dist/styles/bottom-navigation.css +1 -1
  183. package/dist/styles/calendar.css +2 -0
  184. package/dist/styles/chip.css +1 -1
  185. package/dist/styles/combobox.css +1 -1
  186. package/dist/styles/config.css +2 -0
  187. package/dist/styles/confirm.css +2 -0
  188. package/dist/styles/grid.css +1 -1
  189. package/dist/styles/highlight.css +1 -1
  190. package/dist/styles/image.css +2 -0
  191. package/dist/styles/list.css +1 -1
  192. package/dist/styles/panes.css +1 -1
  193. package/dist/styles/popconfirm.css +2 -0
  194. package/dist/styles/progress-box.css +1 -1
  195. package/dist/styles/progress-circular.css +1 -1
  196. package/dist/styles/progress-linear.css +1 -1
  197. package/dist/styles/rating.css +1 -1
  198. package/dist/styles/shortcut.css +1 -1
  199. package/dist/styles/slider.css +1 -1
  200. package/dist/styles/snackbar.css +1 -1
  201. package/dist/styles/stepper.css +2 -0
  202. package/dist/styles/text-field.css +1 -1
  203. package/dist/styles/timeline.css +1 -1
  204. package/dist/styles/tokens.css +1 -1
  205. package/dist/styles/transfer.css +1 -1
  206. package/dist/styles/typography.css +1 -1
  207. package/dist/styles/visually-hidden.css +2 -0
  208. package/dist/styles.css +1 -1
  209. package/dist/tailwind.css +91 -5
  210. package/dist/types.d.ts +64 -0
  211. package/package.json +6 -1
@@ -0,0 +1,105 @@
1
+ import { type MPResolvedOS } from '../internal/keys.js';
2
+ /** The three platforms a shortcut is spelled for. */
3
+ export type { MPResolvedOS };
4
+ /** Where the keystroke is listened for, and what happens to it. */
5
+ export interface MPShortcutOptions {
6
+ /**
7
+ * Turns the binding off without unmounting whatever holds it. A shortcut
8
+ * behind a feature flag, or one that belongs to a panel that is closed.
9
+ * @default true
10
+ */
11
+ enabled?: boolean;
12
+ /**
13
+ * Calls `preventDefault()` on the matching keystroke.
14
+ *
15
+ * On by default, and it is the honest default: some browsers put their own
16
+ * search bar on `Mod+K`, and a page binding that combination has said the key
17
+ * is theirs. Switch it off for a shortcut that means to run *alongside* the
18
+ * browser's, which is rare enough to be worth writing down.
19
+ * @default true
20
+ */
21
+ preventDefault?: boolean;
22
+ /**
23
+ * Ignores the keystroke while the focus is in a text input, a textarea or
24
+ * anything `contenteditable`.
25
+ *
26
+ * Off by default, because the shortcut most pages bind has a modifier and
27
+ * `Mod+K` typed into a search field still means "open the palette". Switch it
28
+ * on for a **bare** key — `/` to focus search, `?` for help — which would
29
+ * otherwise be swallowed out of the middle of somebody's sentence.
30
+ * @default false
31
+ */
32
+ ignoreInputs?: boolean;
33
+ /**
34
+ * What the listener is attached to.
35
+ * @default the window
36
+ */
37
+ target?: EventTarget | null;
38
+ }
39
+ /**
40
+ * Runs something when a keystroke arrives, spelled the way this library spells
41
+ * shortcuts everywhere else.
42
+ *
43
+ * `MPShortcut` **writes** a shortcut down, `MPCommandPalette` **reads** one off
44
+ * a real keyboard, and both have always gone through one matcher so that a label
45
+ * on the screen and the binding under it cannot disagree — see `internal/keys.ts`
46
+ * for the day they did. This is that matcher, for the shortcuts an application
47
+ * binds itself.
48
+ *
49
+ * ```tsx
50
+ * useMPShortcut('Mod+K', () => setOpen(true));
51
+ * useMPShortcut('/', focusSearch, { ignoreInputs: true });
52
+ * ```
53
+ *
54
+ * ## `Mod` is the whole point
55
+ *
56
+ * It resolves to Command on a Mac and Control everywhere else, which is what
57
+ * lets one string be both the binding and the label:
58
+ *
59
+ * ```tsx
60
+ * <MPShortcut keys="Mod+K" />;
61
+ * useMPShortcut('Mod+K', open);
62
+ * ```
63
+ *
64
+ * Two lines, one spelling, and no way for the page to draw `⌘K` while listening
65
+ * for `Ctrl+K`.
66
+ *
67
+ * Modifiers are matched in **both** directions: `Mod+K` does not fire when Shift
68
+ * is also held, because that combination may belong to something else. A
69
+ * shortcut that ignored extra modifiers would be quietly taking keystrokes it
70
+ * was not given.
71
+ *
72
+ * ## The handler is not a dependency
73
+ *
74
+ * It is kept in a ref and read at the moment the key arrives, so an inline arrow
75
+ * function is fine and does not rebind the listener on every render. What *does*
76
+ * rebind is the shortcut itself, `enabled`, and `target` — the things that change
77
+ * what is being listened for.
78
+ *
79
+ * ## Sharp edges
80
+ *
81
+ * - **It listens on the window**, so it fires wherever the focus is unless
82
+ * `ignoreInputs` says otherwise. That is what a page-wide shortcut wants and
83
+ * not what a shortcut belonging to one panel wants — pass that panel's element
84
+ * as `target`.
85
+ * - **It does not stop propagation.** A page with two hooks bound to one
86
+ * combination runs both, which is a collision the page has to resolve rather
87
+ * than something the hook can guess at.
88
+ * - **The platform is detected once.** It cannot change under a running page.
89
+ */
90
+ export declare function useMPShortcut(keys: string | string[], handler: (event: KeyboardEvent) => void, options?: MPShortcutOptions): void;
91
+ /**
92
+ * Which keyboard the reader is on — `'mac'`, `'windows'` or `'linux'`.
93
+ *
94
+ * The same detection `MPShortcut` prints its key caps from, exported so an
95
+ * application writing a key cap of its own cannot end up on a different answer
96
+ * from the component beside it. Three sources are matched at once —
97
+ * `userAgentData.platform`, `navigator.platform` and the user agent string —
98
+ * because the question is coarse and browsers freeze or lie about each of them
99
+ * separately.
100
+ *
101
+ * `'windows'` on a server, and corrected on hydration through
102
+ * `useSyncExternalStore` — which is the one API that tells React the two renders
103
+ * are *meant* to differ, and is exactly the sequence a Mac reader sees.
104
+ */
105
+ export declare function useMPPlatform(): MPResolvedOS;
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import*as e from"react";import{matchesShortcut as t,useDetectedOS as n}from"../internal/keys.js";const r=/^(input|textarea|select)$/i;export function useMPShortcut(o,i,s={}){const{enabled:u=!0,preventDefault:a=!0,ignoreInputs:c=!1,target:f}=s,d=n(),l=e.useRef(i);l.current=i;const p=Array.isArray(o)?o.join("+"):o;e.useEffect(()=>{if(!u)return;const e=void 0===f?"undefined"==typeof window?null:window:f;if(!e)return;const n=e=>{const n=e;c&&function(e){return e instanceof HTMLElement&&(r.test(e.tagName)||e.isContentEditable)}(n.target)||t(n,p,d)&&(a&&n.preventDefault(),l.current(n))};return e.addEventListener("keydown",n),()=>e.removeEventListener("keydown",n)},[p,d,u,a,c,f])}export function useMPPlatform(){return n()}
@@ -0,0 +1,48 @@
1
+ import type { MPWindowClass } from '../types.js';
2
+ /**
3
+ * Which of Material's five window size classes the window is in.
4
+ *
5
+ * The library has always had this axis — `MPGrid` reflows along it, `MPResponsive`
6
+ * is written in terms of it, `MPSidebar` collapses at it — and a consumer could
7
+ * name the classes in a prop without ever being able to *ask* which one they
8
+ * were in. So a page that wanted one more decision than a prop covers had to
9
+ * write the four breakpoints out again, in numbers that had to match the
10
+ * library's or the layout would disagree with itself at one width.
11
+ *
12
+ * ```tsx
13
+ * const size = useMPWindowClass();
14
+ *
15
+ * return size === 'compact' ? <MPDrawer>{nav}</MPDrawer> : <MPSidebar>{nav}</MPSidebar>;
16
+ * ```
17
+ *
18
+ * ## It reads the media queries, not the width
19
+ *
20
+ * Which is what keeps it agreeing with the stylesheet. `innerWidth` counts a
21
+ * classic scrollbar and a media query does not, so a 615px window with a 15px
22
+ * scrollbar is `medium` to CSS and `compact` to arithmetic — a layout whose
23
+ * JavaScript and whose CSS part company at exactly one width, which is the
24
+ * hardest kind of bug to be shown.
25
+ *
26
+ * It also subscribes to the four boundaries rather than to `resize`. A window
27
+ * dragged from 500 to 1900 wakes this four times; a `resize` listener wakes
28
+ * several hundred, for the same four answers.
29
+ *
30
+ * ## On a server
31
+ *
32
+ * There is no window, so there is no true answer — and this returns `onServer`,
33
+ * which is `'expanded'` unless you say otherwise. That is a **guess**, and the
34
+ * argument is there because an application usually knows better than the library
35
+ * does: a marketing site's first paint is mostly phones and `'compact'` is the
36
+ * closer bet, an internal dashboard's is not.
37
+ *
38
+ * The client corrects it on hydration. `useSyncExternalStore` is what makes that
39
+ * correction legitimate rather than a mismatch React warns about — but the
40
+ * correction is a second render, so a component that swaps a whole navigation
41
+ * pattern on this will do so visibly on a first load. Where that matters, the
42
+ * CSS answer is the one that has no first render to be wrong: `MPGrid`'s
43
+ * responsive props and Tailwind's own variants are resolved by the browser
44
+ * before anything paints.
45
+ *
46
+ * @param onServer what to answer where there is no window. @default 'expanded'
47
+ */
48
+ export declare function useMPWindowClass(onServer?: MPWindowClass): MPWindowClass;
@@ -0,0 +1 @@
1
+ import{useWindowClass as n}from"../internal/window-class.js";export function useMPWindowClass(e="expanded"){return n(e)}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './types.js';
2
2
  export { registerMPMessages, type MPLocale, type MPMessages, type MPPartialMessages } from './internal/i18n.js';
3
3
  export * from './constants/icons.js';
4
+ export * from './hooks/index.js';
4
5
  export * from './components/accordion/index.js';
5
6
  export * from './components/alert/index.js';
6
7
  export * from './components/animate-appear/index.js';
@@ -24,12 +25,15 @@ export * from './components/box/index.js';
24
25
  export * from './components/breadcrumb/index.js';
25
26
  export * from './components/button/index.js';
26
27
  export * from './components/button-group/index.js';
28
+ export * from './components/calendar/index.js';
27
29
  export * from './components/card/index.js';
28
30
  export * from './components/carousel/index.js';
29
31
  export * from './components/chat-bubble/index.js';
30
32
  export * from './components/checkbox/index.js';
31
33
  export * from './components/chip/index.js';
32
34
  export * from './components/collapsible/index.js';
35
+ export * from './components/config/index.js';
36
+ export * from './components/confirm/index.js';
33
37
  export * from './components/color-picker/index.js';
34
38
  export * from './components/combobox/index.js';
35
39
  export * from './components/command-palette/index.js';
@@ -51,6 +55,7 @@ export * from './components/header/index.js';
51
55
  export * from './components/highlight/index.js';
52
56
  export * from './components/icon/index.js';
53
57
  export * from './components/icon-button/index.js';
58
+ export * from './components/image/index.js';
54
59
  export * from './components/list/index.js';
55
60
  export * from './components/locale/index.js';
56
61
  export * from './components/menu/index.js';
@@ -63,6 +68,7 @@ export * from './components/page-layout/index.js';
63
68
  export * from './components/pagination/index.js';
64
69
  export * from './components/panes/index.js';
65
70
  export * from './components/pill/index.js';
71
+ export * from './components/popconfirm/index.js';
66
72
  export * from './components/popover/index.js';
67
73
  export * from './components/progress-box/index.js';
68
74
  export * from './components/progress-circular/index.js';
@@ -77,6 +83,7 @@ export * from './components/skeleton/index.js';
77
83
  export * from './components/slider/index.js';
78
84
  export * from './components/snackbar/index.js';
79
85
  export * from './components/spoiler/index.js';
86
+ export * from './components/stepper/index.js';
80
87
  export * from './components/switch/index.js';
81
88
  export * from './components/table/index.js';
82
89
  export * from './components/tabs/index.js';
@@ -89,3 +96,4 @@ export * from './components/toggle-group/index.js';
89
96
  export * from './components/tooltip/index.js';
90
97
  export * from './components/transfer/index.js';
91
98
  export * from './components/typography/index.js';
99
+ export * from './components/visually-hidden/index.js';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./types.js";export{registerMPMessages}from"./internal/i18n.js";export*from"./constants/icons.js";export*from"./components/accordion/index.js";export*from"./components/alert/index.js";export*from"./components/animate-appear/index.js";export*from"./components/animate-blink/index.js";export*from"./components/animate-fade/index.js";export*from"./components/animate-grow/index.js";export*from"./components/animate-headline/index.js";export*from"./components/animate-lighting/index.js";export*from"./components/animate-marquee/index.js";export*from"./components/animate-rotate/index.js";export*from"./components/animate-slide/index.js";export*from"./components/animate-typing/index.js";export*from"./components/animate-zoom/index.js";export*from"./components/aspect-ratio/index.js";export*from"./components/avatar/index.js";export*from"./components/avatar-group/index.js";export*from"./components/badge/index.js";export*from"./components/blockquote/index.js";export*from"./components/bottom-navigation/index.js";export*from"./components/box/index.js";export*from"./components/breadcrumb/index.js";export*from"./components/button/index.js";export*from"./components/button-group/index.js";export*from"./components/card/index.js";export*from"./components/carousel/index.js";export*from"./components/chat-bubble/index.js";export*from"./components/checkbox/index.js";export*from"./components/chip/index.js";export*from"./components/collapsible/index.js";export*from"./components/color-picker/index.js";export*from"./components/combobox/index.js";export*from"./components/command-palette/index.js";export*from"./components/container/index.js";export*from"./components/date-picker/index.js";export*from"./components/date-range-picker/index.js";export*from"./components/date-time-picker/index.js";export*from"./components/dialog/index.js";export*from"./components/divider/index.js";export*from"./components/drawer/index.js";export*from"./components/empty/index.js";export*from"./components/fieldset/index.js";export*from"./components/file-picker/index.js";export*from"./components/floating-action-button/index.js";export*from"./components/footer/index.js";export*from"./components/form/index.js";export*from"./components/grid/index.js";export*from"./components/header/index.js";export*from"./components/highlight/index.js";export*from"./components/icon/index.js";export*from"./components/icon-button/index.js";export*from"./components/list/index.js";export*from"./components/locale/index.js";export*from"./components/menu/index.js";export*from"./components/menubar/index.js";export*from"./components/navigation-menu/index.js";export*from"./components/number-field/index.js";export*from"./components/otp-field/index.js";export*from"./components/overlay/index.js";export*from"./components/page-layout/index.js";export*from"./components/pagination/index.js";export*from"./components/panes/index.js";export*from"./components/pill/index.js";export*from"./components/popover/index.js";export*from"./components/progress-box/index.js";export*from"./components/progress-circular/index.js";export*from"./components/progress-linear/index.js";export*from"./components/radio-group/index.js";export*from"./components/rating/index.js";export*from"./components/segmented-button/index.js";export*from"./components/select/index.js";export*from"./components/shortcut/index.js";export*from"./components/sidebar/index.js";export*from"./components/skeleton/index.js";export*from"./components/slider/index.js";export*from"./components/snackbar/index.js";export*from"./components/spoiler/index.js";export*from"./components/switch/index.js";export*from"./components/table/index.js";export*from"./components/tabs/index.js";export*from"./components/text-field/index.js";export*from"./components/text-link/index.js";export*from"./components/time-picker/index.js";export*from"./components/timeline/index.js";export*from"./components/toggle/index.js";export*from"./components/toggle-group/index.js";export*from"./components/tooltip/index.js";export*from"./components/transfer/index.js";export*from"./components/typography/index.js";
1
+ export*from"./types.js";export{registerMPMessages}from"./internal/i18n.js";export*from"./constants/icons.js";export*from"./hooks/index.js";export*from"./components/accordion/index.js";export*from"./components/alert/index.js";export*from"./components/animate-appear/index.js";export*from"./components/animate-blink/index.js";export*from"./components/animate-fade/index.js";export*from"./components/animate-grow/index.js";export*from"./components/animate-headline/index.js";export*from"./components/animate-lighting/index.js";export*from"./components/animate-marquee/index.js";export*from"./components/animate-rotate/index.js";export*from"./components/animate-slide/index.js";export*from"./components/animate-typing/index.js";export*from"./components/animate-zoom/index.js";export*from"./components/aspect-ratio/index.js";export*from"./components/avatar/index.js";export*from"./components/avatar-group/index.js";export*from"./components/badge/index.js";export*from"./components/blockquote/index.js";export*from"./components/bottom-navigation/index.js";export*from"./components/box/index.js";export*from"./components/breadcrumb/index.js";export*from"./components/button/index.js";export*from"./components/button-group/index.js";export*from"./components/calendar/index.js";export*from"./components/card/index.js";export*from"./components/carousel/index.js";export*from"./components/chat-bubble/index.js";export*from"./components/checkbox/index.js";export*from"./components/chip/index.js";export*from"./components/collapsible/index.js";export*from"./components/config/index.js";export*from"./components/confirm/index.js";export*from"./components/color-picker/index.js";export*from"./components/combobox/index.js";export*from"./components/command-palette/index.js";export*from"./components/container/index.js";export*from"./components/date-picker/index.js";export*from"./components/date-range-picker/index.js";export*from"./components/date-time-picker/index.js";export*from"./components/dialog/index.js";export*from"./components/divider/index.js";export*from"./components/drawer/index.js";export*from"./components/empty/index.js";export*from"./components/fieldset/index.js";export*from"./components/file-picker/index.js";export*from"./components/floating-action-button/index.js";export*from"./components/footer/index.js";export*from"./components/form/index.js";export*from"./components/grid/index.js";export*from"./components/header/index.js";export*from"./components/highlight/index.js";export*from"./components/icon/index.js";export*from"./components/icon-button/index.js";export*from"./components/image/index.js";export*from"./components/list/index.js";export*from"./components/locale/index.js";export*from"./components/menu/index.js";export*from"./components/menubar/index.js";export*from"./components/navigation-menu/index.js";export*from"./components/number-field/index.js";export*from"./components/otp-field/index.js";export*from"./components/overlay/index.js";export*from"./components/page-layout/index.js";export*from"./components/pagination/index.js";export*from"./components/panes/index.js";export*from"./components/pill/index.js";export*from"./components/popconfirm/index.js";export*from"./components/popover/index.js";export*from"./components/progress-box/index.js";export*from"./components/progress-circular/index.js";export*from"./components/progress-linear/index.js";export*from"./components/radio-group/index.js";export*from"./components/rating/index.js";export*from"./components/segmented-button/index.js";export*from"./components/select/index.js";export*from"./components/shortcut/index.js";export*from"./components/sidebar/index.js";export*from"./components/skeleton/index.js";export*from"./components/slider/index.js";export*from"./components/snackbar/index.js";export*from"./components/spoiler/index.js";export*from"./components/stepper/index.js";export*from"./components/switch/index.js";export*from"./components/table/index.js";export*from"./components/tabs/index.js";export*from"./components/text-field/index.js";export*from"./components/text-link/index.js";export*from"./components/time-picker/index.js";export*from"./components/timeline/index.js";export*from"./components/toggle/index.js";export*from"./components/toggle-group/index.js";export*from"./components/tooltip/index.js";export*from"./components/transfer/index.js";export*from"./components/typography/index.js";export*from"./components/visually-hidden/index.js";
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { type MPTimeUnit } from './date.js';
2
+ import { type MPCalendarView, type MPTimeUnit } from './date.js';
3
3
  import type { MPMessages } from './i18n.js';
4
4
  import type { MPColor, MPSize, MPWeekday } from '../types.js';
5
5
  /**
@@ -10,7 +10,15 @@ import type { MPColor, MPSize, MPWeekday } from '../types.js';
10
10
  * calendars, so three components need this and none of them should have to
11
11
  * import another. The two things it reaches *up* for are `MPButton` and
12
12
  * `MPIconButton` — the header's steppers are buttons, they are not a new kind of
13
- * control. Nothing here is exported from `src/index.ts`.
13
+ * control.
14
+ *
15
+ * Nothing here is exported from `src/index.ts` under its own name. `Calendar` is
16
+ * reachable from outside through `MPCalendar`, which is a wrapper rather than a
17
+ * re-export: everything below is fully controlled and takes its `labels` already
18
+ * resolved, because four callers had already decided those things. A consumer
19
+ * has not, so the public component is where the state and the translation are
20
+ * put back. That is also why the name went the other way round — the `MP` prefix
21
+ * belongs to what a consumer can import.
14
22
  *
15
23
  * The day cells are deliberately *not* buttons in that sense. A cell has states
16
24
  * a button has no vocabulary for — inside a range, at the end of a range, today,
@@ -19,7 +27,7 @@ import type { MPColor, MPSize, MPWeekday } from '../types.js';
19
27
  */
20
28
  /** The strings a picker says that `Intl` has no opinion about. */
21
29
  export type MPPickerLabels = MPMessages['picker'];
22
- export interface MPCalendarProps {
30
+ export interface CalendarProps {
23
31
  size: MPSize;
24
32
  color: MPColor;
25
33
  locale?: string;
@@ -54,6 +62,13 @@ export interface MPCalendarProps {
54
62
  autoFocus?: boolean;
55
63
  showPreviousButton?: boolean;
56
64
  showNextButton?: boolean;
65
+ /**
66
+ * The finest view the calendar offers, and therefore what a press answers
67
+ * with. `'month'` never draws a day grid and `'year'` never draws either of
68
+ * the other two.
69
+ * @default 'day'
70
+ */
71
+ precision?: MPCalendarView;
57
72
  labels: MPPickerLabels;
58
73
  }
59
74
  /**
@@ -71,7 +86,7 @@ export interface MPCalendarProps {
71
86
  * grid instead of walking forty-two cells — the pattern the ARIA date-picker
72
87
  * practice describes, and the reason none of the cells is a `disabled` button.
73
88
  */
74
- export declare function MPCalendar({ size, color, locale, weekStartsOn, month, onMonthChange, selected, rangeStart, rangeEnd, onSelect, onPreviewChange, minDate, maxDate, shouldDisableDate, showOutsideDays, autoFocus, showPreviousButton, showNextButton, labels }: MPCalendarProps): React.JSX.Element;
89
+ export declare function Calendar({ size, color, locale, weekStartsOn, month, onMonthChange, selected, rangeStart, rangeEnd, onSelect, onPreviewChange, minDate, maxDate, shouldDisableDate, showOutsideDays, autoFocus, showPreviousButton, showNextButton, precision, labels }: CalendarProps): React.JSX.Element;
75
90
  export interface MPTimeGridProps {
76
91
  size: MPSize;
77
92
  locale?: string;
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import*as o from"react";import{MPButton as r}from"../components/button/MPButton.js";import{MPIcon as l}from"../components/icon/MPIcon.js";import{MPIconButton as a}from"../components/icon-button/MPIconButton.js";import{ChevronDownIcon as s,ChevronLeftIcon as c,ChevronRightIcon as i}from"../constants/icons.js";import{MPStateLayer as u}from"./StateLayer.js";import{CONTROL_ICON as m,META_TEXT as d,PROSE_TEXT as h}from"./scale.js";import{VISUALLY_HIDDEN as f}from"./visually-hidden.js";import{addDays as p,addMonths as g,addYears as v,calendarWeeks as y,compareDay as w,dateFormatter as x,daysInMonth as b,isDayOutside as D,isMonthBeforeYear as S,isSameDay as M,isSameMonth as N,isValidDate as P,makeDate as _,meridiemLabels as C,monthLabels as k,startOfDay as j,startOfMonth as z,today as F,weekdayLabels as A,withTime as E,YEAR_PAGE_SIZE as T,yearPageStart as Y}from"./date.js";const B={xs:"1.75rem",sm:"2rem",md:"2.5rem",lg:"2.75rem",xl:"3rem"},R={xs:"xs",sm:"xs",md:"sm",lg:"sm",xl:"md"},H=/*@__PURE__*/["group relative flex cursor-pointer items-center justify-center overflow-hidden","box-border appearance-none bg-transparent font-[inherit] tabular-nums select-none","transition-[background-color,border-color,color]","duration-(--mp-sys-motion-duration-short4)","outline-mp-secondary focus-visible:z-10 focus-visible:outline-2","focus-visible:outline-offset-[-2px] focus-visible:outline-solid outline-none"].join(" ");function $({children:n,label:o,selected:r,inRange:l=!1,rangeEdge:a=null,current:s=!1,muted:c=!1,disabled:i=!1,focused:m=!1,className:d,onClick:h,onPointerEnter:f,onKeyDown:p}){return t("button",{type:"button",role:"gridcell","aria-label":o,"aria-selected":r,"aria-current":s?"date":void 0,"aria-disabled":i||void 0,tabIndex:m?0:-1,"data-focus-target":m?"true":void 0,className:[H,"start"===a?"rounded-s-mp-full":"end"===a?"rounded-e-mp-full":"middle"===a?"rounded-none":"rounded-mp-full",i?"cursor-default text-mp-on-surface/38":r?"bg-(--_mp-accent) text-(--_mp-on-accent)":l?"bg-(--_mp-accent-container) text-(--_mp-on-accent-container)":s?"border border-(--_mp-accent) text-(--_mp-accent)":c?"text-mp-on-surface-variant":"text-mp-on-surface",d??""].filter(Boolean).join(" "),onClick:()=>{i||h()},onPointerEnter:f,onKeyDown:p,children:[i?null:e(u,{}),n]})}function K({size:o,color:u,view:d,month:f,locale:p,labels:g,showPreviousButton:v,showNextButton:y,onStep:w,onViewChange:x}){const b=k(p,"long")[f.getMonth()],D=String(f.getFullYear()),M=S(p),N=R[o],P="day"===d?[g.previousMonth,g.nextMonth]:"month"===d?[g.previousYear,g.nextYear]:[g.previousYears,g.nextYears],_=(t,n)=>n?e(a,{size:N,color:u,label:P[-1===t?0:1],icon:e(l,{icon:-1===t?c:i,size:m[N],className:"rtl:rotate-180"}),onClick:()=>w(t)}):e("span",{"aria-hidden":"true",className:"size-(--_mp-cell)"}),C=t=>e(l,{icon:s,size:m[N],className:["transition-transform duration-(--mp-sys-motion-duration-short4)",t?"rotate-180":""].filter(Boolean).join(" ")}),j=e(r,{variant:"text",size:N,color:u,"aria-label":g.chooseMonth,"aria-expanded":"month"===d,endIcon:C("month"===d),onClick:()=>x("month"===d?"day":"month"),children:b},"month"),z=e(r,{variant:"text",size:N,color:u,className:"tabular-nums","aria-label":g.chooseYear,"aria-expanded":"year"===d,endIcon:C("year"===d),onClick:()=>x("year"===d?"day":"year"),children:D},"year"),F=Y(f.getFullYear());return t("div",{className:"flex items-center justify-between gap-1",children:[_(-1,v),e("div",{className:"flex min-w-0 flex-1 items-center justify-center gap-1",children:"year"===d?e("span",{className:`text-mp-on-surface flex h-(--_mp-cell) items-center tabular-nums ${h[o]}`,children:`${F}–${F+T-1}`}):"month"===d?z:t(n,M?{children:[j,z]}:{children:[z,j]})}),_(1,y)]})}export function MPCalendar({size:n,color:r,locale:l,weekStartsOn:a,month:s,onMonthChange:c,selected:i,rangeStart:u=null,rangeEnd:m=null,onSelect:d,onPreviewChange:h,minDate:f,maxDate:p,shouldDisableDate:y,showOutsideDays:w=!0,autoFocus:x=!1,showPreviousButton:b=!0,showNextButton:S=!0,labels:M}){const[C,k]=o.useState("day"),A=o.useMemo(()=>i.filter(P),[i]),[E,Y]=o.useState(()=>{const e=A.find(e=>N(e,s));return e?j(e):N(F(),s)?F():z(s)}),R=o.useRef(x),H=o.useRef(null);o.useEffect(()=>{Y(e=>N(e,s)?e:z(s))},[s]),o.useLayoutEffect(()=>{R.current&&(R.current=!1,H.current?.querySelector('[data-focus-target="true"]')?.focus({preventScroll:!0}))});const $=o.useCallback(e=>D(e,f,p)||(y?.(e)??!1),[f,p,y]),L=e=>{R.current=!0,k(e)},q=e=>{R.current=!0,c(e)};return t("div",{ref:H,className:"mp-calendar flex flex-col gap-1",style:{"--_mp-cell":B[n]},onPointerLeave:()=>h?.(null),children:[e(K,{size:n,color:r,view:C,month:s,locale:l,labels:M,showPreviousButton:b,showNextButton:S,onStep:e=>{c("day"===C?g(s,e):v(s,"month"===C?e:e*T))},onViewChange:L}),e("div",{className:"h-[calc(var(--_mp-cell)*7)] w-[calc(var(--_mp-cell)*7)]",children:"day"===C?e(U,{size:n,locale:l,weekStartsOn:a,month:s,chosen:A,rangeStart:u,rangeEnd:m,focusedDate:E,showOutsideDays:w,isDisabled:$,onSelect:e=>{Y(e),d(e)},onPreviewChange:h,onMoveFocus:e=>{R.current=!0,Y(e),N(e,s)||c(z(e))}}):"month"===C?e(I,{size:n,locale:l,month:s,chosen:A,minDate:f,maxDate:p,onMoveCursor:q,onPick:e=>{c(_(s.getFullYear(),e,1)),L("day")}}):e(O,{size:n,month:s,chosen:A,minDate:f,maxDate:p,onMoveCursor:q,onPick:e=>{c(_(e,s.getMonth(),1)),L("month")}})})]})}function L(e){return"rtl"===getComputedStyle(e).direction?-1:1}function U({size:n,locale:r,weekStartsOn:l,month:a,chosen:s,rangeStart:c,rangeEnd:i,focusedDate:u,showOutsideDays:m,isDisabled:f,onSelect:v,onPreviewChange:b,onMoveFocus:D}){const S=A(r,l,"narrow"),_=A(r,l,"long"),C=(j=i,P(k=c)&&P(j)?w(k,j)<=0?[k,j]:[j,k]:null);var k,j;const z=F(),E=o.useMemo(()=>{const e=x(r,{dateStyle:"full"});return y(a,l).map(t=>t.map(t=>({date:t,label:e.format(t)})))},[a,l,r]),T=o.useRef(null),Y=o.useRef(a);o.useLayoutEffect(()=>{const e=T.current,t=Y.current;if(Y.current=a,!e||N(t,a))return;const n=t.getTime()<a.getTime(),o="rtl"===getComputedStyle(e).direction;e.style.setProperty("--_mp-calendar-from",String(n===o?-1:1)),e.dataset.mpPaged="true",e.style.animationName="none",e.offsetWidth,e.style.animationName=""},[a]);return t("div",{role:"grid","aria-label":x(r,{year:"numeric",month:"long"}).format(a),className:"flex h-full flex-col",children:[e("div",{role:"rowgroup",children:e("div",{role:"row",className:"grid grid-cols-7",children:S.map((t,n)=>e("span",{role:"columnheader","aria-label":_[n],className:`text-mp-on-surface-variant flex h-(--_mp-cell) items-center justify-center select-none ${d}`,children:t},n))})}),e("div",{ref:T,role:"rowgroup",className:"mp-calendar__page flex flex-1 flex-col",children:E.map((t,o)=>e("div",{role:"row",className:"grid grid-cols-7",children:t.map(({date:t,label:o})=>{const r=!N(t,a);if(r&&!m)return e("span",{role:"gridcell","aria-hidden":"true",className:"size-(--_mp-cell)"},t.getTime());const c=s.some(e=>M(e,t)),i=null!==C&&w(t,C[0])>=0&&w(t,C[1])<=0,d=null!==C&&i&&M(t,C[0]),y=null!==C&&i&&M(t,C[1]);return e($,{label:o,selected:c,inRange:i&&!c,rangeEdge:i?d&&y?"both":d?"start":y?"end":"middle":null,current:M(t,z)&&!c,muted:r,disabled:f(t),focused:M(t,u),className:`size-(--_mp-cell) ${h[n]}`,onClick:()=>v(t),onPointerEnter:()=>b?.(t),onKeyDown:e=>((e,t)=>{const n=(t.getDay()-l+7)%7,o=L(e.currentTarget),r={ArrowLeft:()=>p(t,-o),ArrowRight:()=>p(t,o),ArrowUp:()=>p(t,-7),ArrowDown:()=>p(t,7),Home:()=>p(t,-n),End:()=>p(t,6-n),PageUp:()=>g(t,e.shiftKey?-12:-1),PageDown:()=>g(t,e.shiftKey?12:1)}[e.key];r&&(e.preventDefault(),D(r()))})(e,t),children:t.getDate()},t.getTime())})},o))})]})}function I({size:t,locale:n,month:o,chosen:r,minDate:l,maxDate:a,onMoveCursor:s,onPick:c}){const i=k(n,"short"),u=k(n,"long"),m=o.getFullYear(),d=new Date,f=e=>{const t=L(e.currentTarget),n={ArrowLeft:-t,ArrowRight:t,ArrowUp:-3,ArrowDown:3,PageUp:-12,PageDown:12}[e.key];void 0!==n&&(e.preventDefault(),s(g(z(o),n)))};return e("div",{role:"grid",className:"flex h-full flex-col justify-evenly",children:[0,1,2,3].map(n=>e("div",{role:"row",className:"grid grid-cols-3 gap-1",children:[0,1,2].map(s=>{const p=3*n+s,g=_(m,p,1),v=_(m,p,b(m,p));return e($,{label:`${u[p]} ${m}`,selected:r.some(e=>e.getFullYear()===m&&e.getMonth()===p),current:d.getFullYear()===m&&d.getMonth()===p,disabled:P(l)&&w(v,l)<0||P(a)&&w(g,a)>0,focused:p===o.getMonth(),className:`h-(--_mp-cell) w-full ${h[t]}`,onClick:()=>c(p),onKeyDown:f,children:i[p]},p)})},n))})}function O({size:t,month:n,chosen:o,minDate:r,maxDate:l,onMoveCursor:a,onPick:s}){const c=Y(n.getFullYear()),i=(new Date).getFullYear(),u=e=>{const t=L(e.currentTarget),o={ArrowLeft:-t,ArrowRight:t,ArrowUp:-4,ArrowDown:4,PageUp:-T,PageDown:T}[e.key];void 0!==o&&(e.preventDefault(),a(v(z(n),o)))};return e("div",{role:"grid",className:"flex h-full flex-col justify-evenly",children:[0,1,2].map(a=>e("div",{role:"row",className:"grid grid-cols-4 gap-1",children:[0,1,2,3].map(m=>{const d=c+4*a+m;return e($,{label:String(d),selected:o.some(e=>e.getFullYear()===d),current:d===i,disabled:P(r)&&d<r.getFullYear()||P(l)&&d>l.getFullYear(),focused:d===n.getFullYear(),className:`h-(--_mp-cell) w-full ${h[t]}`,onClick:()=>s(d),onKeyDown:u,children:d},d)})},a))})}function q(e,t){return Number.isFinite(e)?Math.min(t,Math.max(1,Math.round(e))):1}function V(e){const t=e.parentElement;if(!t)return;const n=e.getBoundingClientRect(),o=t.getBoundingClientRect(),r=n.top-o.top-t.clientTop+t.scrollTop,l=r+n.height;r<t.scrollTop?t.scrollTop=r:l>t.scrollTop+t.clientHeight&&(t.scrollTop=l-t.clientHeight)}export function MPTimeGrid({size:n,locale:r,value:l,referenceDate:a,onChange:s,hour12:c,showSeconds:i,hourStep:m,minuteStep:d,secondStep:p,shouldDisableTime:g,autoFocus:v=!1,labels:y}){const w=l??a,b=o.useRef(null),[D,S]=o.useMemo(()=>C(r),[r]);o.useEffect(()=>{const e=b.current;if(e?.querySelectorAll('[data-chosen="true"]').forEach(V),v){const t=e?.querySelector('[role="listbox"]');(t?.querySelector('[data-chosen="true"]')??t?.querySelector('[role="option"]'))?.focus({preventScroll:!0})}},[v]);const M=o.useMemo(()=>{const e=c?12:24,t=q(m,e),n=Array.from({length:Math.ceil(e/t)},(e,n)=>n*t);return c?n.map(e=>0===e?12:e):n},[c,m]),N=o.useMemo(()=>{const e=q(d,60);return Array.from({length:Math.ceil(60/e)},(t,n)=>n*e)},[d]),P=o.useMemo(()=>{const e=q(p,60);return Array.from({length:Math.ceil(60/e)},(t,n)=>n*e)},[p]),_=e=>String(e).padStart(2,"0"),k=c?w.getHours()%12||12:w.getHours(),[j,z]=o.useState({}),F=(o,r,a,i,m)=>{const d=null===l?-1:a.findIndex(e=>i(e)),f=j[o]??(d>=0?d:0);return e("div",{role:"listbox","aria-label":r,className:["mp-time-grid__column flex flex-col gap-0.5 overflow-y-auto overscroll-contain","h-[calc(var(--_mp-cell)*7)] w-[calc(var(--_mp-cell)*1.75)]","scroll-py-0.5 [scrollbar-width:thin]"].join(" "),onKeyDown:e=>{const t={ArrowDown:1,ArrowUp:-1,PageDown:5,PageUp:-5}[e.key],n=void 0!==t?(e=>{const t=[...e.children].indexOf(document.activeElement);return t>=0?t:f})(e.currentTarget)+t:"Home"===e.key?0:"End"===e.key?a.length-1:null;null!==n&&(e.preventDefault(),((e,t)=>{const n=Math.min(a.length-1,Math.max(0,e)),r=t.children[n];z(e=>({...e,[o]:n})),r instanceof HTMLElement&&(r.focus({preventScroll:!0}),V(r))})(n,e.currentTarget))},children:a.map((r,a)=>{const d=((e,t)=>E(w,"hour"===e?{hours:c?t%12+(w.getHours()>=12?12:0):t}:"minute"===e?{minutes:t}:"second"===e?{seconds:t}:{hours:w.getHours()%12+12*t}))(o,r),p=null!==l&&i(r),v=g?.(d,o)??!1;return t("button",{type:"button",role:"option","aria-selected":p,"aria-disabled":v||void 0,"data-chosen":p?"true":void 0,tabIndex:a===f?0:-1,className:[H,"rounded-mp-full h-(--_mp-cell) w-full shrink-0",h[n],v?"cursor-default text-mp-on-surface/38":p?"bg-(--_mp-accent) text-(--_mp-on-accent)":"text-mp-on-surface"].join(" "),onFocus:()=>z(e=>({...e,[o]:a})),onClick:()=>{v||s(d)},children:[v?null:e(u,{}),m(r)]},r)})},o)};return t("div",{ref:b,className:"mp-time-grid flex gap-1",style:{"--_mp-cell":B[n]},children:[F("hour",y.hour,M,e=>e===k,e=>c?String(e):_(e)),F("minute",y.minute,N,e=>e===w.getMinutes(),_),i?F("second",y.second,P,e=>e===w.getSeconds(),_):null,c?F("meridiem",y.meridiem,[0,1],e=>(w.getHours()>=12?1:0)===e,e=>0===e?D:S):null,e("span",{className:f,"aria-live":"polite",children:null===l?"":x(r,{hour:"numeric",minute:"2-digit",...i?{second:"2-digit"}:{}}).format(l)})]})}
2
+ import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import*as o from"react";import{MPButton as r}from"../components/button/MPButton.js";import{MPIcon as l}from"../components/icon/MPIcon.js";import{MPIconButton as a}from"../components/icon-button/MPIconButton.js";import{ChevronDownIcon as s,ChevronLeftIcon as c,ChevronRightIcon as i}from"../constants/icons.js";import{MPStateLayer as u}from"./StateLayer.js";import{CONTROL_ICON as m,META_TEXT as d,PROSE_TEXT as h}from"./scale.js";import{VISUALLY_HIDDEN as p}from"./visually-hidden.js";import{addDays as f,addMonths as g,addYears as y,calendarWeeks as v,compareDay as w,dateFormatter as x,isDayOutside as b,isMonthBeforeYear as D,isSameDay as S,isSameMonth as M,isUnitOutside as N,isValidDate as P,makeDate as _,meridiemLabels as C,monthLabels as k,startOfDay as j,startOfMonth as z,today as A,weekdayLabels as E,withTime as T,YEAR_PAGE_SIZE as F,yearPageStart as Y}from"./date.js";const B={xs:"1.75rem",sm:"2rem",md:"2.5rem",lg:"2.75rem",xl:"3rem"},R={xs:"xs",sm:"xs",md:"sm",lg:"sm",xl:"md"},H=/*@__PURE__*/["group relative flex cursor-pointer items-center justify-center overflow-hidden","box-border appearance-none font-[inherit] tabular-nums select-none","transition-[background-color,border-color,color]","duration-(--mp-sys-motion-duration-short4)","outline-mp-secondary focus-visible:z-10 focus-visible:outline-2","focus-visible:outline-offset-[-2px] focus-visible:outline-solid outline-none"].join(" "),$={day:0,month:1,year:2};function K({children:n,label:o,selected:r,inRange:l=!1,rangeEdge:a=null,current:s=!1,muted:c=!1,disabled:i=!1,focused:m=!1,className:d,onClick:h,onPointerEnter:p,onKeyDown:f}){return t("button",{type:"button",role:"gridcell","aria-label":o,"aria-selected":r,"aria-current":s?"date":void 0,"aria-disabled":i||void 0,tabIndex:m?0:-1,"data-focus-target":m?"true":void 0,className:[H,"start"===a?"rounded-s-mp-full":"end"===a?"rounded-e-mp-full":"middle"===a?"rounded-none":"rounded-mp-full",i?"bg-transparent cursor-default text-mp-on-surface/38":r?"bg-(--_mp-accent) text-(--_mp-on-accent)":l?"bg-(--_mp-accent-container) text-(--_mp-on-accent-container)":s?"bg-transparent border border-(--_mp-accent) text-(--_mp-accent)":c?"bg-transparent text-mp-on-surface-variant":"bg-transparent text-mp-on-surface",d??""].filter(Boolean).join(" "),onClick:()=>{i||h()},onPointerEnter:p,onKeyDown:f,children:[i?null:e(u,{}),n]})}function L({size:o,color:u,view:d,month:p,locale:f,labels:g,showPreviousButton:y,showNextButton:v,onStep:w,onViewChange:x}){const b=k(f,"long")[p.getMonth()],S=String(p.getFullYear()),M=D(f),N=R[o],P="day"===d?[g.previousMonth,g.nextMonth]:"month"===d?[g.previousYear,g.nextYear]:[g.previousYears,g.nextYears],_=(t,n)=>n?e(a,{size:N,color:u,label:P[-1===t?0:1],icon:e(l,{icon:-1===t?c:i,size:m[N],className:"rtl:rotate-180"}),onClick:()=>w(t)}):e("span",{"aria-hidden":"true",className:"size-(--_mp-cell)"}),C=t=>e(l,{icon:s,size:m[N],className:["transition-transform duration-(--mp-sys-motion-duration-short4)",t?"rotate-180":""].filter(Boolean).join(" ")}),j=e(r,{variant:"text",size:N,color:u,"aria-label":g.chooseMonth,"aria-expanded":"month"===d,endIcon:C("month"===d),onClick:()=>x("month"===d?"day":"month"),children:b},"month"),z=e(r,{variant:"text",size:N,color:u,className:"tabular-nums","aria-label":g.chooseYear,"aria-expanded":"year"===d,endIcon:C("year"===d),onClick:()=>x("year"===d?"day":"year"),children:S},"year"),A=Y(p.getFullYear());return t("div",{className:"flex items-center justify-between gap-1",children:[_(-1,y),e("div",{className:"flex min-w-0 flex-1 items-center justify-center gap-1",children:"year"===d?e("span",{className:`text-mp-on-surface flex h-(--_mp-cell) items-center tabular-nums ${h[o]}`,children:`${A}–${A+F-1}`}):"month"===d?z:t(n,M?{children:[j,z]}:{children:[z,j]})}),_(1,v)]})}export function Calendar({size:n,color:r,locale:l,weekStartsOn:a,month:s,onMonthChange:c,selected:i,rangeStart:u=null,rangeEnd:m=null,onSelect:d,onPreviewChange:h,minDate:p,maxDate:f,shouldDisableDate:v,showOutsideDays:w=!0,autoFocus:x=!1,showPreviousButton:D=!0,showNextButton:S=!0,precision:N="day",labels:C}){const[k,E]=o.useState(N),T=$[k]<$[N]?N:k,Y=o.useMemo(()=>i.filter(P),[i]),[R,H]=o.useState(()=>{const e=Y.find(e=>M(e,s));return e?j(e):M(A(),s)?A():z(s)}),K=o.useRef(x),U=o.useRef(null);o.useEffect(()=>{H(e=>M(e,s)?e:z(s))},[s]),o.useLayoutEffect(()=>{K.current&&(K.current=!1,U.current?.querySelector('[data-focus-target="true"]')?.focus({preventScroll:!0}))});const V=o.useCallback(e=>b(e,p,f)||(v?.(e)??!1),[p,f,v]),G=e=>{K.current=!0,E(e)},W=e=>{K.current=!0,c(e)};return t("div",{ref:U,className:"mp-calendar flex flex-col gap-1",style:{"--_mp-cell":B[n]},onPointerLeave:()=>h?.(null),children:[e(L,{size:n,color:r,view:T,month:s,locale:l,labels:C,showPreviousButton:D,showNextButton:S,onStep:e=>{c("day"===T?g(s,e):y(s,"month"===T?e:e*F))},onViewChange:G}),e("div",{className:"h-[calc(var(--_mp-cell)*7)] w-[calc(var(--_mp-cell)*7)]",children:"day"===T?e(I,{size:n,locale:l,weekStartsOn:a,month:s,chosen:Y,rangeStart:u,rangeEnd:m,focusedDate:R,showOutsideDays:w,isDisabled:V,onSelect:e=>{H(e),d(e)},onPreviewChange:h,onMoveFocus:e=>{K.current=!0,H(e),M(e,s)||c(z(e))}}):"month"===T?e(O,{size:n,locale:l,month:s,chosen:Y,minDate:p,maxDate:f,onMoveCursor:W,onPick:e=>{const t=_(s.getFullYear(),e,1);"month"!==N?(c(t),G("day")):d(t)}}):e(q,{size:n,month:s,chosen:Y,minDate:p,maxDate:f,onMoveCursor:W,onPick:e=>{"year"!==N?(c(_(e,s.getMonth(),1)),G("month")):d(_(e,0,1))}})})]})}function U(e){return"rtl"===getComputedStyle(e).direction?-1:1}function I({size:n,locale:r,weekStartsOn:l,month:a,chosen:s,rangeStart:c,rangeEnd:i,focusedDate:u,showOutsideDays:m,isDisabled:p,onSelect:y,onPreviewChange:b,onMoveFocus:D}){const N=E(r,l,"narrow"),_=E(r,l,"long"),C=(j=i,P(k=c)&&P(j)?w(k,j)<=0?[k,j]:[j,k]:null);var k,j;const z=A(),T=o.useMemo(()=>{const e=x(r,{dateStyle:"full"});return v(a,l).map(t=>t.map(t=>({date:t,label:e.format(t)})))},[a,l,r]),F=o.useRef(null),Y=o.useRef(a);o.useLayoutEffect(()=>{const e=F.current,t=Y.current;if(Y.current=a,!e||M(t,a))return;const n=t.getTime()<a.getTime(),o="rtl"===getComputedStyle(e).direction;e.style.setProperty("--_mp-calendar-from",String(n===o?-1:1)),e.dataset.mpPaged="true",e.style.animationName="none",e.offsetWidth,e.style.animationName=""},[a]);return t("div",{role:"grid","aria-label":x(r,{year:"numeric",month:"long"}).format(a),className:"flex h-full flex-col",children:[e("div",{role:"rowgroup",children:e("div",{role:"row",className:"grid grid-cols-7",children:N.map((t,n)=>e("span",{role:"columnheader","aria-label":_[n],className:`text-mp-on-surface-variant flex h-(--_mp-cell) items-center justify-center select-none ${d}`,children:t},n))})}),e("div",{ref:F,role:"rowgroup",className:"mp-calendar__page flex flex-1 flex-col",children:T.map((t,o)=>e("div",{role:"row",className:"grid grid-cols-7",children:t.map(({date:t,label:o})=>{const r=!M(t,a);if(r&&!m)return e("span",{role:"gridcell","aria-hidden":"true",className:"size-(--_mp-cell)"},t.getTime());const c=s.some(e=>S(e,t)),i=null!==C&&w(t,C[0])>=0&&w(t,C[1])<=0,d=null!==C&&i&&S(t,C[0]),v=null!==C&&i&&S(t,C[1]);return e(K,{label:o,selected:c,inRange:i&&!c,rangeEdge:i?d&&v?"both":d?"start":v?"end":"middle":null,current:S(t,z)&&!c,muted:r,disabled:p(t),focused:S(t,u),className:`size-(--_mp-cell) ${h[n]}`,onClick:()=>y(t),onPointerEnter:()=>b?.(t),onKeyDown:e=>((e,t)=>{const n=(t.getDay()-l+7)%7,o=U(e.currentTarget),r={ArrowLeft:()=>f(t,-o),ArrowRight:()=>f(t,o),ArrowUp:()=>f(t,-7),ArrowDown:()=>f(t,7),Home:()=>f(t,-n),End:()=>f(t,6-n),PageUp:()=>g(t,e.shiftKey?-12:-1),PageDown:()=>g(t,e.shiftKey?12:1)}[e.key];r&&(e.preventDefault(),D(r()))})(e,t),children:t.getDate()},t.getTime())})},o))})]})}function O({size:t,locale:n,month:r,chosen:l,minDate:a,maxDate:s,onMoveCursor:c,onPick:i}){const u=k(n,"short"),m=r.getFullYear(),d=new Date,p=o.useMemo(()=>{const e=x(n,{year:"numeric",month:"long"});return Array.from({length:12},(t,n)=>e.format(_(m,n,1)))},[n,m]),f=e=>{const t=U(e.currentTarget),n={ArrowLeft:-t,ArrowRight:t,ArrowUp:-3,ArrowDown:3,PageUp:-12,PageDown:12}[e.key];void 0!==n&&(e.preventDefault(),c(g(z(r),n)))};return e("div",{role:"grid","aria-label":String(m),className:"flex h-full flex-col justify-evenly",children:[0,1,2,3].map(n=>e("div",{role:"row",className:"grid grid-cols-3 gap-1",children:[0,1,2].map(o=>{const c=3*n+o;return e(K,{label:p[c],selected:l.some(e=>e.getFullYear()===m&&e.getMonth()===c),current:d.getFullYear()===m&&d.getMonth()===c,disabled:N(_(m,c,1),"month",a,s),focused:c===r.getMonth(),className:`h-(--_mp-cell) w-full ${h[t]}`,onClick:()=>i(c),onKeyDown:f,children:u[c]},c)})},n))})}function q({size:t,month:n,chosen:o,minDate:r,maxDate:l,onMoveCursor:a,onPick:s}){const c=Y(n.getFullYear()),i=(new Date).getFullYear(),u=e=>{const t=U(e.currentTarget),o={ArrowLeft:-t,ArrowRight:t,ArrowUp:-4,ArrowDown:4,PageUp:-F,PageDown:F}[e.key];void 0!==o&&(e.preventDefault(),a(y(z(n),o)))};return e("div",{role:"grid","aria-label":`${c}–${c+F-1}`,className:"flex h-full flex-col justify-evenly",children:[0,1,2].map(a=>e("div",{role:"row",className:"grid grid-cols-4 gap-1",children:[0,1,2,3].map(m=>{const d=c+4*a+m;return e(K,{label:String(d),selected:o.some(e=>e.getFullYear()===d),current:d===i,disabled:N(_(d,0,1),"year",r,l),focused:d===n.getFullYear(),className:`h-(--_mp-cell) w-full ${h[t]}`,onClick:()=>s(d),onKeyDown:u,children:d},d)})},a))})}function V(e,t){return Number.isFinite(e)?Math.min(t,Math.max(1,Math.round(e))):1}function G(e){const t=e.parentElement;if(!t)return;const n=e.getBoundingClientRect(),o=t.getBoundingClientRect(),r=n.top-o.top-t.clientTop+t.scrollTop,l=r+n.height;r<t.scrollTop?t.scrollTop=r:l>t.scrollTop+t.clientHeight&&(t.scrollTop=l-t.clientHeight)}export function MPTimeGrid({size:n,locale:r,value:l,referenceDate:a,onChange:s,hour12:c,showSeconds:i,hourStep:m,minuteStep:d,secondStep:f,shouldDisableTime:g,autoFocus:y=!1,labels:v}){const w=l??a,b=o.useRef(null),[D,S]=o.useMemo(()=>C(r),[r]);o.useEffect(()=>{const e=b.current;if(e?.querySelectorAll('[data-chosen="true"]').forEach(G),y){const t=e?.querySelector('[role="listbox"]');(t?.querySelector('[data-chosen="true"]')??t?.querySelector('[role="option"]'))?.focus({preventScroll:!0})}},[y]);const M=o.useMemo(()=>{const e=c?12:24,t=V(m,e),n=Array.from({length:Math.ceil(e/t)},(e,n)=>n*t);return c?n.map(e=>0===e?12:e):n},[c,m]),N=o.useMemo(()=>{const e=V(d,60);return Array.from({length:Math.ceil(60/e)},(t,n)=>n*e)},[d]),P=o.useMemo(()=>{const e=V(f,60);return Array.from({length:Math.ceil(60/e)},(t,n)=>n*e)},[f]),_=e=>String(e).padStart(2,"0"),k=c?w.getHours()%12||12:w.getHours(),[j,z]=o.useState({}),A=(o,r,a,i,m)=>{const d=null===l?-1:a.findIndex(e=>i(e)),p=j[o]??(d>=0?d:0);return e("div",{role:"listbox","aria-label":r,className:["mp-time-grid__column flex flex-col gap-0.5 overflow-y-auto overscroll-contain","h-[calc(var(--_mp-cell)*7)] w-[calc(var(--_mp-cell)*1.75)]","scroll-py-0.5 [scrollbar-width:thin]"].join(" "),onKeyDown:e=>{const t={ArrowDown:1,ArrowUp:-1,PageDown:5,PageUp:-5}[e.key],n=void 0!==t?(e=>{const t=[...e.children].indexOf(document.activeElement);return t>=0?t:p})(e.currentTarget)+t:"Home"===e.key?0:"End"===e.key?a.length-1:null;null!==n&&(e.preventDefault(),((e,t)=>{const n=Math.min(a.length-1,Math.max(0,e)),r=t.children[n];z(e=>({...e,[o]:n})),r instanceof HTMLElement&&(r.focus({preventScroll:!0}),G(r))})(n,e.currentTarget))},children:a.map((r,a)=>{const d=((e,t)=>T(w,"hour"===e?{hours:c?t%12+(w.getHours()>=12?12:0):t}:"minute"===e?{minutes:t}:"second"===e?{seconds:t}:{hours:w.getHours()%12+12*t}))(o,r),f=null!==l&&i(r),y=g?.(d,o)??!1;return t("button",{type:"button",role:"option","aria-selected":f,"aria-disabled":y||void 0,"data-chosen":f?"true":void 0,tabIndex:a===p?0:-1,className:[H,"rounded-mp-full h-(--_mp-cell) w-full shrink-0",h[n],y?"bg-transparent cursor-default text-mp-on-surface/38":f?"bg-(--_mp-accent) text-(--_mp-on-accent)":"bg-transparent text-mp-on-surface"].join(" "),onFocus:()=>z(e=>({...e,[o]:a})),onClick:()=>{y||s(d)},children:[y?null:e(u,{}),m(r)]},r)})},o)};return t("div",{ref:b,className:"mp-time-grid flex gap-1",style:{"--_mp-cell":B[n]},children:[A("hour",v.hour,M,e=>e===k,e=>c?String(e):_(e)),A("minute",v.minute,N,e=>e===w.getMinutes(),_),i?A("second",v.second,P,e=>e===w.getSeconds(),_):null,c?A("meridiem",v.meridiem,[0,1],e=>(w.getHours()>=12?1:0)===e,e=>0===e?D:S):null,e("span",{className:p,"aria-live":"polite",children:null===l?"":x(r,{hour:"numeric",minute:"2-digit",...i?{second:"2-digit"}:{}}).format(l)})]})}
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import type { MPPickerLabels } from './Calendar.js';
3
- import type { MPColor, MPSize, MPStyleProps } from '../types.js';
3
+ import type { MPColor, MPControlEventProps, MPSize, MPStyleProps } from '../types.js';
4
4
  /**
5
5
  * The strings a trigger is held open by, kept across renders that did not
6
6
  * change what it could say.
@@ -25,6 +25,18 @@ import type { MPColor, MPSize, MPStyleProps } from '../types.js';
25
25
  * never a wrong answer.
26
26
  */
27
27
  export declare function useDisplaySamples(locale: string | undefined, options: Intl.DateTimeFormatOptions): string[];
28
+ /**
29
+ * The popup's room, one track tighter than a control's.
30
+ *
31
+ * A calendar is already a grid of forty-two padded cells; giving the sheet
32
+ * around it a control's 16px as well would put 24px of nothing between the last
33
+ * column and the edge.
34
+ *
35
+ * Exported because `MPCalendar` draws the same grid on a surface of its own, and
36
+ * a standalone calendar sitting one track wider than the identical calendar in a
37
+ * picker's popup is the drift a shared table exists to prevent.
38
+ */
39
+ export declare const POPUP_PAD: Record<MPSize, string>;
28
40
  /**
29
41
  * The props a picker takes from its shell rather than inventing.
30
42
  *
@@ -32,7 +44,7 @@ export declare function useDisplaySamples(locale: string | undefined, options: I
32
44
  * the rows a reader of the docs is actually looking at — every one of the four
33
45
  * pickers lists them, and they mean the same thing on all four.
34
46
  */
35
- export interface MPPickerShellProps extends MPStyleProps {
47
+ export interface MPPickerShellProps extends MPStyleProps, MPControlEventProps<HTMLButtonElement> {
36
48
  /**
37
49
  * Which accent family the popup reads: the chosen day's fill, the band across
38
50
  * a range, today's outline, the footer's confirm button.
@@ -130,7 +142,7 @@ interface InternalShellProps extends MPPickerShellProps {
130
142
  * treatment, and the popup's `surface-container` at elevation 2 — which is the
131
143
  * same floating sheet a menu and a select's list are drawn on.
132
144
  */
133
- export declare function MPPickerShell({ slug, size, color, fullWidth, label, floatingLabel, description, errorMessage, startIcon, required, disabled, readOnly, id, className, style, display, samples, empty, clearable, onClear, open, onOpenChange, labels, hiddenValues, children, triggerRef }: InternalShellProps): React.JSX.Element;
145
+ export declare function MPPickerShell({ slug, size, color, fullWidth, label, floatingLabel, description, errorMessage, startIcon, required, disabled, readOnly, id, className, style, onKeyDown, onKeyUp, onFocus, onBlur, onClick, onDoubleClick, onContextMenu, display, samples, empty, clearable, onClear, open, onOpenChange, labels, hiddenValues, children, triggerRef }: InternalShellProps): React.JSX.Element;
134
146
  /**
135
147
  * The row of shortcuts under a picker's panel.
136
148
  *
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as i from"react";import{Field as n}from"@base-ui/react/field";import{Popover as t}from"@base-ui/react/popover";import{MPIcon as o}from"../components/icon/MPIcon.js";import{CloseIcon as a}from"../constants/icons.js";import{accentSlots as s}from"./accent.js";import{MPFieldLabel as l,MPFieldOutline as p,useFloatingLabel as c}from"./FieldOutline.js";import{MPStateLayer as m}from"./StateLayer.js";import{MPSupportingText as d}from"./SupportingText.js";import{MPWidthSizer as u}from"./WidthSizer.js";import{displaySamples as f}from"./date.js";import{CONTROL_ICON as h,hasContent as g,PROSE_TEXT as x}from"./scale.js";import{FADE as b,PORTAL_LAYER as j}from"./surface.js";export function useDisplaySamples(e,r){const n=`${e??""} ${JSON.stringify(r)}`;return i.useMemo(()=>f(e,r),[n])}const v={xs:{padding:"px-2",height:"h-8"},sm:{padding:"px-3",height:"h-10"},md:{padding:"px-4",height:"h-14"},lg:{padding:"px-4",height:"h-16"},xl:{padding:"px-5",height:"h-18"}},y={xs:"p-1.5",sm:"p-2",md:"p-2.5",lg:"p-3",xl:"p-3.5"};export function MPPickerShell({slug:f,size:N="md",color:P="primary",fullWidth:w=!1,label:O,floatingLabel:k=!0,description:M,errorMessage:S,startIcon:z,required:F=!1,disabled:B=!1,readOnly:C=!1,id:I,className:R,style:$,display:q,samples:T,empty:_,clearable:D=!1,onClear:E,open:L,onOpenChange:W,labels:J,hiddenValues:V,children:Z,triggerRef:A}){const G=g(S),H=v[N],K=i.useId(),Q=I??K,U=D&&!_&&!(B||C),{shrunk:X,focusProps:Y}=c({floating:k&&g(O),filled:!_,pinned:L||g(z)});return r(n.Root,{disabled:B,invalid:G,"data-mp-size":N,className:[`mp-${f} group flex-col align-top`,w?"flex w-full":"inline-flex w-fit",R??""].filter(Boolean).join(" "),style:{...s(P),...$},...Y,children:[r(t.Root,{open:L,onOpenChange:W,children:[r("div",{className:"relative w-full",children:[r(t.Trigger,{id:Q,ref:A,disabled:B,nativeButton:!0,className:["relative flex w-full items-center gap-2 select-none","appearance-none bg-transparent font-[inherit] outline-none",H.padding,U?"pe-10":"",H.height,x[N],B?"text-mp-on-surface/38 cursor-default":"text-mp-on-surface "+(C?"cursor-default":"cursor-pointer")].filter(Boolean).join(" "),children:[z?e("span",{className:["flex shrink-0 items-center",B?"text-mp-on-surface/38":"text-mp-on-surface-variant"].join(" "),children:z}):null,r("span",{className:"flex min-w-0 flex-1 flex-col",children:[e("span",{className:["w-full truncate text-start",_&&!B?"text-mp-on-surface-variant":""].filter(Boolean).join(" "),children:_&&!X?null:q}),e(u,{samples:T??[]})]})]}),U?r("button",{type:"button","aria-label":J.clear,onClick:E,className:["group/clear rounded-mp-full text-mp-on-surface-variant absolute inset-y-0","end-1 my-auto flex size-8 cursor-pointer items-center justify-center","appearance-none border-0 bg-transparent font-[inherit]","outline-mp-secondary focus-visible:outline-2 focus-visible:outline-offset-1","focus-visible:outline-solid outline-none"].join(" "),children:[e(m,{className:"group-hover/clear:opacity-8 group-focus-visible/clear:opacity-10"}),e(o,{icon:a,size:h[N]})]}):null,e(p,{label:O,required:F,notched:X}),g(O)?e(l,{size:N,label:O,required:F,htmlFor:Q,shrunk:X}):null]}),e(t.Portal,{children:e(t.Positioner,{className:j,sideOffset:4,align:"start",children:e(t.Popup,{initialFocus:!1,className:[`mp-${f}__popup rounded-mp-md shadow-mp-2 bg-mp-surface-container`,"text-mp-on-surface outline-none",y[N],x[N],b].join(" "),children:Z})})})]}),e(d,{description:M,errorMessage:S,className:H.padding}),V?.map((r,i)=>e("input",{type:"hidden",name:r.name,value:r.value},i))]})}export function MPPickerFooter({children:r}){return e("div",{className:"border-mp-outline-variant flex items-center justify-end gap-1 border-t pt-1.5",children:r})}export function MPPickerDivider(){return e("div",{"aria-hidden":"true",className:"bg-mp-outline-variant w-px self-stretch"})}export const FOOTER_SIZE={xs:"xs",sm:"xs",md:"sm",lg:"sm",xl:"md"};
2
+ import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as o from"react";import{Field as r}from"@base-ui/react/field";import{Popover as i}from"@base-ui/react/popover";import{MPIcon as t}from"../components/icon/MPIcon.js";import{CloseIcon as l}from"../constants/icons.js";import{accentSlots as s}from"./accent.js";import{MPFieldLabel as a,MPFieldOutline as p,useFloatingLabel as c}from"./FieldOutline.js";import{MPStateLayer as u}from"./StateLayer.js";import{MPSupportingText as m}from"./SupportingText.js";import{MPWidthSizer as d}from"./WidthSizer.js";import{displaySamples as f}from"./date.js";import{CONTROL_ICON as h,hasContent as x,PROSE_TEXT as g}from"./scale.js";import{FADE as b,PORTAL_LAYER as y}from"./surface.js";export function useDisplaySamples(e,n){const r=`${e??""} ${JSON.stringify(n)}`;return o.useMemo(()=>f(e,n),[r])}const j={xs:{padding:"px-2",height:"h-8"},sm:{padding:"px-3",height:"h-10"},md:{padding:"px-4",height:"h-14"},lg:{padding:"px-4",height:"h-16"},xl:{padding:"px-5",height:"h-18"}};export const POPUP_PAD={xs:"p-1.5",sm:"p-2",md:"p-2.5",lg:"p-3",xl:"p-3.5"};export function MPPickerShell({slug:f,size:v="md",color:P="primary",fullWidth:N=!1,label:k,floatingLabel:w=!0,description:C,errorMessage:O,startIcon:M,required:D=!1,disabled:F=!1,readOnly:S=!1,id:z,className:B,style:_,onKeyDown:I,onKeyUp:K,onFocus:R,onBlur:U,onClick:$,onDoubleClick:q,onContextMenu:T,display:A,samples:E,empty:L,clearable:W=!1,onClear:J,open:V,onOpenChange:Z,labels:G,hiddenValues:H,children:Q,triggerRef:X}){const Y=x(O),ee=j[v],ne=o.useId(),oe=z??ne,re=W&&!L&&!(F||S),{shrunk:ie,focusProps:te}=c({floating:w&&x(k),filled:!L,pinned:V||x(M)});return n(r.Root,{disabled:F,invalid:Y,"data-mp-size":v,className:[`mp-${f} group flex-col align-top`,N?"flex w-full":"inline-flex w-fit",B??""].filter(Boolean).join(" "),style:{...s(P),..._},...te,children:[n(i.Root,{open:V,onOpenChange:Z,children:[n("div",{className:"relative w-full",children:[n(i.Trigger,{id:oe,ref:X,disabled:F,nativeButton:!0,onKeyDown:I,onKeyUp:K,onFocus:R,onBlur:U,onClick:$,onDoubleClick:q,onContextMenu:T,className:["relative flex w-full items-center gap-2 select-none","appearance-none bg-transparent font-[inherit] outline-none",ee.padding,re?"pe-10":"",ee.height,g[v],F?"text-mp-on-surface/38 cursor-default":"text-mp-on-surface "+(S?"cursor-default":"cursor-pointer")].filter(Boolean).join(" "),children:[M?e("span",{className:["flex shrink-0 items-center",F?"text-mp-on-surface/38":"text-mp-on-surface-variant"].join(" "),children:M}):null,n("span",{className:"flex min-w-0 flex-1 flex-col",children:[e("span",{className:["w-full truncate text-start",L&&!F?"text-mp-on-surface-variant":""].filter(Boolean).join(" "),children:L&&!ie?null:A}),e(d,{samples:E??[]})]})]}),re?n("button",{type:"button","aria-label":G.clear,onClick:J,className:["group/clear rounded-mp-full text-mp-on-surface-variant absolute inset-y-0","end-1 my-auto flex size-8 cursor-pointer items-center justify-center","appearance-none border-0 bg-transparent font-[inherit]","outline-mp-secondary focus-visible:outline-2 focus-visible:outline-offset-1","focus-visible:outline-solid outline-none"].join(" "),children:[e(u,{className:"group-hover/clear:opacity-8 group-focus-visible/clear:opacity-10"}),e(t,{icon:l,size:h[v]})]}):null,e(p,{label:k,required:D,notched:ie}),x(k)?e(a,{size:v,label:k,required:D,htmlFor:oe,shrunk:ie}):null]}),e(i.Portal,{children:e(i.Positioner,{className:y,sideOffset:4,align:"start",children:e(i.Popup,{initialFocus:!1,style:s(P),className:[`mp-${f}__popup rounded-mp-md shadow-mp-2 bg-mp-surface-container`,"text-mp-on-surface outline-none",POPUP_PAD[v],g[v],b].join(" "),children:Q})})})]}),e(m,{description:C,errorMessage:O,className:ee.padding}),H?.map((n,o)=>e("input",{type:"hidden",name:n.name,value:n.value},o))]})}export function MPPickerFooter({children:n}){return e("div",{className:"border-mp-outline-variant flex items-center justify-end gap-1 border-t pt-1.5",children:n})}export function MPPickerDivider(){return e("div",{"aria-hidden":"true",className:"bg-mp-outline-variant w-px self-stretch"})}export const FOOTER_SIZE={xs:"xs",sm:"xs",md:"sm",lg:"sm",xl:"md"};
@@ -0,0 +1,28 @@
1
+ /** What a page can be set to. `'system'` is the absence of a choice. */
2
+ export type MPColorScheme = 'light' | 'dark' | 'system';
3
+ /** What is actually painted, once `'system'` has been resolved. */
4
+ export type MPResolvedColorScheme = 'light' | 'dark';
5
+ export declare const SCHEME_ATTRIBUTE = "data-mp-scheme";
6
+ export declare const DEFAULT_STORAGE_KEY = "mp-color-scheme";
7
+ /**
8
+ * Puts the choice on the document element, or takes it off.
9
+ *
10
+ * `'system'` **removes** the attribute rather than writing it, which is the
11
+ * whole of how the media query gets its say back: the dark block is reached
12
+ * either by `prefers-color-scheme` on a root that is not forced light, or by the
13
+ * attribute. An attribute spelling out `system` would match neither.
14
+ */
15
+ export declare function applyScheme(scheme: MPColorScheme): void;
16
+ export declare function setScheme(storageKey: string, scheme: MPColorScheme): void;
17
+ export declare function useChosenScheme(storageKey: string): MPColorScheme;
18
+ /**
19
+ * What the operating system is asking for, followed live.
20
+ *
21
+ * Subscribed to even while a page has chosen `'light'` or `'dark'`, which costs
22
+ * one listener and buys the thing a toggle is usually for: switching back to
23
+ * `'system'` reports the right answer immediately rather than on the next
24
+ * change.
25
+ */
26
+ export declare function useSystemScheme(): MPResolvedColorScheme;
27
+ /** Test seam: forgets the page's choice so a suite can start from nothing. */
28
+ export declare function resetScheme(): void;
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import*as e from"react";export const SCHEME_ATTRIBUTE="data-mp-scheme";export const DEFAULT_STORAGE_KEY="mp-color-scheme";const t="(prefers-color-scheme: dark)";function n(e){return"light"===e||"dark"===e||"system"===e}let o;const r=new Set;function c(){for(const e of r)e()}export function applyScheme(e){if("undefined"==typeof document)return;const t=document.documentElement;"system"===e?t.removeAttribute("data-mp-scheme"):t.setAttribute("data-mp-scheme",e)}export function setScheme(e,t){o=t,function(e,t){try{"system"===t?localStorage.removeItem(e):localStorage.setItem(e,t)}catch{}}(e,t),applyScheme(t),c()}function s(e){return r.add(e),()=>{r.delete(e)}}function u(e){return o??=function(){if("undefined"==typeof document)return;const e=document.documentElement.getAttribute("data-mp-scheme");return n(e)&&"system"!==e?e:void 0}()??function(e){try{if("undefined"==typeof localStorage)return"system";const t=localStorage.getItem(e);return n(t)?t:"system"}catch{return"system"}}(e),o}export function useChosenScheme(t){const n=e.useCallback(()=>u(t),[t]);return e.useSyncExternalStore(s,n,()=>"system")}function m(e){if("undefined"==typeof window||!window.matchMedia)return()=>{};const n=window.matchMedia(t);return n.addEventListener("change",e),()=>n.removeEventListener("change",e)}function i(){return"undefined"!=typeof window&&window.matchMedia?.(t).matches?"dark":"light"}export function useSystemScheme(){return e.useSyncExternalStore(m,i,()=>"light")}export function resetScheme(){o=void 0,c()}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * The two prop defaults an application can move for the whole page.
3
+ *
4
+ * `size` and `color` are the only axes where every component in this library
5
+ * starts from the *same* answer — `md` and `primary` — which is what makes a
6
+ * single app-wide default meaningful for them and meaningless for anything else.
7
+ * A `variant` default is per component by design (`MPAccordion` is `outlined`,
8
+ * `MPAlert` is `tonal`, `MPBadge` is `filled`), so one global value would be
9
+ * overwriting six considered decisions with one arbitrary one.
10
+ *
11
+ * The same rule decides which components read this at all: a component that was
12
+ * taking the library's default takes the configured one instead, and a component
13
+ * that had chosen its own keeps it. `MPBadge` stays `error`, `MPTooltip` stays
14
+ * `sm`, `MPDialog`, `MPPill` and `MPShortcut` stay `secondary` — those are not
15
+ * unfilled defaults, they are answers.
16
+ *
17
+ * ## Why this needs context at all
18
+ *
19
+ * Which is the question `MPLocaleProvider` answers for itself, and the answer
20
+ * here is the same shape. Everything a theme normally carries — the colour
21
+ * roles, the type scale, the corners, the motion — is a CSS custom property and
22
+ * reaches a component through the cascade. `size` cannot: it resolves to literal
23
+ * Tailwind class strings (`h-14`, `text-mp-body-large`), because Tailwind finds
24
+ * classes by scanning source text and an interpolated `h-${n}` generates no rule
25
+ * at all. See `internal/scale.ts`. A value that cannot be a custom property and
26
+ * has to reach every call site is exactly what context is for.
27
+ */
28
+ import * as React from 'react';
29
+ import type { MPColor, MPSize } from '../types.js';
30
+ /** What an `MPConfigProvider` can set. Anything unset is inherited, then default. */
31
+ export interface MPConfigValue {
32
+ size?: MPSize;
33
+ color?: MPColor;
34
+ }
35
+ export declare const MPConfigContext: React.Context<MPConfigValue>;
36
+ /** The configuration in force at this point in the tree. */
37
+ export declare function useMPConfig(): MPConfigValue;
38
+ /**
39
+ * `prop ?? config ?? the library's own`, which is the order of specificity: what
40
+ * this call site said, then what the application said, then what Material says.
41
+ */
42
+ export declare function useMPSize(size: MPSize | undefined): MPSize;
43
+ export declare function useMPColor(color: MPColor | undefined): MPColor;
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import*as t from"react";const e=Object.freeze({});export const MPConfigContext=/*@__PURE__*/t.createContext(e);export function useMPConfig(){return t.useContext(MPConfigContext)}export function useMPSize(e){const o=t.useContext(MPConfigContext);return e??o.size??"md"}export function useMPColor(e){const o=t.useContext(MPConfigContext);return e??o.color??"primary"}
@@ -25,6 +25,16 @@
25
25
  import type { MPWeekday } from '../types.js';
26
26
  /** Which unit the calendar is currently letting you pick. */
27
27
  export type MPCalendarView = 'day' | 'month' | 'year';
28
+ /**
29
+ * Which unit a picker asks for at all — the view the calendar stops at.
30
+ *
31
+ * The same three words as `MPCalendarView` and deliberately a second name: one
32
+ * is what is on screen at this moment, the other is what the control is *for*.
33
+ * A day picker passes through all three views and answers with a day; a month
34
+ * picker never draws a day grid, and the year view above it is a way of
35
+ * reaching a month rather than an answer of its own.
36
+ */
37
+ export type MPDatePrecision = MPCalendarView;
28
38
  /** How many years one page of the year grid holds. Four columns of three. */
29
39
  export declare const YEAR_PAGE_SIZE = 12;
30
40
  /**
@@ -44,8 +54,22 @@ export declare function isValidDate(value: unknown): value is Date;
44
54
  export declare function startOfDay(date: Date): Date;
45
55
  /** The first day of the month this date is in, at midnight. */
46
56
  export declare function startOfMonth(date: Date): Date;
57
+ /** The first day of the year this date is in, at midnight. */
58
+ export declare function startOfYear(date: Date): Date;
47
59
  /** How many days a month has, leap years included. */
48
60
  export declare function daysInMonth(year: number, month: number): number;
61
+ /**
62
+ * The first instant of the day, month or year a date falls in.
63
+ *
64
+ * Which of the three is the picker's question rather than the calendar's. A
65
+ * control asked for a month holds a `Date` standing for a whole month, and the
66
+ * only honest one is that month's first day: a picker whose trigger says
67
+ * *July 2026* and whose form submits the 31st is printing one thing and sending
68
+ * another.
69
+ */
70
+ export declare function startOfUnit(date: Date, unit: MPCalendarView): Date;
71
+ /** The last day of that same unit, at midnight — the other end of its span. */
72
+ export declare function endOfUnit(date: Date, unit: MPCalendarView): Date;
49
73
  /** Today, at midnight. The one place the pickers read the clock for a *date*. */
50
74
  export declare function today(): Date;
51
75
  export declare function addDays(date: Date, amount: number): Date;
@@ -71,6 +95,21 @@ export declare function isSameMonth(a: Date | null | undefined, b: Date | null |
71
95
  * has been chosen.
72
96
  */
73
97
  export declare function isDayOutside(date: Date, min?: Date | null, max?: Date | null): boolean;
98
+ /**
99
+ * The same question asked of a whole month or a whole year.
100
+ *
101
+ * A unit is outside the span only when *every* day in it is, which is what
102
+ * leaves July reachable under a `minDate` of 10 July: the bound is about which
103
+ * months exist, and where inside one it falls is a day grid's problem. It is
104
+ * the widening `isDayOutside` already applies to the time of day, one rung up —
105
+ * and it is the rule both the month grid and the year grid were already
106
+ * spelling out for themselves.
107
+ *
108
+ * The day case is handed to `isDayOutside` rather than written as this rule
109
+ * with a one-day span, because that is the one that runs forty-two times per
110
+ * calendar per render and it can answer without building either end.
111
+ */
112
+ export declare function isUnitOutside(date: Date, unit: MPCalendarView, min?: Date | null, max?: Date | null): boolean;
74
113
  /** Seconds since local midnight — what `minTime`/`maxTime` are compared on. */
75
114
  export declare function secondsOfDay(date: Date): number;
76
115
  /** Which column of a clock a candidate time is being offered for. */
@@ -127,16 +166,24 @@ export declare function displaySamples(locale: string | undefined, options: Intl
127
166
  */
128
167
  export declare function withPlaceholder(samples: string[], placeholder: unknown): string[];
129
168
  /**
130
- * The three machine-readable spellings, for the hidden input that makes a picker
169
+ * The machine-readable spellings, for the hidden input that makes a picker
131
170
  * submit with a form.
132
171
  *
133
172
  * Local, not UTC, and that is the whole point: `toISOString()` on a `Date`
134
173
  * standing for 27 July in Seoul gives `2026-07-26T15:00:00Z`, and a form field
135
174
  * that quietly reports the day before the one on screen is the single most
136
175
  * expensive bug a date picker can ship. The shapes are the ones the native
137
- * `<input type="date">`, `type="time"` and `type="datetime-local"` submit, so a
138
- * server that already parses those needs no new code.
176
+ * `<input type="date">`, `type="month"`, `type="time"` and
177
+ * `type="datetime-local"` submit, so a server that already parses those needs no
178
+ * new code.
179
+ *
180
+ * A year on its own is the one with no input type behind it, and `YYYY` is what
181
+ * is left of the others once the parts a year picker was never asked about are
182
+ * taken off. Each spelling is built from the one above it, so there is one
183
+ * answer to how a year is written and not three.
139
184
  */
185
+ export declare function toISOYear(date: Date): string;
186
+ export declare function toISOMonth(date: Date): string;
140
187
  export declare function toISODate(date: Date): string;
141
188
  export declare function toISOTime(date: Date, withSeconds?: boolean): string;
142
189
  export declare function toISODateTime(date: Date, withSeconds?: boolean): string;