@box-kite/react 1.0.0 → 2.0.1

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 (179) hide show
  1. package/.claude/rules/box-kite-rules.md +23 -1
  2. package/.claude/skills/box-kite/SKILL.md +134 -427
  3. package/.claude/skills/box-kite/references/components.md +235 -0
  4. package/.claude/skills/box-kite/references/extending.md +42 -0
  5. package/.claude/skills/box-kite/references/patterns.md +27 -0
  6. package/.claude/skills/box-kite/references/styling.md +222 -0
  7. package/.cursor/rules/box-kite.mdc +73 -0
  8. package/AGENTS.md +102 -0
  9. package/BOX_AI_CONTEXT.md +1124 -153
  10. package/BOX_KITE_AI_CONTEXT.md +1124 -153
  11. package/README.md +36 -2
  12. package/a11y.cjs +1 -1
  13. package/a11y.d.ts +1 -1
  14. package/a11y.mjs +3 -2
  15. package/anchor.cjs +1 -0
  16. package/anchor.d.ts +14 -0
  17. package/anchor.mjs +3 -0
  18. package/behavior.cjs +1 -1
  19. package/behavior.mjs +118 -136
  20. package/box.cjs +1 -1
  21. package/box.mjs +1 -1
  22. package/client.cjs +1 -1
  23. package/client.mjs +15 -14
  24. package/components/accordion.cjs +1 -0
  25. package/components/accordion.d.ts +114 -0
  26. package/components/accordion.mjs +251 -0
  27. package/components/button.cjs +1 -1
  28. package/components/button.d.ts +3 -0
  29. package/components/button.mjs +1 -1
  30. package/components/chart.cjs +1 -1
  31. package/components/chart.d.ts +2 -1
  32. package/components/chart.mjs +159 -184
  33. package/components/checkbox.cjs +1 -1
  34. package/components/checkbox.d.ts +8 -0
  35. package/components/checkbox.mjs +1 -1
  36. package/components/combobox/comboboxChips.d.ts +21 -0
  37. package/components/combobox/comboboxListbox.d.ts +47 -0
  38. package/components/combobox.cjs +1 -0
  39. package/components/combobox.d.ts +121 -0
  40. package/components/combobox.mjs +563 -0
  41. package/components/dataGrid/components/dataGridAggregateValue.d.ts +10 -0
  42. package/components/dataGrid/components/dataGridCell.d.ts +2 -1
  43. package/components/dataGrid/components/dataGridCellEditor.d.ts +15 -0
  44. package/components/dataGrid/components/dataGridCellPlaceholder.d.ts +14 -0
  45. package/components/dataGrid/components/dataGridCellTree.d.ts +16 -0
  46. package/components/dataGrid/components/dataGridDataSourceError.d.ts +12 -0
  47. package/components/dataGrid/components/dataGridExport.d.ts +10 -0
  48. package/components/dataGrid/components/dataGridFooter.d.ts +11 -0
  49. package/components/dataGrid/contracts/dataGridContract.d.ts +474 -16
  50. package/components/dataGrid/export/gridExport.d.ts +10 -0
  51. package/components/dataGrid/gridNavigationContext.d.ts +9 -1
  52. package/components/dataGrid/models/aggregateCellModel.d.ts +34 -0
  53. package/components/dataGrid/models/aggregationModel.d.ts +32 -0
  54. package/components/dataGrid/models/cellKeys.d.ts +11 -0
  55. package/components/dataGrid/models/cellModel.d.ts +27 -1
  56. package/components/dataGrid/models/columnModel.d.ts +12 -2
  57. package/components/dataGrid/models/dataSourceModel.d.ts +177 -0
  58. package/components/dataGrid/models/editModel.d.ts +77 -0
  59. package/components/dataGrid/models/exportModel.d.ts +51 -0
  60. package/components/dataGrid/models/gridModel.d.ts +108 -21
  61. package/components/dataGrid/models/groupRowCellModel.d.ts +11 -3
  62. package/components/dataGrid/models/groupRowModel.d.ts +22 -2
  63. package/components/dataGrid/models/rowModel.d.ts +13 -1
  64. package/components/dataGrid/models/sourceGroupRowModel.d.ts +45 -0
  65. package/components/dataGrid/models/sourceLevel.d.ts +71 -0
  66. package/components/dataGrid/models/sourceRowModel.d.ts +29 -0
  67. package/components/dataGrid/models/sourceTreeRowModel.d.ts +23 -0
  68. package/components/dataGrid/models/treeModel.d.ts +94 -0
  69. package/components/dataGrid/models/treeRow.d.ts +22 -0
  70. package/components/dataGrid/models/treeRowModel.d.ts +50 -0
  71. package/components/dataGrid.cjs +1 -1
  72. package/components/dataGrid.d.ts +4 -2
  73. package/components/dataGrid.mjs +4484 -2755
  74. package/components/dialog.cjs +1 -0
  75. package/components/dialog.d.ts +151 -0
  76. package/components/dialog.mjs +223 -0
  77. package/components/dropdown.cjs +1 -1
  78. package/components/dropdown.d.ts +30 -0
  79. package/components/dropdown.mjs +256 -244
  80. package/components/icon.cjs +1 -1
  81. package/components/icon.d.ts +2 -1
  82. package/components/icon.mjs +3 -3
  83. package/components/menu.cjs +1 -0
  84. package/components/menu.d.ts +234 -0
  85. package/components/menu.mjs +422 -0
  86. package/components/overlay.cjs +1 -1
  87. package/components/overlay.d.ts +30 -26
  88. package/components/overlay.mjs +45 -75
  89. package/components/popover.cjs +1 -0
  90. package/components/popover.d.ts +100 -0
  91. package/components/popover.mjs +69 -0
  92. package/components/presence.d.ts +6 -0
  93. package/components/progress.cjs +1 -0
  94. package/components/progress.d.ts +47 -0
  95. package/components/progress.mjs +28 -0
  96. package/components/radioButton.cjs +1 -1
  97. package/components/radioButton.d.ts +8 -0
  98. package/components/radioButton.mjs +1 -1
  99. package/components/radioGroup.cjs +1 -1
  100. package/components/radioGroup.d.ts +15 -2
  101. package/components/radioGroup.mjs +34 -30
  102. package/components/select.d.ts +9 -0
  103. package/components/semantics.cjs +1 -1
  104. package/components/semantics.d.ts +33 -28
  105. package/components/semantics.mjs +3 -3
  106. package/components/slider.cjs +1 -0
  107. package/components/slider.d.ts +98 -0
  108. package/components/slider.mjs +250 -0
  109. package/components/svg.cjs +1 -1
  110. package/components/svg.d.ts +25 -23
  111. package/components/svg.mjs +3 -3
  112. package/components/switch.cjs +1 -1
  113. package/components/switch.d.ts +9 -0
  114. package/components/switch.mjs +1 -1
  115. package/components/tabs.cjs +1 -0
  116. package/components/tabs.d.ts +87 -0
  117. package/components/tabs.mjs +324 -0
  118. package/components/textarea.cjs +1 -1
  119. package/components/textarea.d.ts +14 -0
  120. package/components/textarea.mjs +1 -1
  121. package/components/textbox.cjs +1 -1
  122. package/components/textbox.d.ts +12 -0
  123. package/components/textbox.mjs +1 -1
  124. package/components/toaster.cjs +1 -0
  125. package/components/toaster.d.ts +106 -0
  126. package/components/toaster.mjs +295 -0
  127. package/components/tooltip.cjs +1 -1
  128. package/components/tooltip.d.ts +39 -4
  129. package/components/tooltip.mjs +56 -54
  130. package/docs/a11y.md +199 -0
  131. package/docs/anchor.md +139 -0
  132. package/docs/components.md +48 -0
  133. package/docs/index.md +11 -0
  134. package/docs/props.md +1777 -0
  135. package/effects.cjs +1 -1
  136. package/effects.mjs +1 -1
  137. package/gridExport.cjs +2 -0
  138. package/gridExport.mjs +244 -0
  139. package/identity.cjs +1 -0
  140. package/identity.mjs +12 -0
  141. package/keyboard.cjs +1 -0
  142. package/keyboard.mjs +30 -0
  143. package/layer.cjs +1 -0
  144. package/layer.mjs +127 -0
  145. package/motion.cjs +1 -1
  146. package/motion.mjs +1 -1
  147. package/package.json +134 -10
  148. package/placement.cjs +1 -0
  149. package/placement.mjs +180 -0
  150. package/platform.cjs +1 -1
  151. package/platform.mjs +18 -5
  152. package/react/anchor/useAnchorPosition.d.ts +79 -0
  153. package/react/dialog/useScrollLock.d.ts +12 -0
  154. package/react/hooks/usePortalContainer.d.ts +6 -1
  155. package/react/hooks/useVirtualization.d.ts +24 -35
  156. package/react/popover/usePopoverLayer.d.ts +87 -0
  157. package/react-shared.cjs +1 -1
  158. package/react-shared.mjs +19 -2
  159. package/rsc.cjs +1 -1
  160. package/rsc.mjs +1 -1
  161. package/utils/accordion/accordionUtils.d.ts +48 -0
  162. package/utils/anchor/anchorUtils.d.ts +79 -0
  163. package/utils/array/lazyList.d.ts +10 -0
  164. package/utils/chart/chartPalette.d.ts +15 -0
  165. package/utils/chart/chartUtils.d.ts +2 -8
  166. package/utils/combobox/comboboxUtils.d.ts +89 -0
  167. package/utils/dom/domUtils.d.ts +6 -0
  168. package/utils/environment/environmentUtils.d.ts +10 -0
  169. package/utils/export/csvUtils.d.ts +23 -0
  170. package/utils/export/downloadUtils.d.ts +12 -0
  171. package/utils/export/xlsxUtils.d.ts +56 -0
  172. package/utils/export/zipUtils.d.ts +26 -0
  173. package/utils/keyboard/typeaheadUtils.d.ts +31 -0
  174. package/utils/menu/menuUtils.d.ts +25 -0
  175. package/utils/slider/sliderUtils.d.ts +67 -0
  176. package/utils/tabs/tabsUtils.d.ts +75 -0
  177. package/utils/toast/toastStore.d.ts +73 -0
  178. package/utils/virtual/virtualUtils.d.ts +47 -0
  179. /package/react/{a11y → identity}/useIdentifier.d.ts +0 -0
