material-plus-ui 1.3.1 → 1.5.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 (261) hide show
  1. package/.fix.py +92 -0
  2. package/README.md +2 -2
  3. package/dist/components/alert/MPAlert.d.ts +26 -0
  4. package/dist/components/alert/MPAlert.js +1 -1
  5. package/dist/components/alert/index.d.ts +1 -1
  6. package/dist/components/animate-marquee/MPAnimateMarquee.js +1 -1
  7. package/dist/components/avatar/MPAvatar.js +1 -1
  8. package/dist/components/avatar-group/MPAvatarGroup.d.ts +74 -0
  9. package/dist/components/avatar-group/MPAvatarGroup.js +2 -0
  10. package/dist/components/avatar-group/index.d.ts +2 -0
  11. package/dist/components/avatar-group/index.js +1 -0
  12. package/dist/components/breadcrumb/MPBreadcrumb.d.ts +10 -4
  13. package/dist/components/breadcrumb/MPBreadcrumb.js +1 -1
  14. package/dist/components/button/MPButton.js +1 -1
  15. package/dist/components/button-group/MPButtonGroup.d.ts +9 -0
  16. package/dist/components/button-group/MPButtonGroup.js +1 -1
  17. package/dist/components/carousel/MPCarousel.d.ts +12 -7
  18. package/dist/components/carousel/MPCarousel.js +1 -1
  19. package/dist/components/chat-bubble/MPChatBubble.d.ts +15 -2
  20. package/dist/components/chat-bubble/MPChatBubble.js +1 -1
  21. package/dist/components/checkbox/MPCheckbox.d.ts +6 -0
  22. package/dist/components/checkbox/MPCheckbox.js +1 -1
  23. package/dist/components/color-picker/MPColorPicker.d.ts +20 -17
  24. package/dist/components/color-picker/MPColorPicker.js +1 -1
  25. package/dist/components/combobox/MPCombobox.d.ts +22 -4
  26. package/dist/components/combobox/MPCombobox.js +1 -1
  27. package/dist/components/command-palette/MPCommandPalette.d.ts +132 -0
  28. package/dist/components/command-palette/MPCommandPalette.js +2 -0
  29. package/dist/components/command-palette/index.d.ts +2 -0
  30. package/dist/components/command-palette/index.js +1 -0
  31. package/dist/components/container/MPContainer.js +1 -1
  32. package/dist/components/date-time-picker/MPDateTimePicker.d.ts +5 -0
  33. package/dist/components/dialog/MPDialog.js +1 -1
  34. package/dist/components/divider/MPDivider.js +1 -1
  35. package/dist/components/drawer/MPDrawer.js +1 -1
  36. package/dist/components/fieldset/MPFieldset.d.ts +52 -0
  37. package/dist/components/fieldset/MPFieldset.js +2 -0
  38. package/dist/components/fieldset/index.d.ts +2 -0
  39. package/dist/components/fieldset/index.js +1 -0
  40. package/dist/components/file-picker/MPFilePicker.d.ts +10 -3
  41. package/dist/components/file-picker/MPFilePicker.js +1 -1
  42. package/dist/components/floating-action-button/MPFloatingActionButton.js +1 -1
  43. package/dist/components/footer/MPFooter.d.ts +94 -0
  44. package/dist/components/footer/MPFooter.js +2 -0
  45. package/dist/components/footer/index.d.ts +2 -0
  46. package/dist/components/footer/index.js +1 -0
  47. package/dist/components/form/MPForm.d.ts +73 -0
  48. package/dist/components/form/MPForm.js +2 -0
  49. package/dist/components/form/index.d.ts +2 -0
  50. package/dist/components/form/index.js +1 -0
  51. package/dist/components/header/MPHeader.d.ts +122 -0
  52. package/dist/components/header/MPHeader.js +2 -0
  53. package/dist/components/header/index.d.ts +2 -0
  54. package/dist/components/header/index.js +1 -0
  55. package/dist/components/highlight/MPHighlight.d.ts +7 -0
  56. package/dist/components/menu/MPMenu.d.ts +4 -2
  57. package/dist/components/menu/MPMenu.js +1 -1
  58. package/dist/components/menubar/MPMenubar.d.ts +89 -0
  59. package/dist/components/menubar/MPMenubar.js +2 -0
  60. package/dist/components/menubar/index.d.ts +2 -0
  61. package/dist/components/menubar/index.js +1 -0
  62. package/dist/components/navigation-menu/MPNavigationMenu.d.ts +158 -0
  63. package/dist/components/navigation-menu/MPNavigationMenu.js +2 -0
  64. package/dist/components/navigation-menu/index.d.ts +2 -0
  65. package/dist/components/navigation-menu/index.js +1 -0
  66. package/dist/components/number-field/MPNumberField.d.ts +19 -4
  67. package/dist/components/number-field/MPNumberField.js +1 -1
  68. package/dist/components/overlay/MPOverlay.d.ts +8 -2
  69. package/dist/components/overlay/MPOverlay.js +1 -1
  70. package/dist/components/page-layout/MPPageLayout.d.ts +145 -0
  71. package/dist/components/page-layout/MPPageLayout.js +2 -0
  72. package/dist/components/page-layout/index.d.ts +2 -0
  73. package/dist/components/page-layout/index.js +1 -0
  74. package/dist/components/panes/MPPanes.js +1 -1
  75. package/dist/components/popover/MPPopover.js +1 -1
  76. package/dist/components/progress-box/MPProgressBox.js +1 -1
  77. package/dist/components/progress-circular/MPProgressCircular.js +1 -1
  78. package/dist/components/progress-linear/MPProgressLinear.js +1 -1
  79. package/dist/components/radio-group/MPRadioGroup.d.ts +12 -0
  80. package/dist/components/radio-group/MPRadioGroup.js +1 -1
  81. package/dist/components/segmented-button/MPSegmentedButton.d.ts +7 -0
  82. package/dist/components/segmented-button/MPSegmentedButton.js +1 -1
  83. package/dist/components/select/MPSelect.d.ts +19 -1
  84. package/dist/components/select/MPSelect.js +1 -1
  85. package/dist/components/shortcut/MPShortcut.js +1 -1
  86. package/dist/components/sidebar/MPSidebar.d.ts +160 -0
  87. package/dist/components/sidebar/MPSidebar.js +2 -0
  88. package/dist/components/sidebar/MPSidebarTrigger.d.ts +45 -0
  89. package/dist/components/sidebar/MPSidebarTrigger.js +2 -0
  90. package/dist/components/sidebar/index.d.ts +4 -0
  91. package/dist/components/sidebar/index.js +1 -0
  92. package/dist/components/skeleton/MPSkeleton.js +1 -1
  93. package/dist/components/slider/MPSlider.d.ts +6 -0
  94. package/dist/components/slider/MPSlider.js +1 -1
  95. package/dist/components/snackbar/MPSnackbar.js +1 -1
  96. package/dist/components/switch/MPSwitch.d.ts +6 -0
  97. package/dist/components/switch/MPSwitch.js +1 -1
  98. package/dist/components/table/MPTable.d.ts +27 -5
  99. package/dist/components/table/MPTable.js +1 -1
  100. package/dist/components/text-field/MPTextField.d.ts +21 -2
  101. package/dist/components/text-field/MPTextField.js +1 -1
  102. package/dist/components/text-link/MPTextLink.d.ts +7 -1
  103. package/dist/components/text-link/MPTextLink.js +1 -1
  104. package/dist/components/time-picker/MPTimePicker.d.ts +4 -0
  105. package/dist/components/toggle/MPToggle.d.ts +72 -0
  106. package/dist/components/toggle/MPToggle.js +2 -0
  107. package/dist/components/toggle/index.d.ts +2 -0
  108. package/dist/components/toggle/index.js +1 -0
  109. package/dist/components/toggle-group/MPToggleGroup.d.ts +74 -0
  110. package/dist/components/toggle-group/MPToggleGroup.js +2 -0
  111. package/dist/components/toggle-group/index.d.ts +2 -0
  112. package/dist/components/toggle-group/index.js +1 -0
  113. package/dist/components/tooltip/MPTooltip.js +1 -1
  114. package/dist/components/transfer/MPTransfer.d.ts +98 -0
  115. package/dist/components/transfer/MPTransfer.js +2 -0
  116. package/dist/components/transfer/index.d.ts +2 -0
  117. package/dist/components/transfer/index.js +1 -0
  118. package/dist/constants/glyphs.d.ts +10 -0
  119. package/dist/constants/glyphs.js +1 -1
  120. package/dist/constants/icons.d.ts +1 -0
  121. package/dist/constants/icons.js +1 -1
  122. package/dist/index.d.ts +13 -0
  123. package/dist/index.js +1 -1
  124. package/dist/internal/Calendar.js +1 -1
  125. package/dist/internal/FieldOutline.js +1 -1
  126. package/dist/internal/SupportingText.d.ts +1 -1
  127. package/dist/internal/SupportingText.js +1 -1
  128. package/dist/internal/animate.d.ts +0 -17
  129. package/dist/internal/animate.js +1 -1
  130. package/dist/internal/avatar-group.d.ts +22 -0
  131. package/dist/internal/avatar-group.js +2 -0
  132. package/dist/internal/button-group.d.ts +20 -1
  133. package/dist/internal/button-group.js +1 -1
  134. package/dist/internal/color.d.ts +0 -5
  135. package/dist/internal/color.js +1 -1
  136. package/dist/internal/date.js +1 -1
  137. package/dist/internal/i18n.d.ts +201 -4
  138. package/dist/internal/keys.d.ts +72 -0
  139. package/dist/internal/keys.js +2 -0
  140. package/dist/internal/length.d.ts +42 -0
  141. package/dist/internal/length.js +1 -0
  142. package/dist/internal/link.d.ts +44 -0
  143. package/dist/internal/link.js +1 -0
  144. package/dist/internal/locale.d.ts +20 -1
  145. package/dist/internal/locale.js +1 -1
  146. package/dist/internal/messages/breadcrumb.d.ts +3 -0
  147. package/dist/internal/messages/breadcrumb.js +1 -0
  148. package/dist/internal/messages/carousel.d.ts +3 -0
  149. package/dist/internal/messages/carousel.js +1 -0
  150. package/dist/internal/messages/color-picker.d.ts +3 -0
  151. package/dist/internal/messages/color-picker.js +1 -0
  152. package/dist/internal/messages/combobox.d.ts +3 -0
  153. package/dist/internal/messages/combobox.js +1 -0
  154. package/dist/internal/messages/command.d.ts +3 -0
  155. package/dist/internal/messages/command.js +1 -0
  156. package/dist/internal/messages/file-picker.d.ts +3 -0
  157. package/dist/internal/messages/file-picker.js +1 -0
  158. package/dist/internal/messages/layout.d.ts +3 -0
  159. package/dist/internal/messages/layout.js +1 -0
  160. package/dist/internal/messages/number-field.d.ts +3 -0
  161. package/dist/internal/messages/number-field.js +1 -0
  162. package/dist/internal/messages/overlay.d.ts +3 -0
  163. package/dist/internal/messages/overlay.js +1 -0
  164. package/dist/internal/messages/table.d.ts +3 -0
  165. package/dist/internal/messages/table.js +1 -0
  166. package/dist/internal/messages/text-link.d.ts +3 -0
  167. package/dist/internal/messages/text-link.js +1 -0
  168. package/dist/internal/messages/transfer.d.ts +3 -0
  169. package/dist/internal/messages/transfer.js +1 -0
  170. package/dist/internal/page-layout.d.ts +182 -0
  171. package/dist/internal/page-layout.js +2 -0
  172. package/dist/internal/scale.d.ts +17 -0
  173. package/dist/internal/scale.js +1 -1
  174. package/dist/locales/ar.js +1 -1
  175. package/dist/locales/de.js +1 -1
  176. package/dist/locales/es.js +1 -1
  177. package/dist/locales/fr.js +1 -1
  178. package/dist/locales/hi.js +1 -1
  179. package/dist/locales/id.js +1 -1
  180. package/dist/locales/it.js +1 -1
  181. package/dist/locales/ja.js +1 -1
  182. package/dist/locales/ko.js +1 -1
  183. package/dist/locales/nl.js +1 -1
  184. package/dist/locales/pl.js +1 -1
  185. package/dist/locales/pt.js +1 -1
  186. package/dist/locales/ru.js +1 -1
  187. package/dist/locales/th.js +1 -1
  188. package/dist/locales/tr.js +1 -1
  189. package/dist/locales/vi.js +1 -1
  190. package/dist/locales/zh-hans.js +1 -1
  191. package/dist/locales/zh-hant.js +1 -1
  192. package/dist/styles/accordion.css +1 -1
  193. package/dist/styles/alert.css +1 -1
  194. package/dist/styles/avatar-group.css +2 -0
  195. package/dist/styles/avatar.css +1 -1
  196. package/dist/styles/badge.css +1 -1
  197. package/dist/styles/blockquote.css +1 -1
  198. package/dist/styles/bottom-navigation.css +1 -1
  199. package/dist/styles/box.css +1 -1
  200. package/dist/styles/breadcrumb.css +1 -1
  201. package/dist/styles/button-group.css +1 -1
  202. package/dist/styles/button.css +1 -1
  203. package/dist/styles/card.css +1 -1
  204. package/dist/styles/carousel.css +1 -1
  205. package/dist/styles/chat-bubble.css +1 -1
  206. package/dist/styles/checkbox.css +1 -1
  207. package/dist/styles/chip.css +1 -1
  208. package/dist/styles/collapsible.css +1 -1
  209. package/dist/styles/color-picker.css +1 -1
  210. package/dist/styles/combobox.css +1 -1
  211. package/dist/styles/command-palette.css +2 -0
  212. package/dist/styles/date-picker.css +1 -1
  213. package/dist/styles/date-range-picker.css +1 -1
  214. package/dist/styles/date-time-picker.css +1 -1
  215. package/dist/styles/dialog.css +1 -1
  216. package/dist/styles/divider.css +1 -1
  217. package/dist/styles/drawer.css +1 -1
  218. package/dist/styles/empty.css +1 -1
  219. package/dist/styles/fieldset.css +2 -0
  220. package/dist/styles/file-picker.css +1 -1
  221. package/dist/styles/floating-action-button.css +1 -1
  222. package/dist/styles/footer.css +2 -0
  223. package/dist/styles/form.css +2 -0
  224. package/dist/styles/header.css +2 -0
  225. package/dist/styles/highlight.css +1 -1
  226. package/dist/styles/icon-button.css +1 -1
  227. package/dist/styles/list.css +1 -1
  228. package/dist/styles/locale.css +1 -1
  229. package/dist/styles/menu.css +1 -1
  230. package/dist/styles/menubar.css +2 -0
  231. package/dist/styles/navigation-menu.css +2 -0
  232. package/dist/styles/number-field.css +1 -1
  233. package/dist/styles/otp-field.css +1 -1
  234. package/dist/styles/overlay.css +1 -1
  235. package/dist/styles/page-layout.css +2 -0
  236. package/dist/styles/pagination.css +1 -1
  237. package/dist/styles/panes.css +1 -1
  238. package/dist/styles/pill.css +1 -1
  239. package/dist/styles/popover.css +1 -1
  240. package/dist/styles/progress-box.css +1 -1
  241. package/dist/styles/progress-circular.css +1 -1
  242. package/dist/styles/progress-linear.css +1 -1
  243. package/dist/styles/radio-group.css +1 -1
  244. package/dist/styles/segmented-button.css +1 -1
  245. package/dist/styles/select.css +1 -1
  246. package/dist/styles/sidebar.css +2 -0
  247. package/dist/styles/skeleton.css +1 -1
  248. package/dist/styles/slider.css +1 -1
  249. package/dist/styles/spoiler.css +1 -1
  250. package/dist/styles/switch.css +1 -1
  251. package/dist/styles/table.css +1 -1
  252. package/dist/styles/tabs.css +1 -1
  253. package/dist/styles/text-field.css +1 -1
  254. package/dist/styles/text-link.css +1 -1
  255. package/dist/styles/time-picker.css +1 -1
  256. package/dist/styles/timeline.css +1 -1
  257. package/dist/styles/toggle-group.css +2 -0
  258. package/dist/styles/toggle.css +2 -0
  259. package/dist/styles/transfer.css +2 -0
  260. package/dist/styles.css +1 -1
  261. package/package.json +2 -2
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{jsx as r,Fragment as e,jsxs as t}from"react/jsx-runtime";import*as o from"react";import{Field as n}from"@base-ui/react/field";import{PROSE_TEXT as a}from"./scale.js";const i={xs:"left-1",sm:"left-2",md:"left-3",lg:"left-3",xl:"left-4"},s={xs:"top-[18px]",sm:"top-[18px]",md:"top-5",lg:"top-5",xl:"top-5"};function d(o,n){return t(e,{children:[o,n?r("span",{"aria-hidden":"true",children:" *"}):null]})}export function MPFieldOutline({label:e,required:t=!1,notched:o=!0}){return r("fieldset",{"aria-hidden":"true",className:["pointer-events-none absolute inset-0 -top-[5px] m-0 min-w-0 px-2 pt-0","rounded-mp-xs border border-mp-outline","transition-[border-color] duration-(--mp-sys-motion-duration-short4)","group-hover:border-mp-on-surface","group-focus-within:border-2 group-focus-within:border-mp-primary","group-data-focused:border-2 group-data-focused:border-mp-primary","group-data-invalid:border-mp-error","group-data-disabled:border-mp-on-surface/12"].join(" "),children:e?r("legend",{className:["text-mp-body-small invisible float-none block h-[11px] w-auto overflow-hidden p-0","leading-none","ease-mp-standard transition-[max-width,padding]","duration-(--mp-sys-motion-duration-short4)",o?"max-w-full px-1":"max-w-0 px-0"].join(" "),children:d(e,t)}):null})}export function MPFieldLabel({size:e,label:t,required:o=!1,htmlFor:p,shrunk:l=!0,multiline:u=!1}){return r(n.Label,{htmlFor:p,"data-mp-shrunk":l?"":void 0,className:["text-mp-on-surface-variant","ease-mp-standard transition-[color,top,font-size,max-width]","duration-(--mp-sys-motion-duration-short4)","absolute -translate-y-1/2 px-1 leading-none",i[e],l?"text-mp-body-small pointer-events-auto top-0 max-w-none":[a[e],"pointer-events-none max-w-[calc(100%-2rem)] truncate",u?s[e]:"top-1/2"].join(" "),"group-focus-within:text-mp-primary","group-data-focused:text-mp-primary","group-data-invalid:text-mp-error","group-data-disabled:text-mp-on-surface/38"].join(" "),children:d(t,o)})}export function useFloatingLabel({floating:r,filled:e,pinned:t=!1}){const[n,a]=o.useState(!1);return{shrunk:!r||e||n||t,focusProps:{onFocusCapture:()=>a(!0),onBlurCapture:r=>{r.currentTarget.contains(r.relatedTarget)||a(!1)}}}}
2
+ import{jsx as r,Fragment as t,jsxs as e}from"react/jsx-runtime";import*as o from"react";import{Field as a}from"@base-ui/react/field";import{PROSE_TEXT as n}from"./scale.js";const i={xs:"start-1",sm:"start-2",md:"start-3",lg:"start-3",xl:"start-4"},s={xs:"top-[18px]",sm:"top-[18px]",md:"top-5",lg:"top-5",xl:"top-5"};function d(o,a){return e(t,{children:[o,a?r("span",{"aria-hidden":"true",children:" *"}):null]})}export function MPFieldOutline({label:t,required:e=!1,notched:o=!0}){return r("fieldset",{"aria-hidden":"true",className:["pointer-events-none absolute inset-0 -top-[5px] m-0 min-w-0 px-2 pt-0","rounded-mp-xs border border-mp-outline","transition-[border-color] duration-(--mp-sys-motion-duration-short4)","group-hover:border-mp-on-surface","group-focus-within:border-2 group-focus-within:border-mp-primary","group-data-focused:border-2 group-data-focused:border-mp-primary","group-data-invalid:border-mp-error","group-data-disabled:border-mp-on-surface/12"].join(" "),children:t?r("legend",{className:["text-mp-body-small invisible float-none block h-[11px] w-auto overflow-hidden p-0","leading-none","ease-mp-standard transition-[max-width,padding]","duration-(--mp-sys-motion-duration-short4)",o?"max-w-full px-1":"max-w-0 px-0"].join(" "),children:d(t,e)}):null})}export function MPFieldLabel({size:t,label:e,required:o=!1,htmlFor:p,shrunk:u=!0,multiline:l=!1}){return r(a.Label,{htmlFor:p,"data-mp-shrunk":u?"":void 0,className:["text-mp-on-surface-variant","ease-mp-standard transition-[color,top,font-size,max-width]","duration-(--mp-sys-motion-duration-short4)","absolute -translate-y-1/2 px-1 leading-none",i[t],u?"text-mp-body-small pointer-events-auto top-0 max-w-none":[n[t],"pointer-events-none max-w-[calc(100%-2rem)] truncate",l?s[t]:"top-1/2"].join(" "),"group-focus-within:text-mp-primary","group-data-focused:text-mp-primary","group-data-invalid:text-mp-error","group-data-disabled:text-mp-on-surface/38"].join(" "),children:d(e,o)})}export function useFloatingLabel({floating:r,filled:t,pinned:e=!1}){const[a,n]=o.useState(!1);return{shrunk:!r||t||a||e,focusProps:{onFocusCapture:()=>n(!0),onBlurCapture:r=>{r.currentTarget.contains(r.relatedTarget)||n(!1)}}}}
@@ -20,4 +20,4 @@ export declare function MPSupportingText({ description, errorMessage, className
20
20
  errorMessage?: React.ReactNode;
21
21
  /** Whatever inset lines the text up with the control it belongs to. */
22
22
  className?: string;
23
- }): React.JSX.Element | null;
23
+ }): React.JSX.Element;
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{jsx as r}from"react/jsx-runtime";import{Field as e}from"@base-ui/react/field";import{META_TEXT as t,hasContent as o}from"./scale.js";export function MPSupportingText({description:a,errorMessage:s,className:i}){const n=["mp-supporting-text block",t,"data-disabled:text-mp-on-surface/38",i??""].filter(Boolean).join(" ");return o(s)?r(e.Error,{match:!0,className:`${n} text-mp-error`,children:s}):o(a)?r(e.Description,{className:`${n} text-mp-on-surface-variant`,children:a}):null}
2
+ import{jsx as r}from"react/jsx-runtime";import{Field as e}from"@base-ui/react/field";import{META_TEXT as t,hasContent as o}from"./scale.js";export function MPSupportingText({description:a,errorMessage:s,className:i}){const c=["mp-supporting-text block",t,"data-disabled:text-mp-on-surface/38",i??""].filter(Boolean).join(" ");return o(s)?r(e.Error,{match:!0,className:`${c} text-mp-error`,children:s}):o(a)?r(e.Description,{className:`${c} text-mp-on-surface-variant`,children:a}):r(e.Error,{className:`${c} text-mp-error`})}
@@ -52,28 +52,11 @@ export declare const ANIM_BASE = "mp-anim";
52
52
  export declare const ANIMATION_CLASS: Record<MPAnimation, string>;