@@ -0,0 +1 @@
1
+ "use client";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../platform.cjs"),t=require("../effects.cjs"),n=require("../box.cjs"),r=require("../behavior.cjs"),i=require("../identity.cjs"),a=require("../motion.cjs");let o=require("react"),s=require("react/jsx-runtime");var c;(function(e){let t=e.TAB_SELECTOR=`[role="tab"]`,n=e.LIST_SELECTOR=`[role="tablist"]`,r=e.PANEL_SELECTOR=`[role="tabpanel"]`;function i(e,t){return t instanceof Element&&t.closest(n)===e}e.owns=i;function a(e){return e?[...e.querySelectorAll(t)].filter(t=>i(e,t)):[]}e.tabs=a;function o(e){return e.hasAttribute(`disabled`)||e.getAttribute(`aria-disabled`)===`true`}e.isDisabled=o;function s(e){return e.dataset.value}e.valueOf=s;function c(e){return e.replace(/[^A-Za-z0-9-]/g,e=>`_${e.codePointAt(0).toString(36)}_`)}e.token=c;function l(e,t,n,r){let i=e.length;if(i===0)return;let a=t<0||t>=i?n>0?-1:i:t;for(let t=0;t<i;t++){if(a+=n,a<0||a>=i){if(!r)return;a=(a%i+i)%i}if(!o(e[a]))return e[a]}}e.step=l;function u(e,t){return l(e,t===1?-1:e.length,t,!1)}e.edge=u;function d(e,t){return t instanceof HTMLElement?e.indexOf(t):-1}e.indexOf=d;function f(e,t,n=!1){if(e===`Home`)return{kind:`edge`,delta:1};if(e===`End`)return{kind:`edge`,delta:-1};let r=t===`vertical`,i=r?`ArrowDown`:n?`ArrowLeft`:`ArrowRight`,a=r?`ArrowUp`:n?`ArrowRight`:`ArrowLeft`;if(e===i)return{kind:`step`,delta:1};if(e===a)return{kind:`step`,delta:-1}}e.moveFor=f;function p(e,t,n,r){return n.kind===`edge`?u(e,n.delta):l(e,t,n.delta,r)}e.target=p;function m(e){if(e)return a(e).find(e=>e.getAttribute(`aria-selected`)===`true`)}e.selectedTab=m;function h(e,t,n){let r=e.getBoundingClientRect(),i=t.getBoundingClientRect();return n===`vertical`?{start:i.top-r.top+e.scrollTop,size:i.height}:{start:i.left-r.left+e.scrollLeft,size:i.width}}e.bounds=h;function g(e,t){return!e||!t?e===t:e.start===t.start&&e.size===t.size}e.sameBounds=g;function _(e){if(e)return[...e.querySelectorAll(r)].find(e=>!e.hasAttribute(`hidden`))}e.visiblePanel=_})(c||={});var l=c,u=(0,o.createContext)(null);function d(e){let t=(0,o.useContext)(u);if(!t)throw Error(`<${e}> has to be rendered inside a <Tabs>.`);return t}function f(e){let{children:a,value:c,defaultValue:d,onValueChange:f,orientation:p=`horizontal`,activation:m=`automatic`,loop:h=!0,keepMounted:g=!1,indicator:_=`static`,props:v,...y}=e,b=i.t(`tabs`),[x,S]=r.i({value:c,defaultValue:d,onChange:f}),[C,w]=(0,o.useState)(),[T,E]=(0,o.useState)(!1);t.n(()=>{x!==void 0&&w(x)},[x]);let D=(0,o.useMemo)(()=>({identifier:b,value:x,orientation:p,activation:m,loop:h,keepMounted:g,indicator:_,indicatorLive:T,setIndicatorLive:E,tabStop:C??x,setTabStop:w,select:S,tabId:e=>`${b}-tab-${l.token(e)}`,panelId:e=>`${b}-panel-${l.token(e)}`}),[b,x,p,m,h,g,_,T,C,S]);return(0,s.jsx)(u.Provider,{value:D,children:(0,s.jsx)(n.default,{component:`tabs`,...y,variant:[y.variant,{vertical:p===`vertical`}],props:v,children:a})})}function p(i){let{children:a,label:c,labelledBy:u,props:f,...p}=i,{value:m,orientation:h,activation:g,loop:_,indicator:v,tabStop:y,setTabStop:b,setIndicatorLive:x,select:S}=d(`Tabs.List`),C=(0,o.useRef)(null),[w,T]=(0,o.useState)(),E=v===`sliding`;t.n(()=>{let e=C.current;if(!E||!e)return;let t=()=>{let t=l.selectedTab(e),n=t&&l.bounds(e,t,h);T(e=>l.sameBounds(e,n)?e:n)};if(t(),typeof ResizeObserver>`u`)return;let n=new ResizeObserver(t);n.observe(e);for(let t of l.tabs(e))n.observe(t);return()=>n.disconnect()},[E,h,m]);let D=E&&w&&w.size>0?w:void 0;t.n(()=>{x(D!==void 0)},[D,x]),t.n(()=>{if(y!==void 0)return;let e=l.edge(l.tabs(C.current),1),t=e&&l.valueOf(e);t!==void 0&&b(t)},[y,b]);let O=r.a(t=>{let n=C.current;if(!n||t.defaultPrevented||!l.owns(n,t.target))return;let r=l.tabs(n),i=l.indexOf(r,t.target);if(i===-1)return;if(g===`manual`&&(t.key===`Enter`||t.key===` `)){let e=l.valueOf(r[i]);if(e===void 0)return;t.preventDefault(),S(e,{reason:`keyboard`,event:t});return}let a=l.moveFor(t.key,h,e.u(n));if(!a)return;let o=l.target(r,i,a,_);if(!o)return;t.preventDefault(),o.focus();let s=l.valueOf(o);g===`automatic`&&s!==void 0&&S(s,{reason:`keyboard`,event:t})});return(0,s.jsxs)(n.default,{ref:C,component:`tabs.list`,...p,variant:[p.variant,{vertical:h===`vertical`,sliding:E}],props:{role:`tablist`,"aria-label":c,"aria-labelledby":u,"aria-orientation":h,...f,onKeyDown:O},children:[a,D&&(0,s.jsx)(n.default,{tag:`span`,component:`tabs.indicator`,variant:{vertical:h===`vertical`},style:h===`vertical`?{top:`${D.start}px`,height:`${D.size}px`}:{left:`${D.start}px`,width:`${D.size}px`},props:{"aria-hidden":!0}})]})}p.displayName=`Tabs.List`;function m(e){let{value:t,children:i,disabled:a,props:o,...c}=e,{value:l,orientation:u,keepMounted:f,indicatorLive:p,tabStop:m,setTabStop:h,select:g,tabId:_,panelId:v}=d(`Tabs.Tab`),y=l===t,b=r.a(e=>g(t,{reason:`click`,event:e})),x=r.a(()=>h(t));return(0,s.jsx)(n.default,{tag:`button`,component:`tabs.tab`,...c,variant:[c.variant,{vertical:u===`vertical`,underline:!p}],disabled:a,id:_(t),props:{type:`button`,role:`tab`,"aria-selected":y,"aria-controls":y||f?v(t):void 0,tabIndex:m===t?0:-1,"data-value":t,...o,onClick:b,onFocus:x},children:i})}m.displayName=`Tabs.Tab`;function h(e){let{children:i,props:c,...u}=e,{value:f}=d(`Tabs.Panels`),p=(0,o.useRef)(null),[m,h]=(0,o.useState)(),[g,_]=(0,o.useState)(!1),v=r.a(()=>{let e=p.current;if(!e)return;let t=l.visiblePanel(e)?.offsetHeight;t!==m&&(m!==void 0&&t!==void 0&&_(!0),h(t))});return t.n(()=>{let e=p.current;if(!e||(v(),typeof ResizeObserver>`u`))return;let t=l.visiblePanel(e);if(!t)return;let n=new ResizeObserver(v);return n.observe(t),()=>n.disconnect()},[f,v]),t.n(()=>{let e=p.current;if(!e||!g)return;let t=setTimeout(()=>_(!1),a.n.activeDuration(getComputedStyle(e))+a.n.SETTLE_FRAME);return()=>clearTimeout(t)},[g,m]),(0,s.jsx)(n.default,{ref:p,component:`tabs.panels`,...u,variant:[u.variant,{resizing:g}],style:{height:m===void 0?void 0:`${m}px`,...u.style},props:c,children:i})}h.displayName=`Tabs.Panels`;function g(e){let{value:t,children:r,props:i,...a}=e,{value:o,keepMounted:c,tabId:l,panelId:u}=d(`Tabs.Panel`),f=o===t;return!f&&!c?null:(0,s.jsx)(n.default,{component:`tabs.panel`,...a,variant:[a.variant,{hidden:!f}],id:u(t),props:{role:`tabpanel`,"aria-labelledby":l(t),hidden:!f||void 0,tabIndex:0,...i},children:r})}g.displayName=`Tabs.Panel`;var _=f;_.List=p,_.Tab=m,_.Panels=h,_.Panel=g,_.displayName=`Tabs`,exports.default=_;
@@ -0,0 +1,87 @@
1
+ import { BoxProps } from '../box';
2
+ import { ChangeHandler } from '../react/a11y/useControllableState';
3
+ import { ComponentsAndVariants } from '@box-kite/core/types';
4
+ import { TabsOrientation } from '../utils/tabs/tabsUtils';
5
+ export type { TabsOrientation };
6
+ /** Why the selection changed — a press on a tab, or the keyboard. */
7
+ export type TabsReason = 'click' | 'keyboard';
8
+ /**
9
+ * When a tab becomes the selected one. `automatic` is APG's default and what a reader expects: moving to a
10
+ * tab shows its panel. `manual` moves focus alone and waits for Enter or Space — which is what a panel too
11
+ * expensive to render on the way past needs.
12
+ */
13
+ export type TabsActivation = 'automatic' | 'manual';
14
+ /**
15
+ * Which indicator marks the selected tab. `static` is the tab's own border, which needs no JavaScript
16
+ * and is what a prerendered page paints. `sliding` is one element for the whole list that travels
17
+ * between tabs — measured, so the static one stays until the widget has run.
18
+ */
19
+ export type TabsIndicator = 'static' | 'sliding';
20
+ type TabsBoxProps<TKey extends keyof ComponentsAndVariants> = Omit<BoxProps<'div', TKey>, 'onChange'>;
21
+ export interface TabsProps<TKey extends keyof ComponentsAndVariants = 'tabs'> extends TabsBoxProps<TKey> {
22
+ /** The tabs and their panels: a `Tabs.List` of `Tabs.Tab`, then one `Tabs.Panel` per tab. */
23
+ children?: React.ReactNode;
24
+ /** Controlled selection. Leave it out and the widget owns it. */
25
+ value?: string;
26
+ /** Which tab starts selected. Left out, nothing is selected and no panel is shown until one is chosen. */
27
+ defaultValue?: string;
28
+ /** Fires with the newly selected tab and why it changed — `'click'` or `'keyboard'`. */
29
+ onValueChange?: ChangeHandler<string | undefined, TabsReason>;
30
+ /** Which way the tabs run. Horizontal is the reading axis, so its arrows mirror in a right-to-left page. */
31
+ orientation?: TabsOrientation;
32
+ /** Whether moving to a tab selects it. Default `'automatic'`, which is what APG asks for. */
33
+ activation?: TabsActivation;
34
+ /** Whether the arrows wrap around at the ends. Default `true`. */
35
+ loop?: boolean;
36
+ /**
37
+ * Which indicator marks the selected tab: the tab's own border (`'static'`, the default) or one
38
+ * element travelling between them (`'sliding'`), which animates because it is the same element.
39
+ */
40
+ indicator?: TabsIndicator;
41
+ /**
42
+ * Render every panel rather than only the selected one, hiding the rest. What a panel holding a
43
+ * half-filled form needs, since an unmounted panel loses its state.
44
+ */
45
+ keepMounted?: boolean;
46
+ }
47
+ export interface TabsListProps<TKey extends keyof ComponentsAndVariants = 'tabs.list'> extends BoxProps<'div', TKey> {
48
+ /** The tabs. */
49
+ children?: React.ReactNode;
50
+ /** The list's accessible name. A tablist has none of its own, and one page can hold several. */
51
+ label?: string;
52
+ /** Names the list after an element already on the page, instead of `label`. */
53
+ labelledBy?: string;
54
+ }
55
+ /** Every Box prop, on the `<button>` that is one tab. */
56
+ export interface TabsTabProps<TKey extends keyof ComponentsAndVariants = 'tabs.tab'> extends Omit<BoxProps<'button', TKey>, 'disabled'> {
57
+ /** Which panel this tab shows, and what the widget reports when it is chosen. */
58
+ value: string;
59
+ /** The tab's label. */
60
+ children?: React.ReactNode;
61
+ /**
62
+ * Not selectable, and stepped over by the arrows — unlike a disabled `Menu.Item`, which APG asks stay
63
+ * reachable. Selection follows focus here, so a tab focus could reach and selection could not would
64
+ * leave the widget with no state to be in.
65
+ */
66
+ disabled?: boolean;
67
+ }
68
+ export interface TabsPanelsProps<TKey extends keyof ComponentsAndVariants = 'tabs.panels'> extends BoxProps<'div', TKey> {
69
+ /** The panels. */
70
+ children?: React.ReactNode;
71
+ }
72
+ export interface TabsPanelProps<TKey extends keyof ComponentsAndVariants = 'tabs.panel'> extends BoxProps<'div', TKey> {
73
+ /** The tab this panel belongs to. */
74
+ value: string;
75
+ /** The panel's content. */
76
+ children?: React.ReactNode;
77
+ }
78
+ interface TabsType {
79
+ <TKey extends keyof ComponentsAndVariants = 'tabs'>(props: TabsProps<TKey>): React.ReactNode;
80
+ List: <TKey extends keyof ComponentsAndVariants = 'tabs.list'>(props: TabsListProps<TKey>) => React.ReactNode;
81
+ Tab: <TKey extends keyof ComponentsAndVariants = 'tabs.tab'>(props: TabsTabProps<TKey>) => React.ReactNode;
82
+ Panels: <TKey extends keyof ComponentsAndVariants = 'tabs.panels'>(props: TabsPanelsProps<TKey>) => React.ReactNode;
83
+ Panel: <TKey extends keyof ComponentsAndVariants = 'tabs.panel'>(props: TabsPanelProps<TKey>) => React.ReactNode;
84
+ displayName?: string;
85
+ }
86
+ declare const Tabs: TabsType;
87
+ export default Tabs;
@@ -0,0 +1,324 @@
1
+ "use client";
2
+ import { u as e } from "../platform.mjs";
3
+ import { n as t } from "../effects.mjs";
4
+ import n from "../box.mjs";
5
+ import { a as r, i } from "../behavior.mjs";
6
+ import { t as a } from "../identity.mjs";
7
+ import { n as o } from "../motion.mjs";
8
+ import { createContext as s, useContext as c, useMemo as l, useRef as u, useState as d } from "react";
9
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
10
+ //#region src/utils/tabs/tabsUtils.ts
11
+ var m;
12
+ (function(e) {
13
+ let t = e.TAB_SELECTOR = "[role=\"tab\"]", n = e.LIST_SELECTOR = "[role=\"tablist\"]", r = e.PANEL_SELECTOR = "[role=\"tabpanel\"]";
14
+ function i(e, t) {
15
+ return t instanceof Element && t.closest(n) === e;
16
+ }
17
+ e.owns = i;
18
+ function a(e) {
19
+ return e ? [...e.querySelectorAll(t)].filter((t) => i(e, t)) : [];
20
+ }
21
+ e.tabs = a;
22
+ function o(e) {
23
+ return e.hasAttribute("disabled") || e.getAttribute("aria-disabled") === "true";
24
+ }
25
+ e.isDisabled = o;
26
+ function s(e) {
27
+ return e.dataset.value;
28
+ }
29
+ e.valueOf = s;
30
+ function c(e) {
31
+ return e.replace(/[^A-Za-z0-9-]/g, (e) => `_${e.codePointAt(0).toString(36)}_`);
32
+ }
33
+ e.token = c;
34
+ function l(e, t, n, r) {
35
+ let i = e.length;
36
+ if (i === 0) return;
37
+ let a = t < 0 || t >= i ? n > 0 ? -1 : i : t;
38
+ for (let t = 0; t < i; t++) {
39
+ if (a += n, a < 0 || a >= i) {
40
+ if (!r) return;
41
+ a = (a % i + i) % i;
42
+ }
43
+ if (!o(e[a])) return e[a];
44
+ }
45
+ }
46
+ e.step = l;
47
+ function u(e, t) {
48
+ return l(e, t === 1 ? -1 : e.length, t, !1);
49
+ }
50
+ e.edge = u;
51
+ function d(e, t) {
52
+ return t instanceof HTMLElement ? e.indexOf(t) : -1;
53
+ }
54
+ e.indexOf = d;
55
+ function f(e, t, n = !1) {
56
+ if (e === "Home") return {
57
+ kind: "edge",
58
+ delta: 1
59
+ };
60
+ if (e === "End") return {
61
+ kind: "edge",
62
+ delta: -1
63
+ };
64
+ let r = t === "vertical", i = r ? "ArrowDown" : n ? "ArrowLeft" : "ArrowRight", a = r ? "ArrowUp" : n ? "ArrowRight" : "ArrowLeft";
65
+ if (e === i) return {
66
+ kind: "step",
67
+ delta: 1
68
+ };
69
+ if (e === a) return {
70
+ kind: "step",
71
+ delta: -1
72
+ };
73
+ }
74
+ e.moveFor = f;
75
+ function p(e, t, n, r) {
76
+ return n.kind === "edge" ? u(e, n.delta) : l(e, t, n.delta, r);
77
+ }
78
+ e.target = p;
79
+ function m(e) {
80
+ if (e) return a(e).find((e) => e.getAttribute("aria-selected") === "true");
81
+ }
82
+ e.selectedTab = m;
83
+ function h(e, t, n) {
84
+ let r = e.getBoundingClientRect(), i = t.getBoundingClientRect();
85
+ return n === "vertical" ? {
86
+ start: i.top - r.top + e.scrollTop,
87
+ size: i.height
88
+ } : {
89
+ start: i.left - r.left + e.scrollLeft,
90
+ size: i.width
91
+ };
92
+ }
93
+ e.bounds = h;
94
+ function g(e, t) {
95
+ return !e || !t ? e === t : e.start === t.start && e.size === t.size;
96
+ }
97
+ e.sameBounds = g;
98
+ function _(e) {
99
+ if (e) return [...e.querySelectorAll(r)].find((e) => !e.hasAttribute("hidden"));
100
+ }
101
+ e.visiblePanel = _;
102
+ })(m ||= {});
103
+ var h = m, g = s(null);
104
+ function _(e) {
105
+ let t = c(g);
106
+ if (!t) throw Error(`<${e}> has to be rendered inside a <Tabs>.`);
107
+ return t;
108
+ }
109
+ function v(e) {
110
+ let { children: r, value: o, defaultValue: s, onValueChange: c, orientation: u = "horizontal", activation: p = "automatic", loop: m = !0, keepMounted: _ = !1, indicator: v = "static", props: y, ...b } = e, x = a("tabs"), [S, C] = i({
111
+ value: o,
112
+ defaultValue: s,
113
+ onChange: c
114
+ }), [w, T] = d(), [E, D] = d(!1);
115
+ t(() => {
116
+ S !== void 0 && T(S);
117
+ }, [S]);
118
+ let O = l(() => ({
119
+ identifier: x,
120
+ value: S,
121
+ orientation: u,
122
+ activation: p,
123
+ loop: m,
124
+ keepMounted: _,
125
+ indicator: v,
126
+ indicatorLive: E,
127
+ setIndicatorLive: D,
128
+ tabStop: w ?? S,
129
+ setTabStop: T,
130
+ select: C,
131
+ tabId: (e) => `${x}-tab-${h.token(e)}`,
132
+ panelId: (e) => `${x}-panel-${h.token(e)}`
133
+ }), [
134
+ x,
135
+ S,
136
+ u,
137
+ p,
138
+ m,
139
+ _,
140
+ v,
141
+ E,
142
+ w,
143
+ C
144
+ ]);
145
+ return /* @__PURE__ */ f(g.Provider, {
146
+ value: O,
147
+ children: /* @__PURE__ */ f(n, {
148
+ component: "tabs",
149
+ ...b,
150
+ variant: [b.variant, { vertical: u === "vertical" }],
151
+ props: y,
152
+ children: r
153
+ })
154
+ });
155
+ }
156
+ function y(i) {
157
+ let { children: a, label: o, labelledBy: s, props: c, ...l } = i, { value: m, orientation: g, activation: v, loop: y, indicator: b, tabStop: x, setTabStop: S, setIndicatorLive: C, select: w } = _("Tabs.List"), T = u(null), [E, D] = d(), O = b === "sliding";
158
+ t(() => {
159
+ let e = T.current;
160
+ if (!O || !e) return;
161
+ let t = () => {
162
+ let t = h.selectedTab(e), n = t && h.bounds(e, t, g);
163
+ D((e) => h.sameBounds(e, n) ? e : n);
164
+ };
165
+ if (t(), typeof ResizeObserver > "u") return;
166
+ let n = new ResizeObserver(t);
167
+ n.observe(e);
168
+ for (let t of h.tabs(e)) n.observe(t);
169
+ return () => n.disconnect();
170
+ }, [
171
+ O,
172
+ g,
173
+ m
174
+ ]);
175
+ let k = O && E && E.size > 0 ? E : void 0;
176
+ t(() => {
177
+ C(k !== void 0);
178
+ }, [k, C]), t(() => {
179
+ if (x !== void 0) return;
180
+ let e = h.edge(h.tabs(T.current), 1), t = e && h.valueOf(e);
181
+ t !== void 0 && S(t);
182
+ }, [x, S]);
183
+ let A = r((t) => {
184
+ let n = T.current;
185
+ if (!n || t.defaultPrevented || !h.owns(n, t.target)) return;
186
+ let r = h.tabs(n), i = h.indexOf(r, t.target);
187
+ if (i === -1) return;
188
+ if (v === "manual" && (t.key === "Enter" || t.key === " ")) {
189
+ let e = h.valueOf(r[i]);
190
+ if (e === void 0) return;
191
+ t.preventDefault(), w(e, {
192
+ reason: "keyboard",
193
+ event: t
194
+ });
195
+ return;
196
+ }
197
+ let a = h.moveFor(t.key, g, e(n));
198
+ if (!a) return;
199
+ let o = h.target(r, i, a, y);
200
+ if (!o) return;
201
+ t.preventDefault(), o.focus();
202
+ let s = h.valueOf(o);
203
+ v === "automatic" && s !== void 0 && w(s, {
204
+ reason: "keyboard",
205
+ event: t
206
+ });
207
+ });
208
+ return /* @__PURE__ */ p(n, {
209
+ ref: T,
210
+ component: "tabs.list",
211
+ ...l,
212
+ variant: [l.variant, {
213
+ vertical: g === "vertical",
214
+ sliding: O
215
+ }],
216
+ props: {
217
+ role: "tablist",
218
+ "aria-label": o,
219
+ "aria-labelledby": s,
220
+ "aria-orientation": g,
221
+ ...c,
222
+ onKeyDown: A
223
+ },
224
+ children: [a, k && /* @__PURE__ */ f(n, {
225
+ tag: "span",
226
+ component: "tabs.indicator",
227
+ variant: { vertical: g === "vertical" },
228
+ style: g === "vertical" ? {
229
+ top: `${k.start}px`,
230
+ height: `${k.size}px`
231
+ } : {
232
+ left: `${k.start}px`,
233
+ width: `${k.size}px`
234
+ },
235
+ props: { "aria-hidden": !0 }
236
+ })]
237
+ });
238
+ }
239
+ y.displayName = "Tabs.List";
240
+ function b(e) {
241
+ let { value: t, children: i, disabled: a, props: o, ...s } = e, { value: c, orientation: l, keepMounted: u, indicatorLive: d, tabStop: p, setTabStop: m, select: h, tabId: g, panelId: v } = _("Tabs.Tab"), y = c === t, b = r((e) => h(t, {
242
+ reason: "click",
243
+ event: e
244
+ })), x = r(() => m(t));
245
+ return /* @__PURE__ */ f(n, {
246
+ tag: "button",
247
+ component: "tabs.tab",
248
+ ...s,
249
+ variant: [s.variant, {
250
+ vertical: l === "vertical",
251
+ underline: !d
252
+ }],
253
+ disabled: a,
254
+ id: g(t),
255
+ props: {
256
+ type: "button",
257
+ role: "tab",
258
+ "aria-selected": y,
259
+ "aria-controls": y || u ? v(t) : void 0,
260
+ tabIndex: p === t ? 0 : -1,
261
+ "data-value": t,
262
+ ...o,
263
+ onClick: b,
264
+ onFocus: x
265
+ },
266
+ children: i
267
+ });
268
+ }
269
+ b.displayName = "Tabs.Tab";
270
+ function x(e) {
271
+ let { children: i, props: a, ...s } = e, { value: c } = _("Tabs.Panels"), l = u(null), [p, m] = d(), [g, v] = d(!1), y = r(() => {
272
+ let e = l.current;
273
+ if (!e) return;
274
+ let t = h.visiblePanel(e)?.offsetHeight;
275
+ t !== p && (p !== void 0 && t !== void 0 && v(!0), m(t));
276
+ });
277
+ return t(() => {
278
+ let e = l.current;
279
+ if (!e || (y(), typeof ResizeObserver > "u")) return;
280
+ let t = h.visiblePanel(e);
281
+ if (!t) return;
282
+ let n = new ResizeObserver(y);
283
+ return n.observe(t), () => n.disconnect();
284
+ }, [c, y]), t(() => {
285
+ let e = l.current;
286
+ if (!e || !g) return;
287
+ let t = setTimeout(() => v(!1), o.activeDuration(getComputedStyle(e)) + o.SETTLE_FRAME);
288
+ return () => clearTimeout(t);
289
+ }, [g, p]), /* @__PURE__ */ f(n, {
290
+ ref: l,
291
+ component: "tabs.panels",
292
+ ...s,
293
+ variant: [s.variant, { resizing: g }],
294
+ style: {
295
+ height: p === void 0 ? void 0 : `${p}px`,
296
+ ...s.style
297
+ },
298
+ props: a,
299
+ children: i
300
+ });
301
+ }
302
+ x.displayName = "Tabs.Panels";
303
+ function S(e) {
304
+ let { value: t, children: r, props: i, ...a } = e, { value: o, keepMounted: s, tabId: c, panelId: l } = _("Tabs.Panel"), u = o === t;
305
+ return !u && !s ? null : /* @__PURE__ */ f(n, {
306
+ component: "tabs.panel",
307
+ ...a,
308
+ variant: [a.variant, { hidden: !u }],
309
+ id: l(t),
310
+ props: {
311
+ role: "tabpanel",
312
+ "aria-labelledby": c(t),
313
+ hidden: !u || void 0,
314
+ tabIndex: 0,
315
+ ...i
316
+ },
317
+ children: r
318
+ });
319
+ }
320
+ S.displayName = "Tabs.Panel";
321
+ var C = v;
322
+ C.List = y, C.Tab = b, C.Panels = x, C.Panel = S, C.displayName = "Tabs";
323
+ //#endregion
324
+ export { C as default };
@@ -1 +1 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../rolldown-runtime.cjs"),t=require("../react-shared.cjs"),n=require("../forms.cjs");let r=require("react"),i=require("react/jsx-runtime"),a=require("@box-kite/react");a=e.t(a,1);var o=[`name`,`onInput`,`onChange`,`value`,`defaultValue`,`rows`,`cols`,`autoFocus`,`maxLength`,`minLength`,`readOnly`];function s(e,r){let{placeholder:s,...c}=e,{text:l,styles:u}=n.t(s),d=t.t.buildProps(c,o,l===void 0?void 0:{placeholder:l});return(0,i.jsx)(a.default,{ref:r,tag:`textarea`,component:`textarea`,...d,placeholder:u})}var c=(0,r.forwardRef)(s);c.displayName=`Textarea`,exports.default=c;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../rolldown-runtime.cjs"),t=require("../react-shared.cjs"),n=require("../forms.cjs");let r=require("react"),i=require("react/jsx-runtime"),a=require("@box-kite/react");a=e.t(a,1);var o=[`name`,`onInput`,`onChange`,`value`,`defaultValue`,`rows`,`cols`,`autoFocus`,`maxLength`,`minLength`,`readOnly`];function s(e,r){let{placeholder:s,...c}=e,{text:l,styles:u}=n.t(s),d=t.i.buildProps(c,o,l===void 0?void 0:{placeholder:l});return(0,i.jsx)(a.default,{ref:r,tag:`textarea`,component:`textarea`,...d,placeholder:u})}var c=(0,r.forwardRef)(s);c.displayName=`Textarea`,exports.default=c;
@@ -8,19 +8,33 @@ type TagPropsType = (typeof tagProps)[number];
8
8
  type TextareaProps<TKey extends keyof ComponentsAndVariants> = Omit<BoxProps<'textarea', TKey>, 'tag' | 'props' | 'placeholder'>;
9
9
  type TextareaTagProps = OmitTagProps<BoxTagProps<'textarea'>, TagPropsType | 'type'>;
10
10
  interface Props<TKey extends keyof ComponentsAndVariants> extends TextareaProps<TKey> {
11
+ /** What the field submits under, and what a `<label htmlFor>` of your own would point at. */
11
12
  name?: string;
13
+ /** Attributes for the `<textarea>` itself — an `id`, an `aria-label`, `autoComplete`, `wrap`. */
12
14
  props?: TextareaTagProps;
15
+ /** Fires on every keystroke. `onChange` is React's alias for the same event. */
13
16
  onInput?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
17
+ /** Fires on every keystroke too — React's `onChange` is the DOM's `input`, not its `change`. */
14
18
  onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
19
+ /** A string is the attribute; an object is `::placeholder` styles. Neither one names the field. */
15
20
  placeholder?: PlaceholderProp;
21
+ /** Controlled value. Pair it with `onChange`, or the field cannot be typed into. */
16
22
  value?: string;
23
+ /** The value it starts with when the field owns its own state. */
17
24
  defaultValue?: string;
25
+ /** How many lines tall it starts. `height` is the Box prop for the size it stays. */
18
26
  rows?: number;
27
+ /** How many characters wide it starts — `width` is the prop to reach for instead. */
19
28
  cols?: number;
29
+ /** Focus it on mount. One per page at most — a stolen focus is a lost place in the document. */
20
30
  autoFocus?: boolean;
31
+ /** The most characters the field accepts. The browser both enforces and announces it. */
21
32
  maxLength?: number;
33
+ /** The fewest characters that count as valid. Checked when the form is submitted. */
22
34
  minLength?: number;
35
+ /** Editable to nobody, but still focusable, still read out and still submitted. */
23
36
  readOnly?: boolean;
37
+ /** The form will not submit while it is empty, and a screen reader says so. */
24
38
  required?: boolean;
25
39
  }