53
53
  /** A curve, as the stylesheet spells it. */
54
54
  export declare function easingValue(easing: MPEasing): string;
55
- /**
56
- * A duration, as the stylesheet spells it.
57
- *
58
- * A number is milliseconds and lands as milliseconds. Nothing at all lands as
59
- * the effect's own Material token, so a page that retunes its motion moves this
60
- * animation with it.
61
- */
62
- export declare function durationValue(duration: number | undefined, effect: MPAnimation, mode?: MPAnimateMode): string;
63
55
  /** A number is pixels; a string is already a CSS length. */
64
56
  export declare function lengthValue(value: number | string): string;
65
57
  /** `'infinite'` reaches CSS as the word; a count reaches it as the number. */
66
58
  export declare function repeatValue(repeat: MPAnimateRepeat): string;
67
59
  export declare function isInfinite(repeat: MPAnimateRepeat | undefined): boolean;
68
- /**
69
- * `normal`, `reverse`, `alternate`, `alternate-reverse` — the four CSS already
70
- * has, assembled from the two props that mean something to a caller.
71
- *
72
- * `mode="out"` is a reversed run rather than a keyframe of its own, which is
73
- * also why a reversed animation ends held on its own first frame: `fill-mode`
74
- * is `both`, so a faded-out element stays faded out instead of snapping back.
75
- */
76
- export declare function directionValue(mode: MPAnimateMode, alternate: boolean | undefined): string;
77
60
  export interface AnimationSlotOptions {
78
61
  /** Which effect's tokens to fall back to, and which keyframe to run. */
79
62
  effect: MPAnimation;
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import*as e from"react";export const ANIM_BASE="mp-anim";export const ANIMATION_CLASS={fade:"mp-anim-fade",grow:"mp-anim-scale",slide:"mp-anim-slide",zoom:"mp-anim-scale",rotate:"mp-anim-rotate",blink:"mp-anim-blink"};const n={fade:{in:"medium2",out:"short4"},grow:{in:"medium4",out:"short4"},slide:{in:"medium4",out:"short4"},zoom:{in:"medium4",out:"short4"},rotate:{in:"long2",out:"medium2"},blink:{in:"extra-long4",out:"extra-long4"}},t={fade:"emphasized-decelerate",grow:"emphasized-decelerate",slide:"emphasized-decelerate",zoom:"emphasized-decelerate",rotate:"emphasized-decelerate",blink:"standard"};export function easingValue(e){return`var(--mp-sys-motion-easing-${e})`}export function durationValue(e,t,i="in"){return void 0!==e?`${e}ms`:`var(--mp-sys-motion-duration-${n[t][i]})`}export function lengthValue(e){return"number"==typeof e?`${e}px`:e}export function repeatValue(e){return"infinite"===e?"infinite":String(e)}export function isInfinite(e){return"infinite"===e}export function directionValue(e,n){return"out"===e?n?"alternate-reverse":"reverse":n?"alternate":"normal"}export function animationSlots(e){const n=e.mode??"in",i={"--_mp-anim-duration":durationValue(e.duration,e.effect,n),"--_mp-anim-delay":`${e.delay}ms`,"--_mp-anim-ease":easingValue(e.easing??t[e.effect]),"--_mp-anim-repeat":repeatValue(e.repeat),"--_mp-anim-direction":directionValue(n,e.alternate)};return void 0!==e.opacity&&(i["--_mp-anim-opacity"]=String(e.opacity)),void 0!==e.scale&&(i["--_mp-anim-scale"]=String(e.scale)),void 0!==e.x&&(i["--_mp-anim-x"]=e.x),void 0!==e.y&&(i["--_mp-anim-y"]=e.y),void 0!==e.angle&&(i["--_mp-anim-angle"]=e.angle),void 0!==e.angleTo&&(i["--_mp-anim-angle-to"]=e.angleTo),i}export function slideOffsets(e,n){const t=lengthValue(n),i="number"==typeof n?-n+"px":`calc(-1 * ${t})`;switch(e){case"top":return{x:"0px",y:i};case"bottom":return{x:"0px",y:t};case"left":return{x:i,y:"0px"};default:return{x:t,y:"0px"}}}const i="(prefers-reduced-motion: reduce)";function a(e){if("undefined"==typeof window||!window.matchMedia)return()=>{};const n=window.matchMedia(i);return n.addEventListener("change",e),()=>n.removeEventListener("change",e)}function r(){return!("undefined"==typeof window||!window.matchMedia)&&window.matchMedia(i).matches}function o(){return!1}export function usePrefersReducedMotion(){return e.useSyncExternalStore(a,r,o)}export function useAnimationRun({trigger:n,play:t,once:i,threshold:a,paused:r,infinite:o}){const s=e.useRef(null),[u,m]=e.useState("mount"===n),[c,d]=e.useState(0),l=e.useCallback(()=>{m(!0),d(e=>e+1)},[]);e.useLayoutEffect(()=>{const e=s.current;if(!e||0===c)return;const n=[e,...e.querySelectorAll(".mp-anim, .mp-marquee-track")];for(const e of n)e.style.animationName="none";e.offsetWidth;for(const e of n)e.style.animationName=""},[c]),e.useEffect(()=>{if("visible"!==n)return;const e=s.current;if(!e||"undefined"==typeof IntersectionObserver)return void m(!0);const t=new IntersectionObserver(([e])=>{e.isIntersecting?(l(),i&&t.disconnect()):i||m(!1)},{threshold:a});return t.observe(e),()=>t.disconnect()},[n,i,a,l]),e.useEffect(()=>{"manual"===n&&(t?l():m(!1))},[n,t,l]);const p=e.useCallback(()=>{o&&m(!1)},[o]),f="hover"===n?{onPointerEnter:l,onFocus:l,onPointerLeave:p,onBlur:p}:{};return{ref:e.useCallback(e=>{s.current=e},[]),state:u&&!r?"running":"paused",started:u,handlers:f}}export function useAnimateElement(e){const{trigger:n,play:t,once:i,threshold:a,paused:r,infinite:o,...s}=e,u=useAnimationRun({trigger:n,play:t,once:i,threshold:a,paused:r,infinite:o});return{ref:u.ref,className:`mp-anim ${ANIMATION_CLASS[s.effect]}`,style:{...animationSlots(s),"--_mp-anim-state":u.state},props:{...u.handlers,"data-mp-animation":s.effect,"data-mp-state":u.state}}}
2
+ import*as e from"react";export const ANIM_BASE="mp-anim";export const ANIMATION_CLASS={fade:"mp-anim-fade",grow:"mp-anim-scale",slide:"mp-anim-slide",zoom:"mp-anim-scale",rotate:"mp-anim-rotate",blink:"mp-anim-blink"};const n={fade:{in:"medium2",out:"short4"},grow:{in:"medium4",out:"short4"},slide:{in:"medium4",out:"short4"},zoom:{in:"medium4",out:"short4"},rotate:{in:"long2",out:"medium2"},blink:{in:"extra-long4",out:"extra-long4"}},t={fade:"emphasized-decelerate",grow:"emphasized-decelerate",slide:"emphasized-decelerate",zoom:"emphasized-decelerate",rotate:"emphasized-decelerate",blink:"standard"};export function easingValue(e){return`var(--mp-sys-motion-easing-${e})`}function i(e,t,i="in"){return void 0!==e?`${e}ms`:`var(--mp-sys-motion-duration-${n[t][i]})`}export function lengthValue(e){return"number"==typeof e?`${e}px`:e}export function repeatValue(e){return"infinite"===e?"infinite":String(e)}export function isInfinite(e){return"infinite"===e}function a(e,n){return"out"===e?n?"alternate-reverse":"reverse":n?"alternate":"normal"}export function animationSlots(e){const n=e.mode??"in",r={"--_mp-anim-duration":i(e.duration,e.effect,n),"--_mp-anim-delay":`${e.delay}ms`,"--_mp-anim-ease":easingValue(e.easing??t[e.effect]),"--_mp-anim-repeat":repeatValue(e.repeat),"--_mp-anim-direction":a(n,e.alternate)};return void 0!==e.opacity&&(r["--_mp-anim-opacity"]=String(e.opacity)),void 0!==e.scale&&(r["--_mp-anim-scale"]=String(e.scale)),void 0!==e.x&&(r["--_mp-anim-x"]=e.x),void 0!==e.y&&(r["--_mp-anim-y"]=e.y),void 0!==e.angle&&(r["--_mp-anim-angle"]=e.angle),void 0!==e.angleTo&&(r["--_mp-anim-angle-to"]=e.angleTo),r}export function slideOffsets(e,n){const t=lengthValue(n),i="number"==typeof n?-n+"px":`calc(-1 * ${t})`;switch(e){case"top":return{x:"0px",y:i};case"bottom":return{x:"0px",y:t};case"left":return{x:i,y:"0px"};default:return{x:t,y:"0px"}}}const r="(prefers-reduced-motion: reduce)";function o(e){if("undefined"==typeof window||!window.matchMedia)return()=>{};const n=window.matchMedia(r);return n.addEventListener("change",e),()=>n.removeEventListener("change",e)}function s(){return!("undefined"==typeof window||!window.matchMedia)&&window.matchMedia(r).matches}function m(){return!1}export function usePrefersReducedMotion(){return e.useSyncExternalStore(o,s,m)}export function useAnimationRun({trigger:n,play:t,once:i,threshold:a,paused:r,infinite:o}){const s=e.useRef(null),[m,u]=e.useState("mount"===n),[c,d]=e.useState(0),l=e.useCallback(()=>{u(!0),d(e=>e+1)},[]);e.useLayoutEffect(()=>{const e=s.current;if(!e||0===c)return;const n=[e,...e.querySelectorAll(".mp-anim, .mp-marquee-track")];for(const e of n)e.style.animationName="none";e.offsetWidth;for(const e of n)e.style.animationName=""},[c]),e.useEffect(()=>{if("visible"!==n)return;const e=s.current;if(!e||"undefined"==typeof IntersectionObserver)return void u(!0);const t=new IntersectionObserver(([e])=>{e.isIntersecting?(l(),i&&t.disconnect()):i||u(!1)},{threshold:a});return t.observe(e),()=>t.disconnect()},[n,i,a,l]),e.useEffect(()=>{"manual"===n&&(t?l():u(!1))},[n,t,l]);const p=e.useCallback(()=>{o&&u(!1)},[o]),f="hover"===n?{onPointerEnter:l,onFocus:l,onPointerLeave:p,onBlur:p}:{};return{ref:e.useCallback(e=>{s.current=e},[]),state:m&&!r?"running":"paused",started:m,handlers:f}}export function useAnimateElement(e){const{trigger:n,play:t,once:i,threshold:a,paused:r,infinite:o,...s}=e,m=useAnimationRun({trigger:n,play:t,once:i,threshold:a,paused:r,infinite:o});return{ref:m.ref,className:`mp-anim ${ANIMATION_CLASS[s.effect]}`,style:{...animationSlots(s),"--_mp-anim-state":m.state},props:{...m.handlers,"data-mp-animation":s.effect,"data-mp-state":m.state}}}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * What an avatar inherits from the stack around it.
3
+ *
4
+ * Its own module rather than a file `MPAvatarGroup` exports, for the reason
5
+ * `button-group.ts` gives: both sides import it — the group provides the
6
+ * context and the avatar reads it — so putting it in either component would
7
+ * make one of them pull in the other, and an `MPAvatar` that dragged a group
8
+ * nobody used into the bundle is dead weight on every page with a face on it.
9
+ *
10
+ * Every field is optional and every one of them may legitimately be `undefined`.
11
+ * An avatar reads the group as a *fallback*, so "not set on the group" has to
12
+ * keep meaning "use the avatar's own default" rather than turning into one.
13
+ */
14
+ import * as React from 'react';
15
+ import type { MPColor, MPSize, MPVariant } from '../types.js';
16
+ export interface MPAvatarGroupContextValue {
17
+ size?: MPSize;
18
+ shape?: 'circle' | 'square';
19
+ variant?: MPVariant;
20
+ color?: MPColor;
21
+ }
22
+ export declare const MPAvatarGroupContext: React.Context<MPAvatarGroupContextValue | null>;
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import*as t from"react";export const MPAvatarGroupContext=/*@__PURE__*/t.createContext(null);
@@ -11,7 +11,7 @@
11
11
  * meaning "use the button's own default" rather than turning into one.
12
12
  */
13
13
  import * as React from 'react';
14
- import type { MPColor, MPSize, MPVariant } from '../types.js';
14
+ import type { MPColor, MPOrientation, MPSize, MPVariant } from '../types.js';
15
15
  export interface MPButtonGroupContextValue {
16
16
  variant?: MPVariant;
17
17
  size?: MPSize;
@@ -19,3 +19,22 @@ export interface MPButtonGroupContextValue {
19
19
  disabled?: boolean;
20
20
  }
21
21
  export declare const MPButtonGroupContext: React.Context<MPButtonGroupContextValue | null>;
22
+ /**
23
+ * The corners that face a neighbour.
24
+ *
25
+ * MD3's connected button group keeps the run's *outer* corners fully round and
26
+ * cuts the inner ones back to `corner-small`, so the row reads as one shape that
27
+ * has been divided rather than as three pills that happen to be adjacent. The
28
+ * seam is a 2px gap rather than a border, which is what lets a filled group work
29
+ * at all: two filled buttons sharing an edge merge into one blob, and a hairline
30
+ * between them would be the only line on the page drawn between two fills.
31
+ *
32
+ * Logical properties (`s`/`e`) rather than left/right: under RTL the first
33
+ * button is on the right, and `rounded-l-none` would flatten the wrong side.
34
+ *
35
+ * It is here rather than in `MPButtonGroup`, which was its first reader, because
36
+ * `MPToggleGroup` is a connected run of exactly the same shape — and two copies
37
+ * of one table is how a run of toggles ends up cut differently from a run of
38
+ * buttons beside it.
39
+ */
40
+ export declare const GROUP_JOIN: Record<MPOrientation, string>;
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import*as t from"react";export const MPButtonGroupContext=/*@__PURE__*/t.createContext(null);
2
+ import*as t from"react";export const MPButtonGroupContext=/*@__PURE__*/t.createContext(null);export const GROUP_JOIN={horizontal:"[&>*:not(:first-child)]:rounded-s-mp-sm [&>*:not(:last-child)]:rounded-e-mp-sm",vertical:"[&>*:not(:first-child)]:rounded-t-mp-sm [&>*:not(:last-child)]:rounded-b-mp-sm"};
@@ -58,10 +58,6 @@ export interface MPColorValue {
58
58
  /** The three ways the picker will write a colour back out. */
59
59
  export type MPColorFormat = 'hex' | 'rgb' | 'hsl';
60
60
  export declare function clamp(value: number, min: number, max: number): number;
61
- export declare function hsvToRgb({ h, s, v }: MPHsv): MPRgb;
62
- export declare function rgbToHsv({ r, g, b }: MPRgb): MPHsv;
63
- export declare function rgbToHsl({ r, g, b }: MPRgb): MPHsl;
64
- export declare function hslToRgb({ h, s, l }: MPHsl): MPRgb;
65
61
  /**
66
62
  * A CSS colour string, or `null` if it is not one this understands.
67
63
  *
@@ -71,7 +67,6 @@ export declare function hslToRgb({ h, s, l }: MPHsl): MPRgb;
71
67
  * honest way back from `rebeccapurple` to a point on the panel.
72
68
  */
73
69
  export declare function parseColor(input: string): MPColorValue | null;
74
- export declare function rgbToHex({ r, g, b }: MPRgb, alpha?: number): string;
75
70
  /**
76
71
  * The value the component hands back, in whichever notation was asked for.
77
72
  *
@@ -1 +1 @@
1
- export function clamp(r,t,n){return r<t?t:r>n?n:r}function r(r){const t=r%360;return t<0?t+360:t}export function hsvToRgb({h:t,s:n,v:o}){const e=r(t)/60,a=clamp(n,0,100)/100,s=clamp(o,0,100)/100,c=s*a,l=c*(1-Math.abs(e%2-1)),u=s-c,i=Math.floor(e)%6,[g,h,f]=[[c,l,0],[l,c,0],[0,c,l],[0,l,c],[l,0,c],[c,0,l]][i];return{r:Math.round(255*(g+u)),g:Math.round(255*(h+u)),b:Math.round(255*(f+u))}}export function rgbToHsv({r:t,g:n,b:o}){const e=clamp(t,0,255)/255,a=clamp(n,0,255)/255,s=clamp(o,0,255)/255,c=Math.max(e,a,s),l=c-Math.min(e,a,s);let u=0;return 0!==l&&(u=c===e?(a-s)/l%6:c===a?(s-e)/l+2:(e-a)/l+4),{h:r(60*u),s:0===c?0:l/c*100,v:100*c}}export function rgbToHsl({r:r,g:t,b:n}){const{h:o,s:e,v:a}=rgbToHsv({r:r,g:t,b:n}),s=a/100,c=s*(1-e/100/2),l=Math.min(c,1-c);return{h:o,s:0===l?0:(s-c)/l*100,l:100*c}}export function hslToRgb({h:r,s:t,l:n}){const o=clamp(n,0,100)/100,e=o+clamp(t,0,100)/100*Math.min(o,1-o);return hsvToRgb({h:r,s:0===e?0:2*(1-o/e)*100,v:100*e})}const t=/^#?([0-9a-f]{3,8})$/i;export function parseColor(r){const n=r.trim().toLowerCase();if(!n)return null;if(n.startsWith("#")||t.test(n))return function(r){const n=t.exec(r.trim());if(!n)return null;const o=n[1],e=3===o.length||4===o.length?[...o].map(r=>r+r).join(""):o;if(6!==e.length&&8!==e.length)return null;const a=r=>parseInt(e.slice(2*r,2*r+2),16);return{hsv:rgbToHsv({r:a(0),g:a(1),b:a(2)}),alpha:8===e.length?a(3)/255:1}}(n);const o=/^(rgba?|hsla?)\((.*)\)$/.exec(n);if(!o)return null;const[,e,a]=o,s=function(r){return r.match(/-?[\d.]+%?/g)??[]}(a),c=s.map(r=>parseFloat(r));if(c.length<3||c.some(Number.isNaN))return null;const l=function(r,t){return t.length<=3?1:clamp(r[3]?.endsWith("%")?t[3]/100:t[3],0,1)}(s,c);return e.startsWith("rgb")?{hsv:rgbToHsv({r:c[0],g:c[1],b:c[2]}),alpha:l}:{hsv:rgbToHsv(hslToRgb({h:c[0],s:c[1],l:c[2]})),alpha:l}}function n(r){return clamp(Math.round(r),0,255).toString(16).padStart(2,"0")}export function rgbToHex({r:r,g:t,b:o},e=1){const a=`#${n(r)}${n(t)}${n(o)}`;return e>=1?a:`${a}${n(255*e)}`}function o(r){return String(Math.round(100*clamp(r,0,1))/100)}export function formatColor(r,t,n){const e=hsvToRgb(r);if("hex"===n)return rgbToHex(e,t);if("rgb"===n){const r=`${e.r}, ${e.g}, ${e.b}`;return t>=1?`rgb(${r})`:`rgba(${r}, ${o(t)})`}const{h:a,s:s,l:c}=rgbToHsl(e),l=`${Math.round(a)}, ${Math.round(s)}%, ${Math.round(c)}%`;return t>=1?`hsl(${l})`:`hsla(${l}, ${o(t)})`}export function cssColor(r,t=1){const{r:n,g:e,b:a}=hsvToRgb(r);return t>=1?`rgb(${n}, ${e}, ${a})`:`rgba(${n}, ${e}, ${a}, ${o(t)})`}export function readableInk(r){const{r:t,g:n,b:o}=hsvToRgb(r),e=r=>{const t=r/255;return t<=.03928?t/12.92:((t+.055)/1.055)**2.4};return.2126*e(t)+.7152*e(n)+.0722*e(o)>.42?"#000000":"#ffffff"}export const DEFAULT_SWATCHES=["#000000","#4b5563","#9ca3af","#ffffff","#ef4444","#f97316","#f59e0b","#84cc16","#22c55e","#14b8a6","#06b6d4","#3b82f6","#6366f1","#8b5cf6","#d946ef","#ec4899"];export const CHECKER_BACKGROUND={backgroundImage:"linear-gradient(45deg, var(--_mp-color-outline-variant) 25%, transparent 25%), linear-gradient(-45deg, var(--_mp-color-outline-variant) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--_mp-color-outline-variant) 75%), linear-gradient(-45deg, transparent 75%, var(--_mp-color-outline-variant) 75%)",backgroundSize:"8px 8px",backgroundPosition:"0 0, 0 4px, 4px -4px, -4px 0"};
1
+ export function clamp(n,t,r){return n<t?t:n>r?r:n}function n(n){const t=n%360;return t<0?t+360:t}function t({h:t,s:r,v:a}){const o=n(t)/60,e=clamp(r,0,100)/100,c=clamp(a,0,100)/100,u=c*e,l=u*(1-Math.abs(o%2-1)),i=c-u,s=Math.floor(o)%6,[f,h,p]=[[u,l,0],[l,u,0],[0,u,l],[0,l,u],[l,0,u],[u,0,l]][s];return{r:Math.round(255*(f+i)),g:Math.round(255*(h+i)),b:Math.round(255*(p+i))}}function r({r:t,g:r,b:a}){const o=clamp(t,0,255)/255,e=clamp(r,0,255)/255,c=clamp(a,0,255)/255,u=Math.max(o,e,c),l=u-Math.min(o,e,c);let i=0;return 0!==l&&(i=u===o?(e-c)/l%6:u===e?(c-o)/l+2:(o-e)/l+4),{h:n(60*i),s:0===u?0:l/u*100,v:100*u}}function a({h:n,s:r,l:a}){const o=clamp(a,0,100)/100,e=o+clamp(r,0,100)/100*Math.min(o,1-o);return t({h:n,s:0===e?0:2*(1-o/e)*100,v:100*e})}const o=/^#?([0-9a-f]{3,8})$/i;export function parseColor(n){const t=n.trim().toLowerCase();if(!t)return null;if(t.startsWith("#")||o.test(t))return function(n){const t=o.exec(n.trim());if(!t)return null;const a=t[1],e=3===a.length||4===a.length?[...a].map(n=>n+n).join(""):a;if(6!==e.length&&8!==e.length)return null;const c=n=>parseInt(e.slice(2*n,2*n+2),16);return{hsv:r({r:c(0),g:c(1),b:c(2)}),alpha:8===e.length?c(3)/255:1}}(t);const e=/^(rgba?|hsla?)\((.*)\)$/.exec(t);if(!e)return null;const[,c,u]=e,l=function(n){return n.match(/-?[\d.]+%?/g)??[]}(u),i=l.map(n=>parseFloat(n));if(i.length<3||i.some(Number.isNaN))return null;const s=function(n,t){return t.length<=3?1:clamp(n[3]?.endsWith("%")?t[3]/100:t[3],0,1)}(l,i);return c.startsWith("rgb")?{hsv:r({r:i[0],g:i[1],b:i[2]}),alpha:s}:{hsv:r(a({h:i[0],s:i[1],l:i[2]})),alpha:s}}function e(n){return clamp(Math.round(n),0,255).toString(16).padStart(2,"0")}function c(n){return String(Math.round(100*clamp(n,0,1))/100)}export function formatColor(n,a,o){const u=t(n);if("hex"===o)return function({r:n,g:t,b:r},a=1){const o=`#${e(n)}${e(t)}${e(r)}`;return a>=1?o:`${o}${e(255*a)}`}(u,a);if("rgb"===o){const n=`${u.r}, ${u.g}, ${u.b}`;return a>=1?`rgb(${n})`:`rgba(${n}, ${c(a)})`}const{h:l,s:i,l:s}=function({r:n,g:t,b:a}){const{h:o,s:e,v:c}=r({r:n,g:t,b:a}),u=c/100,l=u*(1-e/100/2),i=Math.min(l,1-l);return{h:o,s:0===i?0:(u-l)/i*100,l:100*l}}(u),f=`${Math.round(l)}, ${Math.round(i)}%, ${Math.round(s)}%`;return a>=1?`hsl(${f})`:`hsla(${f}, ${c(a)})`}export function cssColor(n,r=1){const{r:a,g:o,b:e}=t(n);return r>=1?`rgb(${a}, ${o}, ${e})`:`rgba(${a}, ${o}, ${e}, ${c(r)})`}export function readableInk(n){const{r:r,g:a,b:o}=t(n),e=n=>{const t=n/255;return t<=.03928?t/12.92:((t+.055)/1.055)**2.4};return.2126*e(r)+.7152*e(a)+.0722*e(o)>.42?"#000000":"#ffffff"}export const DEFAULT_SWATCHES=["#000000","#4b5563","#9ca3af","#ffffff","#ef4444","#f97316","#f59e0b","#84cc16","#22c55e","#14b8a6","#06b6d4","#3b82f6","#6366f1","#8b5cf6","#d946ef","#ec4899"];export const CHECKER_BACKGROUND={backgroundImage:"linear-gradient(45deg, var(--_mp-color-outline-variant) 25%, transparent 25%), linear-gradient(-45deg, var(--_mp-color-outline-variant) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--_mp-color-outline-variant) 75%), linear-gradient(-45deg, transparent 75%, var(--_mp-color-outline-variant) 75%)",backgroundSize:"8px 8px",backgroundPosition:"0 0, 0 4px, 4px -4px, -4px 0"};
@@ -1 +1 @@
1
- export const YEAR_PAGE_SIZE=12;export function makeDate(t,e,r){const n=new Date(0);return n.setFullYear(t,e,r),n.setHours(0,0,0,0),n}export function isValidDate(t){return t instanceof Date&&!Number.isNaN(t.getTime())}export function startOfDay(t){const e=new Date(t.getTime());return e.setHours(0,0,0,0),e}export function startOfMonth(t){return makeDate(t.getFullYear(),t.getMonth(),1)}export function daysInMonth(t,e){return makeDate(t,e+1,0).getDate()}export function today(){return startOfDay(new Date)}export function addDays(t,e){const r=new Date(t.getTime());return r.setDate(r.getDate()+e),r}export function addMonths(t,e){const r=new Date(t.getTime()),n=makeDate(t.getFullYear(),t.getMonth()+e,1);return r.setFullYear(n.getFullYear(),n.getMonth(),Math.min(t.getDate(),daysInMonth(n.getFullYear(),n.getMonth()))),r}export function addYears(t,e){return addMonths(t,12*e)}export function compareDay(t,e){return startOfDay(t).getTime()-startOfDay(e).getTime()}export function isSameDay(t,e){return isValidDate(t)&&isValidDate(e)&&0===compareDay(t,e)}export function isSameMonth(t,e){return isValidDate(t)&&isValidDate(e)&&t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()}export function isDayOutside(t,e,r){return!!(isValidDate(e)&&compareDay(t,e)<0)||isValidDate(r)&&compareDay(t,r)>0}export function secondsOfDay(t){return 3600*t.getHours()+60*t.getMinutes()+t.getSeconds()}export function timeUnitSpan(t,e){const r=secondsOfDay(e);if("hour"===t){const t=3600*Math.floor(r/3600);return[t,t+3599]}if("minute"===t){const t=60*Math.floor(r/60);return[t,t+59]}if("second"===t)return[r,r];const n=e.getHours()<12?0:43200;return[n,n+43200-1]}export function withTime(t,e){const r=new Date(t.getTime());return r.setHours(e.hours??r.getHours(),e.minutes??r.getMinutes(),e.seconds??r.getSeconds(),0),r}export function mergeDateAndTime(t,e){return withTime(startOfDay(t),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()})}export function calendarWeeks(t,e){const r=startOfMonth(t),n=(r.getDay()-e+7)%7,o=addDays(r,-n);return Array.from({length:6},(t,e)=>Array.from({length:7},(t,r)=>addDays(o,7*e+r)))}export function yearPageStart(t){return t-(t%12+12)%12}const t=new Map;export function dateFormatter(e,r){const n=`${e??""}\0${JSON.stringify(r)}`;let o=t.get(n);return o||(o=new Intl.DateTimeFormat(e,r),t.set(n,o)),o}export function formatDate(t,e,r){return isValidDate(t)?dateFormatter(e,r).format(t):""}const e=Array.from({length:24},(t,e)=>new Date(2027,e%12,21+e%7,e,58,58));export function displaySamples(t,r){const n=dateFormatter(t,r);return[...new Set(e.map(t=>n.format(t)))]}export function withPlaceholder(t,e){return"string"==typeof e&&""!==e?[...t,e]:t}export function toISODate(t){const e=t=>String(t).padStart(2,"0");return`${String(t.getFullYear()).padStart(4,"0")}-${e(t.getMonth()+1)}-${e(t.getDate())}`}export function toISOTime(t,e=!1){const r=t=>String(t).padStart(2,"0"),n=`${r(t.getHours())}:${r(t.getMinutes())}`;return e?`${n}:${r(t.getSeconds())}`:n}export function toISODateTime(t,e=!1){return`${toISODate(t)}T${toISOTime(t,e)}`}const r=makeDate(2021,7,1),n=new Map;export function weekdayLabels(t,e,o="narrow"){const a=`w ${t??""} ${e} ${o}`;let s=n.get(a);if(!s){const i=dateFormatter(t,{weekday:o});s=Array.from({length:7},(t,n)=>i.format(addDays(r,(e+n)%7))),n.set(a,s)}return s}export function monthLabels(t,e="short"){const r=`m ${t??""} ${e}`;let o=n.get(r);if(!o){const a=dateFormatter(t,{month:e});o=Array.from({length:12},(t,e)=>a.format(makeDate(2021,e,1))),n.set(r,o)}return o}export function isMonthBeforeYear(t){const e=dateFormatter(t,{year:"numeric",month:"long"}).formatToParts(r);return e.findIndex(t=>"month"===t.type)<e.findIndex(t=>"year"===t.type)}export function isHour12(t){const e=dateFormatter(t,{hour:"numeric"}).resolvedOptions();return e.hourCycle?"h11"===e.hourCycle||"h12"===e.hourCycle:!0===e.hour12}export function meridiemLabels(t){const e=dateFormatter(t,{hour:"numeric",hour12:!0}),n=t=>{const n=e.formatToParts(withTime(r,{hours:t})).find(t=>"dayPeriod"===t.type);return n?.value??(t<12?"AM":"PM")};return[n(9),n(21)]}export function localeWeekStart(t){try{const e=t??(new Intl.DateTimeFormat).resolvedOptions().locale,r=new Intl.Locale(e),n="function"==typeof r.getWeekInfo?r.getWeekInfo():r.weekInfo;if("number"==typeof n?.firstDay)return n.firstDay%7}catch{}return 0}
1
+ export const YEAR_PAGE_SIZE=12;export function makeDate(t,e,r){const n=new Date(0);return n.setFullYear(t,e,r),n.setHours(0,0,0,0),n}export function isValidDate(t){return t instanceof Date&&!Number.isNaN(t.getTime())}export function startOfDay(t){const e=new Date(t.getTime());return e.setHours(0,0,0,0),e}export function startOfMonth(t){return makeDate(t.getFullYear(),t.getMonth(),1)}export function daysInMonth(t,e){return makeDate(t,e+1,0).getDate()}export function today(){return startOfDay(new Date)}export function addDays(t,e){const r=new Date(t.getTime());return r.setDate(r.getDate()+e),r}export function addMonths(t,e){const r=new Date(t.getTime()),n=makeDate(t.getFullYear(),t.getMonth()+e,1);return r.setFullYear(n.getFullYear(),n.getMonth(),Math.min(t.getDate(),daysInMonth(n.getFullYear(),n.getMonth()))),r}export function addYears(t,e){return addMonths(t,12*e)}export function compareDay(t,e){return startOfDay(t).getTime()-startOfDay(e).getTime()}export function isSameDay(t,e){return isValidDate(t)&&isValidDate(e)&&0===compareDay(t,e)}export function isSameMonth(t,e){return isValidDate(t)&&isValidDate(e)&&t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()}export function isDayOutside(t,e,r){return!!(isValidDate(e)&&compareDay(t,e)<0)||isValidDate(r)&&compareDay(t,r)>0}export function secondsOfDay(t){return 3600*t.getHours()+60*t.getMinutes()+t.getSeconds()}export function timeUnitSpan(t,e){const r=secondsOfDay(e);if("hour"===t){const t=3600*Math.floor(r/3600);return[t,t+3599]}if("minute"===t){const t=60*Math.floor(r/60);return[t,t+59]}if("second"===t)return[r,r];const n=e.getHours()<12?0:43200;return[n,n+43200-1]}export function withTime(t,e){const r=new Date(t.getTime());return r.setHours(e.hours??r.getHours(),e.minutes??r.getMinutes(),e.seconds??r.getSeconds(),0),r}export function mergeDateAndTime(t,e){return withTime(startOfDay(t),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()})}export function calendarWeeks(t,e){const r=startOfMonth(t),n=(r.getDay()-e+7)%7,o=addDays(r,-n);return Array.from({length:6},(t,e)=>Array.from({length:7},(t,r)=>addDays(o,7*e+r)))}export function yearPageStart(t){return t-(t%12+12)%12}function t(t,e,r){if(t.set(e,r),t.size>64){const e=t.keys().next();e.done||t.delete(e.value)}return r}const e=new Map;export function dateFormatter(r,n){const o=`${r??""}\0${JSON.stringify(n)}`,a=e.get(o);return a||t(e,o,new Intl.DateTimeFormat(r,n))}export function formatDate(t,e,r){return isValidDate(t)?dateFormatter(e,r).format(t):""}const r=Array.from({length:24},(t,e)=>new Date(2027,e%12,21+e%7,e,58,58));export function displaySamples(t,e){const n=dateFormatter(t,e);return[...new Set(r.map(t=>n.format(t)))]}export function withPlaceholder(t,e){return"string"==typeof e&&""!==e?[...t,e]:t}export function toISODate(t){const e=t=>String(t).padStart(2,"0");return`${String(t.getFullYear()).padStart(4,"0")}-${e(t.getMonth()+1)}-${e(t.getDate())}`}export function toISOTime(t,e=!1){const r=t=>String(t).padStart(2,"0"),n=`${r(t.getHours())}:${r(t.getMinutes())}`;return e?`${n}:${r(t.getSeconds())}`:n}export function toISODateTime(t,e=!1){return`${toISODate(t)}T${toISOTime(t,e)}`}const n=makeDate(2021,7,1),o=new Map;export function weekdayLabels(e,r,a="narrow"){const u=`w ${e??""} ${r} ${a}`,i=o.get(u);if(i)return i;const s=dateFormatter(e,{weekday:a});return t(o,u,Array.from({length:7},(t,e)=>s.format(addDays(n,(r+e)%7))))}export function monthLabels(e,r="short"){const n=`m ${e??""} ${r}`,a=o.get(n);if(a)return a;const u=dateFormatter(e,{month:r});return t(o,n,Array.from({length:12},(t,e)=>u.format(makeDate(2021,e,1))))}export function isMonthBeforeYear(t){const e=dateFormatter(t,{year:"numeric",month:"long"}).formatToParts(n);return e.findIndex(t=>"month"===t.type)<e.findIndex(t=>"year"===t.type)}export function isHour12(t){const e=dateFormatter(t,{hour:"numeric"}).resolvedOptions();return e.hourCycle?"h11"===e.hourCycle||"h12"===e.hourCycle:!0===e.hour12}export function meridiemLabels(t){const e=dateFormatter(t,{hour:"numeric",hour12:!0}),r=t=>{const r=e.formatToParts(withTime(n,{hours:t})).find(t=>"dayPeriod"===t.type);return r?.value??(t<12?"AM":"PM")};return[r(9),r(21)]}export function localeWeekStart(t){try{const e=t??(new Intl.DateTimeFormat).resolvedOptions().locale,r=new Intl.Locale(e),n="function"==typeof r.getWeekInfo?r.getWeekInfo():r.weekInfo;if("number"==typeof n?.firstDay)return n.firstDay%7}catch{}return 0}
@@ -39,7 +39,7 @@
39
39
  * the languages it speaks. Once it has, `locale="ko"` resolves through exactly
40
40
  * the path it always did.
41
41
  *
42
- * English left too, for the same reason one step smaller. It is nine modules
42
+ * English left too, for the same reason one step smaller. It is thirteen modules
43
43
  * under `internal/messages/`, one per namespace, because a bundler that can drop
44
44
  * a module it can also drop an export — and cannot drop a property. Held as one
45
45
  * object, English was 1.75 kB that every component carried whole: `MPButton`
@@ -151,6 +151,101 @@ export interface MPMessages {
151
151
  start: string;
152
152
  end: string;
153
153
  };
154
+ /**
155
+ * MPNumberField.
156
+ *
157
+ * The two steppers, which are a plus and a minus and have no words of their
158
+ * own — the same case the pagination's chevrons and the chat's delivery marks
159
+ * are in. They are read out and never drawn.
160
+ */
161
+ numberField: {
162
+ increase: string;
163
+ decrease: string;
164
+ };
165
+ /**
166
+ * MPCarousel.
167
+ *
168
+ * Every string here is read out and never drawn: the strip is pictures, the
169
+ * arrows are chevrons and the marks under it are dots. `{index}` and
170
+ * `{total}` are filled in by `fillMessage`, and they are named rather than
171
+ * positional for the reason the pagination's are — a language that counts the
172
+ * total first is not a language this table can serve with an argument order.
173
+ */
174
+ carousel: {
175
+ /** The name of the `region` the strip is inside. */
176
+ label: string;
177
+ /** The two arrows. */
178
+ previous: string;
179
+ next: string;
180
+ /** One slide, and its own position mark. `Slide 2 of 5`. */
181
+ slide: string;
182
+ };
183
+ /**
184
+ * MPBreadcrumb.
185
+ *
186
+ * Both read out and never drawn: a trail's steps are the caller's words, and
187
+ * these are the two things around them that are not.
188
+ */
189
+ breadcrumb: {
190
+ /** The name of the `<nav>` the trail is inside. */
191
+ label: string;
192
+ /** The `…` that puts the folded middle back. */
193
+ expand: string;
194
+ };
195
+ /**
196
+ * MPCombobox.
197
+ *
198
+ * Both **drawn**, which is what makes them belong here rather than in a prop:
199
+ * a Korean page whose search box says *No matches* has answered in a language
200
+ * the reader did not ask a question in. `{label}` is the text they typed, and
201
+ * is filled in by `fillMessage`.
202
+ */
203
+ combobox: {
204
+ /** The line where the rows would be, when nothing matched. */
205
+ empty: string;
206
+ /** The row that offers what was typed as a value of its own. */
207
+ add: string;
208
+ };
209
+ /**
210
+ * MPTable.
211
+ *
212
+ * One string, drawn across the whole width where the rows would be. A table
213
+ * that says *No data* in the middle of a translated page is the one part of it
214
+ * that was not translated.
215
+ */
216
+ table: {
217
+ empty: string;
218
+ };
219
+ /**
220
+ * MPFilePicker.
221
+ *
222
+ * The line inside the box, and the largest piece of text this table holds. It
223
+ * is drawn, it is an instruction, and it is the whole of what the component
224
+ * tells a reader to do.
225
+ */
226
+ filePicker: {
227
+ prompt: string;
228
+ };
229
+ /**
230
+ * MPTextLink.
231
+ *
232
+ * The sentence after a link that takes over the window. Read out and never
233
+ * drawn — the arrow says it to a reader who can see it, and this says it to
234
+ * everybody else.
235
+ */
236
+ textLink: {
237
+ newTab: string;
238
+ };
239
+ /**
240
+ * MPOverlay.
241
+ *
242
+ * The name of a modal region that may hold nothing readable at all — a bare
243
+ * spinner, a `clear` sheet. Without it a screen reader announces the region as
244
+ * nothing, which is why the component defaults it rather than requiring it.
245
+ */
246
+ overlay: {
247
+ label: string;
248
+ };
154
249
  /** MPAlert. */
155
250
  alert: {
156
251
  /** The × in the corner, which has no text of its own. */
@@ -234,6 +329,108 @@ export interface MPMessages {
234
329
  /** The line above the button, saying why the content is covered. */
235
330
  notice: string;
236
331
  };
332
+ /**
333
+ * MPPageLayout, and the parts of a page it arranges.
334
+ *
335
+ * One namespace for the skeleton rather than one per component, for the reason
336
+ * the pickers share theirs: they are one vocabulary, written by whoever
337
+ * translates a page's chrome, and a caller who has translated the word for a
338
+ * sidebar has translated the button that opens it in the same breath.
339
+ */
340
+ layout: {
341
+ /**
342
+ * The link that jumps past the navigation, drawn only while it holds the
343
+ * focus.
344
+ *
345
+ * Drawn rather than only announced, which makes it one of the few strings
346
+ * here that a sighted keyboard reader actually sees — and the one it would
347
+ * be least forgivable to leave in English, because the readers it exists for
348
+ * are the ones who cannot skip it.
349
+ */
350
+ skipToContent: string;
351
+ /**
352
+ * What an `MPSidebar` is called when nothing named it.
353
+ *
354
+ * Read out and never drawn. Every `<aside>` needs a name and a page with two
355
+ * of them *must* have one each, or a screen reader offers two regions called
356
+ * "complementary" — which is exactly why this is a default rather than a
357
+ * required prop.
358
+ */
359
+ sidebar: string;
360
+ /** The hamburger, which is a drawing and has no word of its own. */
361
+ openSidebar: string;
362
+ /** The same button once the drawer is open. */
363
+ closeSidebar: string;
364
+ /** The handle on a resizable column's inner edge. */
365
+ resizeSidebar: string;
366
+ };
367
+ /**
368
+ * MPTransfer.
369
+ *
370
+ * Every string here is **drawn**, which is unusual in this table and is what
371
+ * makes the namespace necessary: the two headings, the filter's placeholder
372
+ * and the line an empty list shows are all read off the screen, and a Korean
373
+ * page with a column headed *Available* is a page the component broke.
374
+ *
375
+ * The two arrows are the exception and are read out rather than drawn, for the
376
+ * reason the pagination's steppers are.
377
+ */
378
+ transfer: {
379
+ /** The heading over the list of things that have not been chosen. */
380
+ source: string;
381
+ /** And over the list of things that have. */
382
+ target: string;
383
+ /** The arrow that sends the ticked rows across. */
384
+ toTarget: string;
385
+ /** And the one that brings them back. */
386
+ toSource: string;
387
+ /** The filter above each list. */
388
+ search: string;
389
+ /** What a list with nothing in it says. */
390
+ empty: string;
391
+ };
392
+ /**
393
+ * MPCommandPalette.
394
+ *
395
+ * Three strings, two of them drawn: a palette that says *Type a command or
396
+ * search…* to a Korean reader is a palette that has told them, in the first
397
+ * thing they see, that it is not for them.
398
+ */
399
+ command: {
400
+ /** The dialog's accessible name. It has no visible title to take one from. */
401
+ label: string;
402
+ /** The placeholder in the field. */
403
+ search: string;
404
+ /** The line where the rows would be, when nothing matched. */
405
+ empty: string;
406
+ };
407
+ /**
408
+ * MPColorPicker.
409
+ *
410
+ * The one control in the library whose parts have **nowhere to take a name
411
+ * from**: a saturation square, a hue rail and an opacity rail are three
412
+ * draggable rectangles, and without these they are three draggable rectangles
413
+ * to a screen reader too.
414
+ *
415
+ * `empty` is the exception and is drawn — it is what the trigger reads before
416
+ * a colour has been chosen.
417
+ */
418
+ colorPicker: {
419
+ /** The saturation/brightness square. */
420
+ area: string;
421
+ /** The hue rail beside it. */
422
+ hue: string;
423
+ /** The opacity rail, when `alpha` is on. */
424
+ alpha: string;
425
+ /** The field the value can be typed into. */
426
+ value: string;
427
+ /** The grid of ready-made colours. */
428
+ swatches: string;
429
+ /** The × that empties the control. */
430
+ clear: string;
431
+ /** What the trigger reads before anything has been chosen. */
432
+ empty: string;
433
+ };
237
434
  }
238
435
  /** A translation may fill in as much or as little of the table as it has. */
239
436
  export type MPPartialMessages = {
@@ -269,10 +466,10 @@ export interface MPLocale {
269
466
  /**
270
467
  * One namespace's English strings, carrying the name they answer to.
271
468
  *
272
- * The nine of them live in `internal/messages/`, one to a module, and a
469
+ * The thirteen of them live in `internal/messages/`, one to a module, and a
273
470
  * component imports the one it speaks. That is the whole reason this type
274
471
  * exists: `resolveNamespace` below is handed the English table rather than
275
- * looking it up, so the eight tables a component does not use are eight modules
472
+ * looking it up, so the twelve tables a component does not use are twelve modules
276
473
  * nothing imports.
277
474
  *
278
475
  * The name travels with the strings rather than beside them, so a call site is
@@ -313,7 +510,7 @@ export declare function registerMPMessages(...locales: MPLocale[]): void;
313
510
  * A namespace at a time, so a language that has one and not another keeps
314
511
  * English for the rest rather than losing both. That was already how the merge
315
512
  * worked; what changed is that the namespaces are no longer merged all at once,
316
- * because a component that reads one of them should not carry the other eight.
513
+ * because a component that reads one of them should not carry the other twelve.
317
514
  *
318
515
  * Note that this is only about the words in the table. The dates themselves are
319
516
  * formatted by `Intl` against the same tag, and `Intl` speaks every language the
@@ -0,0 +1,72 @@
1
+ /**
2
+ * What keyboard the reader is on, and how a shortcut is spelled.
3
+ *
4
+ * Two components speak this vocabulary and they speak it in opposite
5
+ * directions: [MPShortcut](../components/shortcut/MPShortcut.tsx) *writes* a
6
+ * shortcut down, and [MPCommandPalette](../components/command-palette/MPCommandPalette.tsx)
7
+ * *reads* one off a real keyboard event. Both files already said that the two
8
+ * had to agree — "a shortcut a component displays and one it binds have to be
9
+ * spelled the same way, or the label on the screen is a claim nobody checked" —
10
+ * and both then answered the question separately.
11
+ *
12
+ * They disagreed. The palette tested `navigator.userAgent` alone, which is the
13
+ * one of the three sources a browser is most willing to freeze or lie about, so
14
+ * a page could draw `⌘K` and bind Ctrl+K. Written once, they cannot.
15
+ *
16
+ * Nothing here is exported from `src/index.ts`. It is the library talking to
17
+ * itself, in the sense `internal/` always means.
18
+ */
19
+ /** The three real platforms a shortcut is spelled for. */
20
+ export type MPResolvedOS = 'mac' | 'windows' | 'linux';
21
+ /**
22
+ * What the browser says it is running on.
23
+ *
24
+ * `userAgentData.platform` is the modern spelling and `navigator.platform` the
25
+ * deprecated one that every browser still answers; the user agent string is the
26
+ * last resort. All three are matched at once because the question is coarse —
27
+ * which of three key caps to print — and getting it slightly wrong is a label,
28
+ * not a bug.
29
+ */
30
+ export declare function detectOS(): MPResolvedOS;
31
+ /**
32
+ * `useSyncExternalStore` rather than `useEffect` plus state, and rather than
33
+ * reading `navigator` during render.
34
+ *
35
+ * Reading it during render is a hydration mismatch waiting to happen: the server
36
+ * has no `navigator`, so it would render `Ctrl` and the client would render `⌘`
37
+ * into the same markup. This hook is the one API that tells React the two are
38
+ * *meant* to differ — it hydrates with the server's answer and re-renders with
39
+ * the browser's, which is exactly the sequence a Mac reader sees.
40
+ */
41
+ export declare function useDetectedOS(): MPResolvedOS;
42
+ /**
43
+ * Splits the string form. Empty segments are what `'Ctrl++'` leaves behind, and
44
+ * dropping them is why the array form exists for that case.
45
+ */
46
+ export declare function tokenizeShortcut(keys: string | string[]): string[];
47
+ /**
48
+ * Whether a keyboard event is the shortcut this string names.
49
+ *
50
+ * The same vocabulary `MPShortcut` draws, read rather than written — and the
51
+ * same tokenizer, so a shortcut that can be displayed is a shortcut that can be
52
+ * matched.
53
+ *
54
+ * ## `Mod` is a name for a key, not a fifth modifier
55
+ *
56
+ * It resolves to Command on a Mac and Control everywhere else, so `Mod+K` and
57
+ * `Ctrl+K` are the *same combination* on Windows — and the check has to say so.
58
+ * Tested as a modifier of its own, they contradicted each other: `Ctrl+K` on
59
+ * Windows held Control, `Mod` was not named, and "is Control down without Mod
60
+ * being asked for" answered no. `Ctrl+K` simply never matched anywhere except a
61
+ * Mac, on the component whose whole job is to answer a shortcut.
62
+ *
63
+ * So `Mod` is folded into whichever real key it stands for, and the four
64
+ * modifiers are then compared as themselves.
65
+ *
66
+ * Each is checked in **both** directions. A shortcut that fired with extra
67
+ * modifiers held would take a combination the page had given to something else.
68
+ *
69
+ * The platform is passed rather than sniffed, so a caller reads it through the
70
+ * same hook the label does and the two cannot end up on different answers.
71
+ */
72
+ export declare function matchesShortcut(event: KeyboardEvent, shortcut: string | string[], os: MPResolvedOS): boolean;
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import*as t from"react";export function detectOS(){if("undefined"==typeof navigator)return"windows";const t=navigator.userAgentData,e=`${t?.platform??""} ${navigator.platform??""} ${navigator.userAgent??""}`;return/mac|iphone|ipad|ipod/i.test(e)?"mac":/win/i.test(e)?"windows":"linux"}function e(){return()=>{}}function r(){return"windows"}export function useDetectedOS(){return t.useSyncExternalStore(e,detectOS,r)}export function tokenizeShortcut(t){return Array.isArray(t)?t.map(t=>t.trim()).filter(Boolean):t.split("+").map(t=>t.trim()).filter(Boolean)}export function matchesShortcut(t,e,r){const n=tokenizeShortcut(e).map(t=>t.toLowerCase()),o=n[n.length-1];if(void 0===o)return!1;const a=new Set(n.slice(0,-1)),i=a.has("mod"),s=a.has("ctrl")||i&&"mac"!==r,c=a.has("meta")||i&&"mac"===r;return s===t.ctrlKey&&c===t.metaKey&&(a.has("shift")===t.shiftKey&&a.has("alt")===t.altKey&&t.key.toLowerCase()===o)}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A length, said the way this library says lengths.
3
+ *
4
+ * One rule, everywhere: **a number is CSS pixels and a string is already a CSS
5
+ * length.** Twelve components had written it out inline and four more had a
6
+ * private `toLength` of their own, which is sixteen copies of a sentence that is
7
+ * either true of the whole library or true of nothing.
8
+ *
9
+ * They all happened to agree. That is the argument for collecting them rather
10
+ * than against it — sixteen agreeing copies are sixteen chances for the
11
+ * seventeenth to be written slightly differently, and the difference would be a
12
+ * prop that quietly took a number to mean something else.
13
+ *
14
+ * Nothing here is exported from `src/index.ts`. It is the library talking to
15
+ * itself, in the sense `internal/` always means.
16
+ */
17
+ /** A number is pixels; a string is whatever it says; nothing is nothing. */
18
+ export declare function cssLength(value: number | string): string;
19
+ export declare function cssLength(value: number | string | undefined | null): string | undefined;
20
+ /**
21
+ * A CSS length string, in pixels, or `undefined` for one this cannot resolve.
22
+ *
23
+ * The two components that let a reader *drag* a size — `MPSidebar` and
24
+ * `MPPanes` — both have to turn a written bound into a number to clamp against,
25
+ * and both had the same regex and the same unit arithmetic. This is that,
26
+ * once.
27
+ *
28
+ * `undefined` rather than a fallback, so each caller decides what an
29
+ * unresolvable bound means. They do not agree, and should not: a pane with an
30
+ * unreadable `minSize` is a pane with no minimum, and a sidebar with an
31
+ * unreadable one still has a default to fall back to. A parser that picked for
32
+ * them would have to pick wrongly for one of them.
33
+ *
34
+ * ## What the units are measured against
35
+ *
36
+ * `%` is a share of `extent`, which is whatever the caller is dividing up — the
37
+ * split's own width, the window's. `rem` is the document's font size and `em` is
38
+ * `root`'s, which is the distinction that makes `em` worth accepting at all: a
39
+ * bound written in `em` is a bound in the *component's* text, and a component
40
+ * inside a scaled-down panel means something different by it than the page does.
41
+ */
42
+ export declare function pixelsIn(value: string, extent?: number, root?: Element | null): number | undefined;
@@ -0,0 +1 @@
1
+ export function cssLength(e){if(null!=e)return"number"==typeof e?`${e}px`:e}const e=/^\s*(-?[\d.]+)\s*(px|rem|em|%)\s*$/;export function pixelsIn(t,n,o){const r=e.exec(t);if(!r)return;const u=Number(r[1]);if(!Number.isNaN(u))switch(r[2]){case"px":return u;case"%":return void 0===n?void 0:n*u/100;case"rem":return"undefined"==typeof document?void 0:u*(Number.parseFloat(getComputedStyle(document.documentElement).fontSize)||16);default:return"undefined"!=typeof document&&o?u*(Number.parseFloat(getComputedStyle(o).fontSize)||16):void 0}}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The two questions a component has to ask about a URL it did not write.
3
+ *
4
+ * Four components render an `<a>` whose `target` a caller can set, and three of
5
+ * them had worked out the same `rel` independently — which is three chances for
6
+ * the fourth to forget, and the fourth did. One of them also renders a URL that
7
+ * arrives from somewhere else entirely, which is a different question with a
8
+ * worse failure.
9
+ *
10
+ * Nothing here is exported from `src/index.ts`. It is the library talking to
11
+ * itself, in the sense `internal/` always means.
12
+ */
13
+ /**
14
+ * The `rel` a link opening in a new tab needs, unless the caller named one.
15
+ *
16
+ * `target="_blank"` hands the opened page a `window.opener` back into this one
17
+ * unless it is told not to. Modern browsers imply `noopener` and older ones do
18
+ * not; `noreferrer` is never implied by anything, and is what stops the address
19
+ * of the page the reader was on travelling to wherever they just went.
20
+ *
21
+ * A caller's own `rel` **replaces** this rather than extending it, which is the
22
+ * bargain these components already documented: a row that also needs `nofollow`
23
+ * says `rel="noopener noreferrer nofollow"` and means it. The alternative —
24
+ * merging — is a component quietly adding tokens to an attribute the caller
25
+ * wrote out in full.
26
+ */
27
+ export declare function linkRel(target: string | undefined, rel: string | undefined): string | undefined;
28
+ /**
29
+ * A URL if it is one a reader can safely be sent to, and nothing if it is not.
30
+ *
31
+ * This is for the URLs that arrive from **somewhere else** — the link preview on
32
+ * a message somebody else sent — rather than for the ones an application writes
33
+ * into its own navigation. React renders a `javascript:` href with a development
34
+ * warning and no more, so on a page built out of user-generated content a
35
+ * hostile preview URL is a one-click script execution.
36
+ *
37
+ * A URL with no scheme at all is relative, and a relative URL cannot escalate to
38
+ * anything: it resolves against the page it is already on. Those pass.
39
+ *
40
+ * Rejected means `undefined`, so the element renders with no `href` — visibly
41
+ * not a link, rather than a link that quietly goes nowhere. Half-sanitising a
42
+ * URL into something that still navigates is how a filter becomes a bypass.
43
+ */
44
+ export declare function safeHref(href: string | undefined): string | undefined;
@@ -0,0 +1 @@
1
+ export function linkRel(e,t){return void 0!==t?t:"_blank"===e?"noopener noreferrer":void 0}const e=/[\u0000-\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/g,t=/^([a-z][a-z0-9+.-]*):/i,u=new Set(["http:","https:","mailto:","tel:"]);export function safeHref(r){if(!r)return;const n=t.exec(r.replace(e,""));return n?u.has(`${n[1].toLowerCase()}:`)?r:void 0:r}