26
40
  declare const _default: <TKey extends keyof ComponentsAndVariants = "textarea">(props: Props<TKey> & RefAttributes<HTMLTextAreaElement>) => React.ReactNode;
@@ -1,4 +1,4 @@
1
- import { t as e } from "../react-shared.mjs";
1
+ import { i as e } from "../react-shared.mjs";
2
2
  import { t } from "../forms.mjs";
3
3
  import { forwardRef as n } from "react";
4
4
  import { jsx as r } from "react/jsx-runtime";
@@ -1 +1 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../rolldown-runtime.cjs"),t=require("../react-shared.cjs"),n=require("../forms.cjs");let r=require("react"),i=require("react/jsx-runtime"),a=require("@box-kite/react");a=e.t(a,1);var o=[`name`,`onInput`,`onChange`,`type`,`step`,`defaultValue`,`autoFocus`,`readOnly`,`required`,`value`,`pattern`];function s(e,r){let{placeholder:s,...c}=e,{text:l,styles:u}=n.t(s),d=t.t.buildProps(c,o,l===void 0?void 0:{placeholder:l});return(0,i.jsx)(a.default,{ref:r,tag:`input`,component:`textbox`,...d,placeholder:u})}var c=(0,r.forwardRef)(s);c.displayName=`Textbox`,exports.default=c;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../rolldown-runtime.cjs"),t=require("../react-shared.cjs"),n=require("../forms.cjs");let r=require("react"),i=require("react/jsx-runtime"),a=require("@box-kite/react");a=e.t(a,1);var o=[`name`,`onInput`,`onChange`,`type`,`step`,`defaultValue`,`autoFocus`,`readOnly`,`required`,`value`,`pattern`];function s(e,r){let{placeholder:s,...c}=e,{text:l,styles:u}=n.t(s),d=t.i.buildProps(c,o,l===void 0?void 0:{placeholder:l});return(0,i.jsx)(a.default,{ref:r,tag:`input`,component:`textbox`,...d,placeholder:u})}var c=(0,r.forwardRef)(s);c.displayName=`Textbox`,exports.default=c;
@@ -9,17 +9,29 @@ type TextareaProps<TKey extends keyof ComponentsAndVariants> = Omit<BoxProps<'in
9
9
  type TextboxTagProps = OmitTagProps<BoxTagProps<'input'>, TagPropsType>;
10
10
  type TextboxType = 'date' | 'datetime-local' | 'email' | 'hidden' | 'month' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'time' | 'url' | 'week';
11
11
  interface Props<TKey extends keyof ComponentsAndVariants> extends TextareaProps<TKey> {
12
+ /** What the field submits under, and what a `<label htmlFor>` of your own would point at. */
12
13
  name?: string;
14
+ /** Attributes for the `<input>` itself — an `id`, an `aria-label`, `inputMode`, `autoComplete`. */
13
15
  props?: TextboxTagProps;
16
+ /** Fires on every keystroke. `onChange` is React's alias for the same event. */
14
17
  onInput?: (e: React.ChangeEvent<HTMLInputElement>) => void;
18
+ /** Fires on every keystroke too — React's `onChange` is the DOM's `input`, not its `change`. */
15
19
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
20
+ /** Which text input this is. It decides the validation, the mobile keyboard and the spinner. */
16
21
  type?: TextboxType;
22
+ /** A string is the attribute; an object is `::placeholder` styles. Neither one names the field. */
17
23
  placeholder?: PlaceholderProp;
24
+ /** Controlled value. Pair it with `onChange`, or the field cannot be typed into. */
18
25
  value?: string | number;
26
+ /** The value it starts with when the field owns its own state. */
19
27
  defaultValue?: string | number;
28
+ /** A regular expression the value has to match for the form to be valid. */
20
29
  pattern?: string;
30
+ /** Focus it on mount. One per page at most — a stolen focus is a lost place in the document. */
21
31
  autoFocus?: boolean;
32
+ /** Editable to nobody, but still focusable, still read out and still submitted. */
22
33
  readOnly?: boolean;
34
+ /** How far a `number` field's spinner and arrow keys move. */
23
35
  step?: number | string;
24
36
  }
25
37
  declare const _default: <TKey extends keyof ComponentsAndVariants = "textbox">(props: Props<TKey> & RefAttributes<HTMLInputElement>) => React.ReactNode;
@@ -1,4 +1,4 @@
1
- import { t as e } from "../react-shared.mjs";
1
+ import { i as e } from "../react-shared.mjs";
2
2
  import { t } from "../forms.mjs";
3
3
  import { forwardRef as n } from "react";
4
4
  import { jsx as r } from "react/jsx-runtime";
@@ -0,0 +1 @@
1
+ "use client";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../platform.cjs"),t=require("../client.cjs"),n=require("../effects.cjs"),r=require("../box.cjs"),i=require("../motion.cjs");let a=require("react"),o=require("react/jsx-runtime"),s=require("react-dom"),c=require("use-sync-external-store/shim");var l={toasts:[],overflow:0},u=0;function d(){return u+=1,`toast-${u}`}function f(e){let t=[],n=l,r=e?.limit??3,i=e?.duration??5e3,a=!1,o=new Set,s=new Map,c=e=>{let t=s.get(e);t?.handle&&clearTimeout(t.handle),s.delete(e)},u=()=>{let e=0;t=t.map(t=>{let n=!t.open||e++<r;return t.visible===n?t:{...t,visible:n}}),n={toasts:t,overflow:Math.max(0,e-r)},f(),o.forEach(e=>e())};function f(){let e=new Set;for(let n of t){if(!n.open||!n.visible||!Number.isFinite(n.duration))continue;e.add(n.id);let t=s.get(n.id)??{handle:null,remaining:n.duration,startedAt:0};s.set(n.id,t),!(a||t.handle)&&(t.startedAt=Date.now(),t.handle=setTimeout(()=>{s.delete(n.id),m(n.id,`timeout`)},t.remaining))}for(let t of[...s.keys()])e.has(t)||c(t)}let p=(e,t)=>t??(e===`loading`?1/0:i);function m(e,n=`imperative`){let r=[];t=t.map(t=>!t.open||e!==void 0&&t.id!==e?t:(r.push(t),c(t.id),{...t,open:!1})),r.length&&(u(),r.forEach(e=>e.onDismiss?.(n)))}function h(e,n,r){let i=!1;t=t.map(t=>{if(t.id!==e)return t;i=!0,c(e);let a=r?.kind??t.kind;return{...t,...r,id:e,message:n,kind:a,duration:r?.duration??(r?.kind?p(a):t.duration),open:!0}}),i&&u()}function g(e,n){let r=n?.id??d();if(n?.id&&t.some(e=>e.id===r))return h(r,e,n),r;let i=n?.kind??`default`;return t=[...t,{id:r,kind:i,message:e,description:n?.description,duration:p(i,n?.duration),action:n?.action,dismissible:n?.dismissible??!0,onDismiss:n?.onDismiss,open:!0,visible:!1}],u(),r}return{subscribe(e){return o.add(e),()=>o.delete(e)},getSnapshot:()=>n,getServerSnapshot:()=>l,add:g,update:h,dismiss:m,remove(e){let n=t.filter(t=>t.id!==e);n.length!==t.length&&(c(e),t=n,u())},setLimit(e){e!==r&&(r=e,u())},setDefaultDuration(e){i=e},pause(){if(!a){a=!0;for(let e of s.values())e.handle&&(clearTimeout(e.handle),e.handle=null,e.remaining=Math.max(0,e.remaining-(Date.now()-e.startedAt)))}},resume(){a&&(a=!1,f())},reset(){for(let e of[...s.keys()])c(e);t=[],n=l,o.forEach(e=>e())}}}var p=f(),m=e=>(t,n)=>p.add(t,{...n,kind:e}),h=Object.assign((e,t)=>p.add(e,t),{success:m(`success`),error:m(`error`),warning:m(`warning`),info:m(`info`),loading:m(`loading`),update:(e,t,n)=>p.update(e,t,n),dismiss:e=>p.dismiss(e,`imperative`),promise(e,t,n){let r=p.add(t.loading,{...n,id:n?.id,kind:`loading`}),i=(e,t)=>typeof e==`function`?e(t):e;return e.then(e=>p.update(r,i(t.success,e),{kind:`success`}),e=>p.update(r,i(t.error,e),{kind:`error`})),e}}),g={"top-start":`topStart`,"top-center":`topCenter`,"top-end":`topEnd`,"bottom-start":`bottomStart`,"bottom-center":`bottomCenter`,"bottom-end":`bottomEnd`};function _(e,t){let n=t.toLowerCase().split(`+`),r=n[n.length-1],i=new Set(n.slice(0,-1));return e.key.toLowerCase()===r&&e.altKey===i.has(`alt`)&&e.ctrlKey===i.has(`ctrl`)&&e.shiftKey===i.has(`shift`)&&e.metaKey===i.has(`meta`)}function v(e){let{toast:t,store:a,fromTop:s,closeLabel:c}=e,{mounted:l,ref:u,props:d}=i.t({present:t.open});if(n.n(()=>{l||a.remove(t.id)},[l,a,t.id]),!l)return null;let f=t.action,p=()=>{f?.onClick(),f?.closeOnClick!==!1&&a.dismiss(t.id,`action`)};return(0,o.jsxs)(r.default,{ref:u,component:`toaster.toast`,variant:{[t.kind]:t.kind!=="default",fromTop:s},props:{...t.kind===`error`?{role:`alert`}:{},"data-toast-id":t.id,...d},children:[(0,o.jsx)(r.default,{component:`toaster.message`,children:t.message}),t.description!==void 0&&(0,o.jsx)(r.default,{component:`toaster.description`,children:t.description}),f&&(0,o.jsx)(r.default,{tag:`button`,component:`toaster.action`,props:{type:`button`,onClick:p},children:f.label}),t.dismissible&&(0,o.jsx)(r.default,{tag:`button`,component:`toaster.close`,props:{type:`button`,"aria-label":c,onClick:()=>a.dismiss(t.id,`close`)}})]})}function y(i){let{position:l=`bottom-end`,limit:u=3,duration:d=5e3,label:f=`Notifications`,closeLabel:m=`Close`,overflowLabel:h=e=>`+${e} more`,hotkey:y=`F6`,store:b=p,props:x,...S}=i,C=(0,c.useSyncExternalStore)(b.subscribe,b.getSnapshot,b.getServerSnapshot),[w,T]=(0,a.useState)(!0),E=t.t(!w),D=(0,a.useRef)(null),O=(0,a.useRef)(null),k=(0,a.useRef)({hovered:!1,focused:!1,hidden:!1}),A=(0,a.useCallback)(()=>{let{hovered:e,focused:t,hidden:n}=k.current;e||t||n?b.pause():b.resume()},[b]);n.n(()=>{e.a()||T(!1)},[]),n.n(()=>b.setLimit(u),[b,u]),n.n(()=>b.setDefaultDuration(d),[b,d]),n.n(()=>{let t=D.current;!w||!e.a()||!t||!t.isConnected||t.matches(`:popover-open`)||t.showPopover()}),n.n(()=>{let t=e.t();if(!t)return;let n=new AbortController;return t.addEventListener(`visibilitychange`,()=>{k.current.hidden=t.hidden,A()},{signal:n.signal}),()=>n.abort()},[A]),n.n(()=>{let t=e.t();if(!y||!t)return;let n=new AbortController;return t.addEventListener(`keydown`,e=>{!_(e,y)||!D.current||(e.preventDefault(),O.current=t.activeElement,D.current.focus())},{signal:n.signal}),()=>n.abort()},[y]);let j=e=>!!e&&!!D.current?.contains(e),M=()=>{k.current.hovered=!0,A()},N=e=>{j(e.relatedTarget)||(k.current.hovered=!1,A())},P=e=>{k.current.focused=!0,A(),j(e.relatedTarget)||(O.current=e.relatedTarget)},F=e=>{j(e.relatedTarget)||(k.current.focused=!1,A())},I=e=>{if(e.key!==`Escape`)return;let t=(e.target.closest?.(`[data-toast-id]`))?.getAttribute(`data-toast-id`);t&&b.dismiss(t,`close`),b.getSnapshot().toasts.some(e=>e.open)?D.current?.focus():O.current?.focus()},L=l.startsWith(`top`),R=C.toasts.filter(e=>e.visible),z=L?[...R].reverse():R,B=C.overflow>0&&(0,o.jsx)(r.default,{component:`toaster.overflow`,children:h(C.overflow)}),V=(0,o.jsxs)(r.default,{tag:`section`,ref:D,component:`toaster`,...S,variant:[S.variant,{[g[l]]:!0}],props:{...w?{popover:`manual`}:{},"aria-live":`polite`,"aria-atomic":`false`,"aria-relevant":`additions text`,"aria-label":f,tabIndex:-1,...x,onPointerOver:M,onPointerOut:N,onFocus:P,onBlur:F,onKeyDown:I},children:[!L&&B,z.map(e=>(0,o.jsx)(v,{toast:e,store:b,fromTop:L,closeLabel:m},e.id)),L&&B]});return w?V:E?(0,s.createPortal)(V,E):null}var b=y;b.displayName=`Toaster`,exports.createToastStore=f,exports.default=b,exports.defaultToastStore=p,exports.toast=h;
@@ -0,0 +1,106 @@
1
+ import { BoxProps } from '../box';
2
+ import { ComponentsAndVariants } from '@box-kite/core/types';
3
+ import { Toast, ToastAction, ToastDismissReason, ToastKind, ToastOptions, ToastStore } from '../utils/toast/toastStore';
4
+ export { default as createToastStore } from '../utils/toast/toastStore';
5
+ export type { Toast, ToastAction, ToastDismissReason, ToastKind, ToastOptions, ToastStore };
6
+ /** Which corner the stack is pinned to. The inline half is logical, so `start` mirrors with the page. */
7
+ export type ToastPosition = 'top-start' | 'top-center' | 'top-end' | 'bottom-start' | 'bottom-center' | 'bottom-end';
8
+ /** What `toast.promise` is told to say at each of the three moments. A function is handed the result. */
9
+ export interface ToastPromiseMessages<TValue> {
10
+ loading: React.ReactNode;
11
+ success: React.ReactNode | ((value: TValue) => React.ReactNode);
12
+ error: React.ReactNode | ((error: unknown) => React.ReactNode);
13
+ }
14
+ type Content = React.ReactNode;
15
+ type Options = ToastOptions<Content>;
16
+ /** The store `toast()` writes to, and the one `<Toaster>` reads when it is given none of its own. */
17
+ export declare const defaultToastStore: ToastStore<Content>;
18
+ /**
19
+ * Puts a message on screen, from anywhere — an event handler, a fetch, a module with no React in it. It
20
+ * returns the id, which is what `toast.dismiss` and a second `toast()` naming the same id act on.
21
+ *
22
+ * ```ts
23
+ * toast.success('Saved', { description: 'Your changes are live.' });
24
+ * toast.error('Could not save', { action: { label: 'Retry', onClick: save } });
25
+ * toast.promise(save(), { loading: 'Saving…', success: 'Saved', error: 'Could not save' });
26
+ * ```
27
+ *
28
+ * Nothing is shown until a `<Toaster>` is on the page; a call made before one mounts is queued rather
29
+ * than lost, because the store holds the toasts and the viewport only draws them.
30
+ */
31
+ export declare const toast: ((message: Content, options?: Options) => string) & {
32
+ success: (message: Content, options?: Options) => string;
33
+ error: (message: Content, options?: Options) => string;
34
+ warning: (message: Content, options?: Options) => string;
35
+ info: (message: Content, options?: Options) => string;
36
+ /** Stays until something dismisses it — a spinner that timed out would leave its work unreported. */
37
+ loading: (message: Content, options?: Options) => string;
38
+ /** Changes a toast already on screen. An id that is not there is ignored. */
39
+ update: (id: string, message: Content, options?: Options) => void;
40
+ /** Starts the exit for one toast, or for every one of them when given no id. */
41
+ dismiss: (id?: string) => void;
42
+ /**
43
+ * One toast for the whole of an async call: a spinner while it runs, then the result in its place.
44
+ * The promise is handed back untouched, so it can still be awaited.
45
+ */
46
+ promise<TValue>(promise: Promise<TValue>, messages: ToastPromiseMessages<TValue>, options?: Options): Promise<TValue>;
47
+ };
48
+ export interface ToasterProps<TKey extends keyof ComponentsAndVariants = 'toaster'> extends Omit<BoxProps<'div', TKey>, 'position'> {
49
+ /** Which corner the stack is pinned to. Default `'bottom-end'`. */
50
+ position?: ToastPosition;
51
+ /** How many toasts are on screen at once. The rest wait their turn, timers and all. Default `3`. */
52
+ limit?: number;
53
+ /** Milliseconds a toast that names no duration of its own stays. Default `5000`. */
54
+ duration?: number;
55
+ /** The region's accessible name. `role="region"` has none of its own, and this one is never labelled visually. */
56
+ label?: string;
57
+ /** The close button's accessible name. */
58
+ closeLabel?: string;
59
+ /** What the counter at the end of the stack says when the limit is holding toasts back. */
60
+ overflowLabel?(count: number): React.ReactNode;
61
+ /**
62
+ * A key that moves focus to the stack from anywhere on the page, since toasts steal none. Default
63
+ * `'F6'`; `'alt+t'` and the like also work, and `false` turns it off.
64
+ */
65
+ hotkey?: string | false;
66
+ /** A store of your own — for a second, independent stack, or for a test that must not share state. */
67
+ store?: ToastStore<Content>;
68
+ }
69
+ /**
70
+ * The viewport every toast is drawn in, and the live region they are announced from. Render one, once,
71
+ * near the root of the app; everything after that is `toast()`, from wherever the message comes from.
72
+ *
73
+ * ```tsx
74
+ * <Toaster position="bottom-end" />
75
+ * // anywhere at all, React or not:
76
+ * toast.success('Saved');
77
+ * ```
78
+ *
79
+ * **It is in the top layer and there is no portal.** The viewport carries `popover="manual"` and is shown
80
+ * as soon as it mounts, so it paints over every stacking context and out of every clipped or transformed
81
+ * ancestor — and because it stays where it was declared, it inherits the theme, the custom properties and
82
+ * the text direction around it. `manual` rather than `auto` because a stack of messages owns no dismissal:
83
+ * a press outside must reach the page, not close the toasts.
84
+ *
85
+ * **A press in the gaps goes through to the page.** The viewport is a corner-sized box that would
86
+ * otherwise swallow every click in it, so it takes no pointer events at all and the toasts take them back.
87
+ *
88
+ * **The limit is a queue, not a cap.** A toast past it waits with its timer unstarted, so nothing expires
89
+ * that was never on screen, and the counter at the end of the stack says how many are waiting.
90
+ *
91
+ * @a11y The viewport is a polite live region that exists from the moment it mounts, **before there is
92
+ * anything in it** — an `aria-live` element inserted together with its content is not reliably announced.
93
+ * @a11y An error toast is `role="alert"`, which is assertive; every other kind is announced politely by
94
+ * the region around it. A toast is never focused on arrival, so nothing is taken away from the keyboard.
95
+ * @a11y Timers stop while the pointer is over the stack, while anything in it has focus, and while the
96
+ * tab is in the background — WCAG 2.2.1, and the reason a toast may carry a control at all.
97
+ * @a11y The accent bar says the kind a second time; it is never the only signal, since the message itself
98
+ * is what says what happened.
99
+ * @keyboard F6 — Moves focus to the stack from anywhere on the page. Configurable through `hotkey`.
100
+ * @keyboard Tab — Through the toasts and their controls, in the order they are on screen.
101
+ * @keyboard Escape — Dismisses the toast focus is in, and hands focus back to where it came from once
102
+ * the stack is empty.
103
+ */
104
+ declare function ToasterImpl<TKey extends keyof ComponentsAndVariants = 'toaster'>(props: ToasterProps<TKey>): import("react").JSX.Element | null;
105
+ declare const Toaster: typeof ToasterImpl;
106
+ export default Toaster;