@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("../client.cjs"),n=require("../effects.cjs"),r=require("../box.cjs"),i=require("../behavior.cjs"),a=require("../identity.cjs"),o=require("./semantics.cjs");let s=require("react"),c=require("react/jsx-runtime");var l=0;function u(r){let{classNames:i,styleElements:a}=t.i({overflow:`hidden`},!1),o=i.slice(1).join(` `);return n.n(()=>{let t=e.n();if(!(!r||!t||!o))return l+=1,t.classList.add(o),()=>{--l,l===0&&t.classList.remove(o)}},[r,o]),a}var d=(0,s.createContext)(null);function f(e){let t=(0,s.useContext)(d);if(!t)throw Error(`<${e}> must be rendered inside a <Dialog>.`);return t}function p(e){return(0,c.jsx)(h,{role:`dialog`,...e})}function m(e){return(0,c.jsx)(h,{role:`alertdialog`,...e,modal:!0,dismissible:!1})}function h(t){let{role:o,trigger:l,children:f,open:p,defaultOpen:m=!1,onOpenChange:h,label:_,labelledBy:v,describedBy:y,modal:b=!0,dismissible:x=!0,lockScroll:S=b,initialFocus:C,props:w,...T}=t,E=a.t(`dialog`),D=T.id??E,[O,k]=i.i({value:p,defaultValue:m,onChange:h}),[A,j]=(0,s.useState)(null),[M,N]=(0,s.useState)(null),[P,F]=(0,s.useState)(!1),[I,L]=(0,s.useState)({title:0,description:0}),R=u(O&&S);i.n({enabled:O,returnTo:M});let z=(0,s.useCallback)(e=>(L(t=>({...t,[e]:t[e]+1})),()=>L(t=>({...t,[e]:t[e]-1}))),[]),B=(0,s.useMemo)(()=>({titleId:`${D}-title`,descriptionId:`${D}-description`,register:z}),[D,z]);g({dialog:A,isOpen:O,domOpen:P,setDomOpen:F,setOpen:k,modal:b,dismissible:x,triggerElement:M}),n.n(()=>{let t=e.c(C);!O||!t||t.focus()},[O,C]);let V=i.a(e=>{k(e=>!e,{reason:`trigger`,event:e})}),H=(0,s.useMemo)(()=>({ref:N,props:{"aria-expanded":O,"aria-haspopup":`dialog`,"aria-controls":O?D:void 0,onClick:V}}),[D,V,O]),U=T;return(0,c.jsxs)(c.Fragment,{children:[R,l?.(H),(0,c.jsx)(d.Provider,{value:B,children:(0,c.jsx)(r.default,{ref:j,tag:`dialog`,component:`dialog`,...U,id:D,props:{role:o,"aria-label":I.title||v?void 0:_,"aria-labelledby":v??(I.title?B.titleId:void 0),"aria-describedby":y??(I.description?B.descriptionId:void 0),...w},children:f})})]})}function g(t){let{dialog:r,isOpen:a,domOpen:o,setDomOpen:c,setOpen:l,modal:u,dismissible:d,triggerElement:f}=t,p=(0,s.useRef)(`imperative`),m=e.i(),h=d?`any`:`closerequest`;n.n(()=>{!r||a===o||(c(a),a?u?r.showModal():r.show():r.close())},[r,a,o,u,c]),n.n(()=>{if(!r)return;let e=new AbortController;return r.addEventListener(`close`,e=>{c(!1),l(!1,{reason:p.current,event:e}),p.current=`imperative`},{signal:e.signal}),()=>e.abort()},[r,c,l]),n.n(()=>{if(!(!r||!m))return r.setAttribute(`closedby`,h),()=>r.removeAttribute(`closedby`)},[r,m,h]),n.n(()=>{if(!a||!r)return;let t=new AbortController,n=(e,n)=>document.addEventListener(e,n,{signal:t.signal,capture:!0});return n(`keydown`,e=>{e.key===`Escape`&&(p.current=`escape`)}),n(`pointerdown`,t=>{e.l(t,[f])?p.current=`trigger`:!e.l(t,[r])||_(r,t)?p.current=`outside-pointer`:p.current=`imperative`}),()=>t.abort()},[a,r,f]),i.r({enabled:a&&!u&&!m,inside:[r],escapeKey:!0,outsidePointer:!1,onDismiss:(e,t)=>l(!1,{reason:`escape`,event:t})}),n.n(()=>{if(!r||!a||!d||m)return;let t=new AbortController;return document.addEventListener(`pointerdown`,t=>{e.l(t,[f])||e.l(t,[r])&&!_(r,t)||l(!1,{reason:`outside-pointer`,event:t})},{signal:t.signal,capture:!0}),()=>t.abort()},[r,a,d,m,f,l])}function _(e,t){let n=e.getBoundingClientRect();return t.clientX<n.left||t.clientX>n.right||t.clientY<n.top||t.clientY>n.bottom}function v(e){let t=f(`Dialog.Title`);return n.n(()=>t.register(`title`),[t]),(0,c.jsx)(o.H2,{id:t.titleId,component:`dialog.title`,...e})}function y(e){let t=f(`Dialog.Description`);return n.n(()=>t.register(`description`),[t]),(0,c.jsx)(o.P,{id:t.descriptionId,component:`dialog.description`,...e})}v.displayName=`Dialog.Title`,y.displayName=`Dialog.Description`;var b={Title:v,Description:y},x=Object.assign(p,b),S=Object.assign(m,b);p.displayName=`Dialog`,m.displayName=`AlertDialog`,exports.AlertDialog=S,exports.default=x;
@@ -0,0 +1,151 @@
1
+ import { BoxProps } from '../box';
2
+ import { ChangeHandler } from '../react/a11y/useControllableState';
3
+ import { ComponentsAndVariants } from '@box-kite/core/types';
4
+ import { ElementLike } from '../utils/dom/domUtils';
5
+ /** Why the dialog opened or closed — `onOpenChange` gets this alongside the event that did it. */
6
+ export type DialogReason = 'trigger' | 'escape' | 'outside-pointer' | 'imperative';
7
+ /** The DOM attributes the trigger has to carry. */
8
+ export interface DialogTriggerAttributes {
9
+ 'aria-expanded': boolean;
10
+ 'aria-haspopup': 'dialog';
11
+ 'aria-controls'?: string;
12
+ onClick(event: React.MouseEvent): void;
13
+ }
14
+ /**
15
+ * What the trigger has to carry: spread it onto the control itself, not a wrapper. The `ref` is what
16
+ * focus returns to when the dialog closes, so it is not optional decoration.
17
+ *
18
+ * ```tsx
19
+ * {(trigger) => <Button {...trigger}>Edit</Button>} // a Box component
20
+ * {(trigger) => <button ref={trigger.ref} {...trigger.props}>} // a plain element
21
+ * ```
22
+ */
23
+ export interface DialogTrigger {
24
+ ref: React.RefCallback<HTMLElement>;
25
+ props: DialogTriggerAttributes;
26
+ }
27
+ type DialogBoxProps<TKey extends keyof ComponentsAndVariants> = Omit<BoxProps<'dialog', TKey>, 'open'>;
28
+ export interface DialogProps<TKey extends keyof ComponentsAndVariants = 'dialog'> extends DialogBoxProps<TKey> {
29
+ /** The control that opens it, handed the ref and props that wire it up. Leave it out to open the dialog from anywhere else. */
30
+ trigger?: (trigger: DialogTrigger) => React.ReactNode;
31
+ /** The dialog's content — a `Dialog.Title`, usually a `Dialog.Description`, and the controls. */
32
+ children?: React.ReactNode;
33
+ /** Controlled open state. Leave it out and the dialog owns it. */
34
+ open?: boolean;
35
+ /** Whether it starts open, when the dialog owns its own state. */
36
+ defaultOpen?: boolean;
37
+ /**
38
+ * Fires with the new state and why it changed — `'trigger'`, `'escape'`, `'outside-pointer'` or
39
+ * `'imperative'`. A close cannot be refused: the browser has already done it by the time this runs.
40
+ */
41
+ onOpenChange?: ChangeHandler<boolean, DialogReason>;
42
+ /** The dialog's accessible name, when no `Dialog.Title` supplies one. A dialog without a name is unusable. */
43
+ label?: string;
44
+ /** Names the dialog after an element already on the page, instead of `label` or a `Dialog.Title`. */
45
+ labelledBy?: string;
46
+ /** Describes it from an element already on the page, instead of a `Dialog.Description`. */
47
+ describedBy?: string;
48
+ /**
49
+ * Whether the rest of the page is blocked while it is open. Default `true`, which is `showModal()`: the
50
+ * top layer, a `::backdrop`, an inert page, Escape and focus containment, all the browser's.
51
+ */
52
+ modal?: boolean;
53
+ /** Whether a press outside closes it. Default `true` — `false` is what makes a decision unavoidable. */
54
+ dismissible?: boolean;
55
+ /**
56
+ * Whether the page behind it stops scrolling. Default: whatever `modal` is, because a modal dialog that
57
+ * scrolls the page behind it is the commonest complaint about every library that blocks it unasked.
58
+ */
59
+ lockScroll?: boolean;
60
+ /**
61
+ * Where focus lands on open, instead of the first focusable thing inside. An **alert dialog owes this to
62
+ * its least destructive action** — APG's rule, so that a keyboard user cannot confirm a deletion by
63
+ * reflex. An `autofocus` attribute inside does the same job with no ref.
64
+ */
65
+ initialFocus?: ElementLike;
66
+ }
67
+ /** Everything an alert dialog does not get to choose: it is modal, and a decision cannot be dismissed. */
68
+ export type AlertDialogProps<TKey extends keyof ComponentsAndVariants = 'dialog'> = Omit<DialogProps<TKey>, 'modal' | 'dismissible' | 'lockScroll'>;
69
+ /** Every Box prop, on an `<h2>` — `tag` takes any of the six headings instead. */
70
+ export type DialogTitleProps<TKey extends keyof ComponentsAndVariants = 'dialog.title'> = BoxProps<'h2', TKey>;
71
+ /** Every Box prop, on a `<p>`. */
72
+ export type DialogDescriptionProps<TKey extends keyof ComponentsAndVariants = 'dialog.description'> = BoxProps<'p', TKey>;
73
+ /**
74
+ * A modal dialog on the platform's own `<dialog>`: `showModal()` supplies the top layer, the
75
+ * `::backdrop`, an inert page behind it, Escape, focus containment and focus return — so none of that is
76
+ * written here.
77
+ *
78
+ * ```tsx
79
+ * <Dialog trigger={(t) => <Button {...t}>Rename</Button>}>
80
+ * <Dialog.Title>Rename this view</Dialog.Title>
81
+ * <Textbox label="Name" />
82
+ * </Dialog>
83
+ * ```
84
+ *
85
+ * **The dialog is always rendered**, and closed means `display: none` — the same shape as `<Popover>`, and
86
+ * what lets the browser own show and hide. The exit is therefore a plain CSS transition rather than a
87
+ * `<Presence>`, since nothing unmounts; content that is expensive to render should be gated by the
88
+ * consumer with `{open && <Heavy />}`.
89
+ *
90
+ * **A close cannot be refused.** The `cancel` event is cancelable, but by the time `onOpenChange` runs the
91
+ * browser has closed the dialog, so a controlled `<Dialog open>` hears about a dismissal afterwards and
92
+ * keeping `open` true re-shows it. Say `dismissible={false}` to make a decision unavoidable instead, which
93
+ * is what `<AlertDialog>` does.
94
+ *
95
+ * **Nothing is portalled**, so the theme, the custom properties, the text direction and the tab order
96
+ * around the declaration all reach inside — a top-layer element inherits normally (measured in Chrome
97
+ * 152, with a local `Box.Theme` wrapper around the dialog).
98
+ *
99
+ * A non-modal dialog (`modal={false}`) is `show()`: no top layer, no backdrop, nothing inert, and the UA
100
+ * positions it against its containing block rather than the viewport. It is the right shape for a
101
+ * persistent panel; for one anchored to a trigger, reach for `<Popover>`.
102
+ *
103
+ * @a11y `role="dialog"` (`alertdialog` on `<AlertDialog>`), named by a `Dialog.Title`, `label` or
104
+ * `labelledBy`, and described by a `Dialog.Description` or `describedBy`.
105
+ * @a11y The trigger carries `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls`.
106
+ * @a11y Focus is contained while a modal dialog is open and returns to the trigger when it closes, both
107
+ * from the platform. `initialFocus` is what an alert dialog needs to land on its least destructive action.
108
+ * @keyboard Escape — Closes it, from anywhere inside, and returns focus to the trigger.
109
+ * @keyboard Tab — Cycles focus inside a modal dialog and never leaves it; in a non-modal one it moves on.
110
+ * @keyboard Enter, Space — On the trigger, opens the dialog.
111
+ */
112
+ declare function DialogImpl<TKey extends keyof ComponentsAndVariants = 'dialog'>(props: DialogProps<TKey>): import("react").JSX.Element;
113
+ /**
114
+ * A dialog that interrupts to ask something: `role="alertdialog"`, always modal, and **never dismissed by
115
+ * a press outside**, because a decision that can be clicked away is one the user did not make.
116
+ *
117
+ * ```tsx
118
+ * <AlertDialog trigger={(t) => <Button {...t}>Delete</Button>} initialFocus={cancelRef}>
119
+ * <AlertDialog.Title>Delete this view?</AlertDialog.Title>
120
+ * <AlertDialog.Description>Nothing here can be undone.</AlertDialog.Description>
121
+ * <Button ref={cancelRef}>Cancel</Button>
122
+ * </AlertDialog>
123
+ * ```
124
+ *
125
+ * Escape still closes it — a keyboard user must always have a way out (APG), and the platform's own close
126
+ * request is that way. `initialFocus` is what puts focus on the least destructive action.
127
+ *
128
+ * @a11y `role="alertdialog"`, which tells a screen reader the content is an alert rather than a panel, so
129
+ * the name and description are announced together on open.
130
+ * @a11y A press outside is ignored on purpose; Escape is not, so the dialog is never a trap.
131
+ * @keyboard Escape — Closes it and returns focus to the trigger.
132
+ * @keyboard Tab — Cycles focus inside it and never leaves.
133
+ */
134
+ declare function AlertDialogImpl<TKey extends keyof ComponentsAndVariants = 'dialog'>(props: AlertDialogProps<TKey>): import("react").JSX.Element;
135
+ /**
136
+ * The dialog's heading, and what names it: rendering one is what puts `aria-labelledby` on the dialog, so
137
+ * a name and a visible title cannot drift apart. An `<h2>` by default — `tag` takes any of the six.
138
+ */
139
+ declare function DialogTitle<TKey extends keyof ComponentsAndVariants = 'dialog.title'>(props: DialogTitleProps<TKey>): import("react").JSX.Element;
140
+ /** The dialog's supporting text, and what describes it: rendering one puts `aria-describedby` on the dialog. */
141
+ declare function DialogDescription<TKey extends keyof ComponentsAndVariants = 'dialog.description'>(props: DialogDescriptionProps<TKey>): import("react").JSX.Element;
142
+ declare const Dialog: typeof DialogImpl & {
143
+ Title: typeof DialogTitle;
144
+ Description: typeof DialogDescription;
145
+ };
146
+ declare const AlertDialog: typeof AlertDialogImpl & {
147
+ Title: typeof DialogTitle;
148
+ Description: typeof DialogDescription;
149
+ };
150
+ export { AlertDialog };
151
+ export default Dialog;
@@ -0,0 +1,223 @@
1
+ "use client";
2
+ import { c as e, i as t, l as n, n as r } from "../platform.mjs";
3
+ import { i } from "../client.mjs";
4
+ import { n as a } from "../effects.mjs";
5
+ import o from "../box.mjs";
6
+ import { a as s, i as c, n as l, r as u } from "../behavior.mjs";
7
+ import { t as d } from "../identity.mjs";
8
+ import { H2 as f, P as p } from "./semantics.mjs";
9
+ import { createContext as m, useCallback as h, useContext as g, useMemo as _, useRef as v, useState as y } from "react";
10
+ import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
11
+ //#region src/react/dialog/useScrollLock.ts
12
+ var C = 0;
13
+ function w(e) {
14
+ let { classNames: t, styleElements: n } = i({ overflow: "hidden" }, !1), o = t.slice(1).join(" ");
15
+ return a(() => {
16
+ let t = r();
17
+ if (!(!e || !t || !o)) return C += 1, t.classList.add(o), () => {
18
+ --C, C === 0 && t.classList.remove(o);
19
+ };
20
+ }, [e, o]), n;
21
+ }
22
+ //#endregion
23
+ //#region src/components/dialog.tsx
24
+ var T = m(null);
25
+ function E(e) {
26
+ let t = g(T);
27
+ if (!t) throw Error(`<${e}> must be rendered inside a <Dialog>.`);
28
+ return t;
29
+ }
30
+ function D(e) {
31
+ return /* @__PURE__ */ x(k, {
32
+ role: "dialog",
33
+ ...e
34
+ });
35
+ }
36
+ function O(e) {
37
+ return /* @__PURE__ */ x(k, {
38
+ role: "alertdialog",
39
+ ...e,
40
+ modal: !0,
41
+ dismissible: !1
42
+ });
43
+ }
44
+ function k(t) {
45
+ let { role: n, trigger: r, children: i, open: u, defaultOpen: f = !1, onOpenChange: p, label: m, labelledBy: g, describedBy: v, modal: C = !0, dismissible: E = !0, lockScroll: D = C, initialFocus: O, props: k, ...j } = t, M = d("dialog"), N = j.id ?? M, [P, F] = c({
46
+ value: u,
47
+ defaultValue: f,
48
+ onChange: p
49
+ }), [I, L] = y(null), [R, z] = y(null), [B, V] = y(!1), [H, U] = y({
50
+ title: 0,
51
+ description: 0
52
+ }), W = w(P && D);
53
+ l({
54
+ enabled: P,
55
+ returnTo: R
56
+ });
57
+ let G = h((e) => (U((t) => ({
58
+ ...t,
59
+ [e]: t[e] + 1
60
+ })), () => U((t) => ({
61
+ ...t,
62
+ [e]: t[e] - 1
63
+ }))), []), K = _(() => ({
64
+ titleId: `${N}-title`,
65
+ descriptionId: `${N}-description`,
66
+ register: G
67
+ }), [N, G]);
68
+ A({
69
+ dialog: I,
70
+ isOpen: P,
71
+ domOpen: B,
72
+ setDomOpen: V,
73
+ setOpen: F,
74
+ modal: C,
75
+ dismissible: E,
76
+ triggerElement: R
77
+ }), a(() => {
78
+ let t = e(O);
79
+ !P || !t || t.focus();
80
+ }, [P, O]);
81
+ let q = s((e) => {
82
+ F((e) => !e, {
83
+ reason: "trigger",
84
+ event: e
85
+ });
86
+ }), J = _(() => ({
87
+ ref: z,
88
+ props: {
89
+ "aria-expanded": P,
90
+ "aria-haspopup": "dialog",
91
+ "aria-controls": P ? N : void 0,
92
+ onClick: q
93
+ }
94
+ }), [
95
+ N,
96
+ q,
97
+ P
98
+ ]), Y = j;
99
+ return /* @__PURE__ */ S(b, { children: [
100
+ W,
101
+ r?.(J),
102
+ /* @__PURE__ */ x(T.Provider, {
103
+ value: K,
104
+ children: /* @__PURE__ */ x(o, {
105
+ ref: L,
106
+ tag: "dialog",
107
+ component: "dialog",
108
+ ...Y,
109
+ id: N,
110
+ props: {
111
+ role: n,
112
+ "aria-label": H.title || g ? void 0 : m,
113
+ "aria-labelledby": g ?? (H.title ? K.titleId : void 0),
114
+ "aria-describedby": v ?? (H.description ? K.descriptionId : void 0),
115
+ ...k
116
+ },
117
+ children: i
118
+ })
119
+ })
120
+ ] });
121
+ }
122
+ function A(e) {
123
+ let { dialog: r, isOpen: i, domOpen: o, setDomOpen: s, setOpen: c, modal: l, dismissible: d, triggerElement: f } = e, p = v("imperative"), m = t(), h = d ? "any" : "closerequest";
124
+ a(() => {
125
+ !r || i === o || (s(i), i ? l ? r.showModal() : r.show() : r.close());
126
+ }, [
127
+ r,
128
+ i,
129
+ o,
130
+ l,
131
+ s
132
+ ]), a(() => {
133
+ if (!r) return;
134
+ let e = new AbortController();
135
+ return r.addEventListener("close", (e) => {
136
+ s(!1), c(!1, {
137
+ reason: p.current,
138
+ event: e
139
+ }), p.current = "imperative";
140
+ }, { signal: e.signal }), () => e.abort();
141
+ }, [
142
+ r,
143
+ s,
144
+ c
145
+ ]), a(() => {
146
+ if (!(!r || !m)) return r.setAttribute("closedby", h), () => r.removeAttribute("closedby");
147
+ }, [
148
+ r,
149
+ m,
150
+ h
151
+ ]), a(() => {
152
+ if (!i || !r) return;
153
+ let e = new AbortController(), t = (t, n) => document.addEventListener(t, n, {
154
+ signal: e.signal,
155
+ capture: !0
156
+ });
157
+ return t("keydown", (e) => {
158
+ e.key === "Escape" && (p.current = "escape");
159
+ }), t("pointerdown", (e) => {
160
+ n(e, [f]) ? p.current = "trigger" : !n(e, [r]) || j(r, e) ? p.current = "outside-pointer" : p.current = "imperative";
161
+ }), () => e.abort();
162
+ }, [
163
+ i,
164
+ r,
165
+ f
166
+ ]), u({
167
+ enabled: i && !l && !m,
168
+ inside: [r],
169
+ escapeKey: !0,
170
+ outsidePointer: !1,
171
+ onDismiss: (e, t) => c(!1, {
172
+ reason: "escape",
173
+ event: t
174
+ })
175
+ }), a(() => {
176
+ if (!r || !i || !d || m) return;
177
+ let e = new AbortController();
178
+ return document.addEventListener("pointerdown", (e) => {
179
+ n(e, [f]) || n(e, [r]) && !j(r, e) || c(!1, {
180
+ reason: "outside-pointer",
181
+ event: e
182
+ });
183
+ }, {
184
+ signal: e.signal,
185
+ capture: !0
186
+ }), () => e.abort();
187
+ }, [
188
+ r,
189
+ i,
190
+ d,
191
+ m,
192
+ f,
193
+ c
194
+ ]);
195
+ }
196
+ function j(e, t) {
197
+ let n = e.getBoundingClientRect();
198
+ return t.clientX < n.left || t.clientX > n.right || t.clientY < n.top || t.clientY > n.bottom;
199
+ }
200
+ function M(e) {
201
+ let t = E("Dialog.Title");
202
+ return a(() => t.register("title"), [t]), /* @__PURE__ */ x(f, {
203
+ id: t.titleId,
204
+ component: "dialog.title",
205
+ ...e
206
+ });
207
+ }
208
+ function N(e) {
209
+ let t = E("Dialog.Description");
210
+ return a(() => t.register("description"), [t]), /* @__PURE__ */ x(p, {
211
+ id: t.descriptionId,
212
+ component: "dialog.description",
213
+ ...e
214
+ });
215
+ }
216
+ M.displayName = "Dialog.Title", N.displayName = "Dialog.Description";
217
+ var P = {
218
+ Title: M,
219
+ Description: N
220
+ }, F = Object.assign(D, P), I = Object.assign(O, P);
221
+ D.displayName = "Dialog", O.displayName = "AlertDialog";
222
+ //#endregion
223
+ export { I as AlertDialog, F as default };
@@ -1 +1 @@
1
- "use client";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../effects.cjs"),t=require("../box.cjs"),n=require("../behavior.cjs"),r=require("./baseSvg.cjs"),i=require("./button.cjs"),a=require("./flex.cjs"),o=require("./checkbox.cjs"),s=require("./textbox.cjs"),c=require("./overlay.cjs"),l=require("./presence.cjs");let u=require("react"),d=require("react/jsx-runtime");var f=(0,u.createContext)(null);function p(){let e=(0,u.useContext)(f);if(!e)throw Error(`Dropdown sub-components must be used within Dropdown`);return e}var m={item:`dropdown.item`,unselect:`dropdown.unselect`,selectAll:`dropdown.selectAll`};function h({row:e,index:n}){let{valueToUse:r,multiple:i,variant:a,showCheckbox:s,selectRow:c,optionId:l,activeIndex:u,rowRef:f,isRowDisabled:h}=p(),g=e.kind===`item`,_=h(n),v=g?r.includes(e.element.props.value):e.kind===`unselect`&&r.length===0,{value:ee,onClick:y,children:b,...x}=e.element.props,te=s&&i&&g;return(0,d.jsx)(t.default,{ref:f(n),component:m[e.kind],variant:[a,g?{multiple:i,highlighted:n===u}:{highlighted:n===u}],selected:v,...x,id:l(n),children:te?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(o.default,{readOnly:!0,checked:v,me:2,props:{tabIndex:-1,"aria-hidden":!0}}),b]}):b,props:{role:`option`,..._?{"aria-disabled":!0}:{},...x.props,onClick:_?void 0:e=>{y?.(e),c(n,e)}}})}var g=(0,u.memo)(h,(e,t)=>e.row.element===t.row.element&&e.index===t.index);function _(e,t,n){return e?{role:`listbox`,"aria-labelledby":n,...t?{"aria-multiselectable":!0}:{}}:{role:`status`}}function v(e){let{presence:n,rows:r,emptyItem:i,triggerRef:a,popupRef:o,listboxId:s,labelledBy:l,itemsProps:f}=e,{present:m,ref:h,props:v}=n,{multiple:y,variant:b}=p(),[x,te]=(0,u.useState)(!1),ne=x?0:a.current?.getBoundingClientRect().height??0,S=(0,u.useCallback)(e=>{let t=e.top-e.windowScrollY>window.innerHeight/2;te(e=>e===t?e:t)},[]);return(0,d.jsx)(t.default,{position:`absolute`,inset:0,children:(0,d.jsx)(c.default,{ref:o,minWidth:`fit-content`,style:{transform:x?`translateY(calc(-100% - 2px))`:`translateY(${ne}px)`},onPositionChange:S,children:(0,d.jsxs)(t.default,{ref:h,component:`dropdown.items`,...f,variant:[b,{up:x,closed:!m&&!x,closedUp:!m&&x}],id:s,props:{..._(r.length>0,y,l),...v},children:[r.map((e,t)=>(0,d.jsx)(g,{row:e,index:t},ee(e,t))),r.length===0&&i&&(0,d.jsx)(t.default,{component:`dropdown.emptyItem`,variant:b,...i.props})]})})})}function ee(e,t){return e.kind===`item`?e.element.props.value:`${e.kind}-${t}`}v.displayName=`DropdownItems`;function y({id:e,value:t,onValueChange:n,placeholder:r,inputRef:i,comboboxProps:o,onOpen:c}){let l=(0,u.useCallback)(e=>n(e.target.value),[n]),f=(0,u.useCallback)(e=>{e.stopPropagation(),c(e)},[c]);return(0,d.jsx)(a.default,{ai:`center`,position:`absolute`,inset:0,p:3,children:(0,d.jsx)(s.default,{clean:!0,id:e,value:t,placeholder:r,onChange:l,ref:i,color:`currentColor`,width:`fit`,props:{role:`combobox`,"aria-autocomplete":`list`,autoComplete:`off`,spellCheck:!1,...o,onClick:f}})})}function b(e){if(e==null)return``;if(typeof e==`object`){let t=e.props?.children;return t==null?``:typeof t==`object`?(Array.isArray(t)?t:[t]).map(e=>b(e)).join(``):t.toString()}return e.toString()}function x(e){let t=e?.props?.disabled;return(Array.isArray(t)?t[0]:t)===!0}function te(e){return e.key.length===1&&!e.ctrlKey&&!e.metaKey&&!e.altKey}var ne=new Set([` `,`Home`,`End`,`ArrowLeft`,`ArrowRight`]);function S(o,c){let{name:p,defaultValue:m,value:h,multiple:g=!1,isSearchable:_,searchPlaceholder:ee,children:S,hideIcon:C,showCheckbox:w=!1,label:re,labelProps:ie,itemsProps:ae,iconProps:oe,onChange:T,props:se,...E}=o,[ce,D]=(0,u.useState)(Array.isArray(m)?m:m?[m]:[]),le=`value`in o,O=(0,u.useMemo)(()=>le?Array.isArray(h)?h:h?[h]:[]:ce,[le,h,ce]),[ue,de]=(0,u.useState)(null),[k,A]=(0,u.useState)(!1),j=(0,u.useRef)(null),fe=(0,u.useCallback)(e=>{j.current=e},[]),pe=(0,u.useRef)(null),M=(0,u.useRef)(null),N=n.n(`dropdown`),P=E.id??`${N}-trigger`,me=`${N}-listbox`,he=`${N}-label`,F=re!=null&&re!==!1,I=(0,u.useCallback)(e=>`${N}-option-${e}`,[N]),L=n.o((e=!1)=>{A(!1),e||de(null)}),R=(0,u.useMemo)(()=>(Array.isArray(S)?S:[S]).flatMap(e=>e).filter(Boolean),[S]),z=(0,u.useMemo)(()=>R.filter(e=>e.type?.displayName===`DropdownItem`),[R]),ge=(0,u.useMemo)(()=>{let e=new Map;for(let t of z)e.set(t,b(t));return e},[z]),B=(0,u.useCallback)(e=>ge.get(e)??b(e),[ge]),V=_?ue??``:``,H=(0,u.useMemo)(()=>V?z.filter(e=>B(e).toLowerCase().includes(V.toLowerCase())):z,[V,z,B]),U=(0,u.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownUnselect`),[R]),W=(0,u.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownSelectAll`),[R]),_e=(0,u.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownEmptyItem`),[R]),G=(0,u.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownDisplay`),[R]),K=(0,u.useMemo)(()=>!_||G?``:z.filter(e=>O.includes(e.props.value)).map(e=>B(e)).join(`, `),[_,G,z,O,B]),ve=!!(W&&g&&H.length>O.length),ye=!!(U&&H.length>0&&!ve),q=(0,u.useMemo)(()=>{let e=[];ye&&U&&e.push({kind:`unselect`,element:U}),ve&&W&&e.push({kind:`selectAll`,element:W});for(let t of H)e.push({kind:`item`,element:t});return e},[ye,U,ve,W,H]),J=(0,u.useCallback)(e=>x(q[e]?.element),[q]),be=(0,u.useCallback)(e=>{let t=q[e];return t?B(t.element):``},[q,B]),xe=(0,u.useMemo)(()=>{if(_&&(k||K!==``))return null;if(G)return typeof G.props.children==`function`?G.props.children(O,k):G.props.children;let e=H.filter(e=>O.includes(e.props.value));if(g&&e.length>1)return e.map(e=>B(e)).join(`, `);let t=e.at(0);return t?.props.children??t?.props.value??(g?null:U?.props.children)},[g,H,O,U,k,_,K,G,B]),Se=(0,u.useCallback)((e,...t)=>{if(t.length===0)D([]),T?.(void 0,[]);else if(g&&t.length>1){let e=t.map(e=>e.props.value);D(e),T?.(void 0,e)}else if(t.length===1){let e=t[0];if(g){let t=O.filter(t=>t!==e.props.value);t.length===O.length&&t.push(e.props.value),D(t),T?.(e.props.value,t)}else D([e.props.value]),T?.(e.props.value,[e.props.value])}e.stopPropagation(),g?_&&setTimeout(()=>M.current?.focus(),0):L()},[g,_,O,T,L]),Y=n.o((e,t)=>{let n=q[e];!n||J(e)||(n.kind===`unselect`?Se(t):n.kind===`selectAll`?Se(t,...z):Se(t,n.element))}),X=n.t({count:q.length,focusItems:!1,defaultActiveIndex:-1,isDisabled:J,textOf:_?void 0:be,onSelect:Y}),Ce=X.setActiveIndex,we=(0,u.useCallback)(e=>Ce(-1,{reason:`programmatic`,event:e}),[Ce]);n.i({enabled:k,inside:[j,pe],onDismiss:e=>L(e===`escape`)}),n.r({enabled:k,returnTo:_?M:j}),(0,u.useEffect)(()=>{k&&M.current?.focus()},[k]);let Z=X.activeIndex,Te=X.activeItem;e.n(()=>{!k||Z===-1||Te()?.scrollIntoView?.({block:`nearest`})},[k,Z,Te]);let Ee=e=>{let t=e===`first`?1:-1;for(let n=e===`first`?0:q.length-1;n>=0&&n<q.length;n+=t)if(!J(n))return n;return-1},Q=e=>{let t=q.findIndex(e=>e.kind===`item`&&O.includes(e.element.props.value));return t!==-1&&!J(t)?t:e===`none`?-1:Ee(e)},$=(e,t)=>{A(!0),X.setActiveIndex(e,{reason:`programmatic`,event:t})},De=n.o(e=>{k?L():$(Q(`none`),e)}),Oe=n.o(e=>{k||$(Q(`none`),e)}),ke=n.o(e=>{de(e),k||A(!0),we()}),Ae=e=>{let{key:t}=e;if(_){if(t===`ArrowDown`||t===`ArrowUp`){e.preventDefault(),$(Q(t===`ArrowUp`?`last`:e.altKey?`none`:`first`),e);return}t===`Escape`&&de(``);return}if(t===`ArrowDown`||t===`Enter`||t===` `){e.preventDefault(),$(Q(e.altKey?`none`:`first`),e);return}if(t===`ArrowUp`){e.preventDefault(),$(Q(`last`),e);return}if(t===`Home`||t===`End`){e.preventDefault(),$(Ee(t===`Home`?`first`:`last`),e);return}te(e)&&(A(!0),X.onKeyDown(e))},je=n.o(e=>{if(se?.onKeyDown?.(e),!e.defaultPrevented){if(!k){Ae(e);return}if(e.key===`Tab`){!g&&X.activeIndex!==-1&&Y(X.activeIndex,e),L();return}if(e.altKey&&e.key===`ArrowUp`){e.preventDefault(),X.activeIndex!==-1&&Y(X.activeIndex,e),L();return}if(_&&ne.has(e.key)){we(e);return}X.onKeyDown(e)}}),Me=q.length>0||!!_e,Ne=k&&Z!==-1&&Me?I(Z):void 0,Pe=X.itemProps,Fe=(0,u.useMemo)(()=>({valueToUse:O,multiple:g,variant:E.variant,showCheckbox:w,selectRow:Y,optionId:I,activeIndex:Z,rowRef:e=>Pe(e).ref,isRowDisabled:J}),[O,g,E.variant,w,Y,I,Z,Pe,J]),Ie={"aria-expanded":k,"aria-controls":k&&Me?me:void 0,"aria-activedescendant":Ne,"aria-labelledby":F?he:void 0,...se,onKeyDown:je},Le=O.map(e=>{let t=JSON.stringify(e);return(0,d.jsx)(s.default,{ref:c,name:p,type:`hidden`,value:t??``},t)}),Re=!C&&(0,d.jsx)(a.default,{component:`dropdown.icon`,...oe,children:(0,d.jsx)(r.default,{viewBox:`0 0 10 6`,width:`0.6rem`,rotate:k?180:0,children:(0,d.jsx)(`path`,{stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`,d:`m1 1 4 4 4-4`})})}),ze=Me&&(0,d.jsx)(l.default,{present:k,children:e=>(0,d.jsx)(v,{presence:e,rows:q,emptyItem:_e,triggerRef:j,popupRef:pe,listboxId:me,labelledBy:F?he:P,itemsProps:ae})}),Be=_?(0,d.jsxs)(t.default,{ref:fe,component:`dropdown`,props:{onClick:De},position:`relative`,pe:C?void 0:6,minWidth:k?36:void 0,width:`fit-content`,...E,id:void 0,children:[Le,(0,d.jsx)(y,{id:P,value:ue??K,onValueChange:ke,placeholder:k?ee:void 0,inputRef:M,comboboxProps:Ie,onOpen:Oe}),xe??(0,d.jsx)(t.default,{tag:`span`,visibility:`hidden`,children:K||`\xA0`}),Re,ze]}):(0,d.jsxs)(i.default,{ref:fe,onClick:De,component:`dropdown`,type:`button`,props:{tabIndex:0,role:`combobox`,...Ie},position:`relative`,pe:C?void 0:6,width:`fit-content`,...E,id:P,children:[Le,xe??`\xA0`,Re,ze]});return(0,d.jsx)(f.Provider,{value:Fe,children:F?(0,d.jsxs)(a.default,{d:`column`,gap:1,width:`fit-content`,...ie,children:[(0,d.jsx)(t.default,{tag:`span`,id:he,children:re}),Be]}):Be})}function C(e){let t=e=>null;return t.displayName=e,t}var w=(0,u.forwardRef)(S);w.Item=C(`DropdownItem`),w.Unselect=C(`DropdownUnselect`),w.SelectAll=C(`DropdownSelectAll`),w.EmptyItem=C(`DropdownEmptyItem`),w.Display=C(`DropdownDisplay`),w.displayName=`Dropdown`,exports.default=w;
1
+ "use client";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../effects.cjs"),t=require("../box.cjs"),n=require("../behavior.cjs"),r=require("../identity.cjs"),i=require("./baseSvg.cjs"),a=require("./button.cjs"),o=require("./flex.cjs"),s=require("./checkbox.cjs"),c=require("./overlay.cjs"),l=require("./presence.cjs"),u=require("./textbox.cjs");let d=require("react"),f=require("react/jsx-runtime");var p=(0,d.createContext)(null);function m(){let e=(0,d.useContext)(p);if(!e)throw Error(`Dropdown sub-components must be used within Dropdown`);return e}var h={item:`dropdown.item`,unselect:`dropdown.unselect`,selectAll:`dropdown.selectAll`};function g({row:e,index:n}){let{valueToUse:r,multiple:i,variant:a,showCheckbox:o,selectRow:c,optionId:l,activeIndex:u,rowRef:d,isRowDisabled:p}=m(),g=e.kind===`item`,_=p(n),v=g?r.includes(e.element.props.value):e.kind===`unselect`&&r.length===0,{value:ee,onClick:y,children:b,...x}=e.element.props,S=o&&i&&g;return(0,f.jsx)(t.default,{ref:d(n),component:h[e.kind],variant:[a,g?{multiple:i,highlighted:n===u}:{highlighted:n===u}],selected:v,...x,id:l(n),children:S?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(s.default,{readOnly:!0,checked:v,me:2,props:{tabIndex:-1,"aria-hidden":!0}}),b]}):b,props:{role:`option`,..._?{"aria-disabled":!0}:{},...x.props,onClick:_?void 0:e=>{y?.(e),c(n,e)}}})}var _=(0,d.memo)(g,(e,t)=>e.row.element===t.row.element&&e.index===t.index);function v(e,t,n){return e?{role:`listbox`,"aria-labelledby":n,...t?{"aria-multiselectable":!0}:{}}:{role:`status`}}function ee(e){let{presence:n,rows:r,emptyItem:i,triggerRef:a,popupRef:o,listboxId:s,labelledBy:l,itemsProps:u}=e,{present:p,ref:h,props:g}=n,{multiple:ee,variant:b}=m(),[x,S]=(0,d.useState)(!1),te=(0,d.useCallback)(e=>S(e===`top`),[]);return(0,f.jsx)(c.default,{ref:o,anchor:a,side:`bottom`,align:`start`,offset:.5,onSideChange:te,children:(0,f.jsxs)(t.default,{ref:h,component:`dropdown.items`,...u,variant:[b,{closed:!p&&!x,closedUp:!p&&x}],id:s,props:{...v(r.length>0,ee,l),...g},children:[r.map((e,t)=>(0,f.jsx)(_,{row:e,index:t},y(e,t))),r.length===0&&i&&(0,f.jsx)(t.default,{component:`dropdown.emptyItem`,variant:b,...i.props})]})})}function y(e,t){return e.kind===`item`?e.element.props.value:`${e.kind}-${t}`}ee.displayName=`DropdownItems`;function b({id:e,value:t,onValueChange:n,placeholder:r,inputRef:i,comboboxProps:a,onOpen:s}){let c=(0,d.useCallback)(e=>n(e.target.value),[n]),l=(0,d.useCallback)(e=>{e.stopPropagation(),s(e)},[s]);return(0,f.jsx)(o.default,{ai:`center`,position:`absolute`,inset:0,p:3,children:(0,f.jsx)(u.default,{clean:!0,id:e,value:t,placeholder:r,onChange:c,ref:i,color:`currentColor`,width:`fit`,props:{role:`combobox`,"aria-autocomplete":`list`,autoComplete:`off`,spellCheck:!1,...a,onClick:l}})})}function x(e){if(e==null)return``;if(typeof e==`object`){let t=e.props?.children;return t==null?``:typeof t==`object`?(Array.isArray(t)?t:[t]).map(e=>x(e)).join(``):t.toString()}return e.toString()}function S(e){return e==null?[]:Array.isArray(e)?e:[e]}function te(e){let t=e?.props?.disabled;return(Array.isArray(t)?t[0]:t)===!0}function ne(e){return e.key.length===1&&!e.ctrlKey&&!e.metaKey&&!e.altKey}var re=new Set([` `,`Home`,`End`,`ArrowLeft`,`ArrowRight`]);function ie(s,c){let{name:m,defaultValue:h,value:g,defaultOpen:_,multiple:v=!1,isSearchable:y,searchPlaceholder:ie,children:C,hideIcon:w,showCheckbox:ae=!1,label:oe,labelProps:se,itemsProps:ce,iconProps:le,onValueChange:ue,onChange:de,props:fe,...T}=s,E=(0,d.useRef)(void 0),pe=n.a((e,t)=>{ue?.(v?e:e[0],t),de?.(E.current,e)}),me=`value`in s,he=(0,d.useMemo)(()=>me?S(g):void 0,[me,g]),[D,O]=n.i({value:he,defaultValue:()=>S(h),onChange:pe}),[ge,_e]=(0,d.useState)(null),[k,A]=(0,d.useState)(!!_),j=(0,d.useRef)(null),ve=(0,d.useCallback)(e=>{j.current=e},[]),ye=(0,d.useRef)(null),M=(0,d.useRef)(null),N=r.t(`dropdown`),P=T.id??`${N}-trigger`,be=`${N}-listbox`,F=`${N}-label`,I=oe!=null&&oe!==!1,xe=(0,d.useCallback)(e=>`${N}-option-${e}`,[N]),L=n.a((e=!1)=>{A(!1),e||_e(null)}),R=(0,d.useMemo)(()=>(Array.isArray(C)?C:[C]).flatMap(e=>e).filter(Boolean),[C]),z=(0,d.useMemo)(()=>R.filter(e=>e.type?.displayName===`DropdownItem`),[R]),Se=(0,d.useMemo)(()=>{let e=new Map;for(let t of z)e.set(t,x(t));return e},[z]),B=(0,d.useCallback)(e=>Se.get(e)??x(e),[Se]),Ce=y?ge??``:``,V=(0,d.useMemo)(()=>Ce?z.filter(e=>B(e).toLowerCase().includes(Ce.toLowerCase())):z,[Ce,z,B]),H=(0,d.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownUnselect`),[R]),U=(0,d.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownSelectAll`),[R]),we=(0,d.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownEmptyItem`),[R]),W=(0,d.useMemo)(()=>R.find(e=>e.type?.displayName===`DropdownDisplay`),[R]),G=(0,d.useMemo)(()=>!y||W?``:z.filter(e=>D.includes(e.props.value)).map(e=>B(e)).join(`, `),[y,W,z,D,B]),Te=!!(U&&v&&V.length>D.length),Ee=!!(H&&V.length>0&&!Te),K=(0,d.useMemo)(()=>{let e=[];Ee&&H&&e.push({kind:`unselect`,element:H}),Te&&U&&e.push({kind:`selectAll`,element:U});for(let t of V)e.push({kind:`item`,element:t});return e},[Ee,H,Te,U,V]),q=(0,d.useCallback)(e=>te(K[e]?.element),[K]),De=(0,d.useCallback)(e=>{let t=K[e];return t?B(t.element):``},[K,B]),Oe=(0,d.useMemo)(()=>{if(y&&(k||G!==``))return null;if(W)return typeof W.props.children==`function`?W.props.children(D,k):W.props.children;let e=V.filter(e=>D.includes(e.props.value));if(v&&e.length>1)return e.map(e=>B(e)).join(`, `);let t=e.at(0);return t?.props.children??t?.props.value??(v?null:H?.props.children)},[v,V,D,H,k,y,G,W,B]),ke=(0,d.useCallback)((e,...t)=>{if(t.length===0)E.current=void 0,O([],{reason:`clear`,event:e});else if(v&&t.length>1)E.current=void 0,O(t.map(e=>e.props.value),{reason:`select-all`,event:e});else if(t.length===1){let n=t[0];if(E.current=n.props.value,v){let t=D.filter(e=>e!==n.props.value),r=t.length!==D.length;r||t.push(n.props.value),O(t,{reason:r?`deselect`:`select`,event:e})}else O([n.props.value],{reason:`select`,event:e})}e.stopPropagation(),v?y&&setTimeout(()=>M.current?.focus(),0):L()},[v,y,D,O,L]),J=n.a((e,t)=>{let n=K[e];!n||q(e)||(n.kind===`unselect`?ke(t):n.kind===`selectAll`?ke(t,...z):ke(t,n.element))}),Ae=e=>{let t=e===`first`?1:-1;for(let n=e===`first`?0:K.length-1;n>=0&&n<K.length;n+=t)if(!q(n))return n;return-1},Y=e=>{let t=K.findIndex(e=>e.kind===`item`&&D.includes(e.element.props.value));return t!==-1&&!q(t)?t:e===`none`?-1:Ae(e)},X=n.t({count:K.length,focusItems:!1,defaultActiveIndex:_?Y(`none`):-1,isDisabled:q,textOf:y?void 0:De,onSelect:J}),je=X.setActiveIndex,Me=(0,d.useCallback)(e=>je(-1,{reason:`programmatic`,event:e}),[je]);n.r({enabled:k,inside:[j,ye],onDismiss:e=>L(e===`escape`)}),n.n({enabled:k,returnTo:y?M:j}),(0,d.useEffect)(()=>{k&&M.current?.focus()},[k]);let Z=X.activeIndex,Ne=X.activeItem;e.n(()=>{!k||Z===-1||Ne()?.scrollIntoView?.({block:`nearest`})},[k,Z,Ne]);let Q=(e,t)=>{A(!0),X.setActiveIndex(e,{reason:`programmatic`,event:t})},Pe=n.a(e=>{k?L():Q(Y(`none`),e)}),Fe=n.a(e=>{k||Q(Y(`none`),e)}),Ie=n.a(e=>{_e(e),k||A(!0),Me()}),Le=e=>{let{key:t}=e;if(y){if(t===`ArrowDown`||t===`ArrowUp`){e.preventDefault(),Q(Y(t===`ArrowUp`?`last`:e.altKey?`none`:`first`),e);return}t===`Escape`&&_e(``);return}if(t===`ArrowDown`||t===`Enter`||t===` `){e.preventDefault(),Q(Y(e.altKey?`none`:`first`),e);return}if(t===`ArrowUp`){e.preventDefault(),Q(Y(`last`),e);return}if(t===`Home`||t===`End`){e.preventDefault(),Q(Ae(t===`Home`?`first`:`last`),e);return}ne(e)&&(A(!0),X.onKeyDown(e))},Re=n.a(e=>{if(fe?.onKeyDown?.(e),!e.defaultPrevented){if(!k){Le(e);return}if(e.key===`Tab`){!v&&X.activeIndex!==-1&&J(X.activeIndex,e),L();return}if(e.altKey&&e.key===`ArrowUp`){e.preventDefault(),X.activeIndex!==-1&&J(X.activeIndex,e),L();return}if(y&&re.has(e.key)){Me(e);return}X.onKeyDown(e)}}),$=K.length>0||!!we,ze=k&&Z!==-1&&$?xe(Z):void 0,Be=X.itemProps,Ve=(0,d.useMemo)(()=>({valueToUse:D,multiple:v,variant:T.variant,showCheckbox:ae,selectRow:J,optionId:xe,activeIndex:Z,rowRef:e=>Be(e).ref,isRowDisabled:q}),[D,v,T.variant,ae,J,xe,Z,Be,q]),He={"aria-expanded":k,"aria-controls":k&&$?be:void 0,"aria-activedescendant":ze,"aria-labelledby":I?F:void 0,...fe,onKeyDown:Re},Ue=D.map(e=>{let t=JSON.stringify(e);return(0,f.jsx)(u.default,{ref:c,name:m,type:`hidden`,value:t??``},t)}),We=!w&&(0,f.jsx)(o.default,{component:`dropdown.icon`,...le,children:(0,f.jsx)(i.default,{viewBox:`0 0 10 6`,width:`0.6rem`,rotate:k?180:0,children:(0,f.jsx)(`path`,{stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`,d:`m1 1 4 4 4-4`})})}),Ge=$&&(0,f.jsx)(l.default,{present:k,children:e=>(0,f.jsx)(ee,{presence:e,rows:K,emptyItem:we,triggerRef:j,popupRef:ye,listboxId:be,labelledBy:I?F:P,itemsProps:ce})}),Ke=y?(0,f.jsxs)(t.default,{ref:ve,component:`dropdown`,props:{onClick:Pe},position:`relative`,pe:w?void 0:6,minWidth:k?36:void 0,width:`fit-content`,...T,id:void 0,children:[Ue,(0,f.jsx)(b,{id:P,value:ge??G,onValueChange:Ie,placeholder:k?ie:void 0,inputRef:M,comboboxProps:He,onOpen:Fe}),Oe??(0,f.jsx)(t.default,{tag:`span`,visibility:`hidden`,children:G||`\xA0`}),We]}):(0,f.jsxs)(a.default,{ref:ve,onClick:Pe,component:`dropdown`,type:`button`,props:{tabIndex:0,role:`combobox`,...He},position:`relative`,pe:w?void 0:6,width:`fit-content`,...T,id:P,children:[Ue,Oe??`\xA0`,We]});return(0,f.jsx)(p.Provider,{value:Ve,children:I?(0,f.jsxs)(o.default,{d:`column`,gap:1,width:`fit-content`,...se,children:[(0,f.jsx)(t.default,{tag:`span`,id:F,children:oe}),Ke,Ge]}):(0,f.jsxs)(f.Fragment,{children:[Ke,Ge]})})}function C(e){let t=e=>null;return t.displayName=e,t}var w=(0,d.forwardRef)(ie);w.Item=C(`DropdownItem`),w.Unselect=C(`DropdownUnselect`),w.SelectAll=C(`DropdownSelectAll`),w.EmptyItem=C(`DropdownEmptyItem`),w.Display=C(`DropdownDisplay`),w.displayName=`Dropdown`,exports.default=w;
@@ -1,11 +1,27 @@
1
1
  import { RefAttributes } from 'react';
2
2
  import { BoxProps } from '../box';
3
+ import { ChangeHandler } from '../react/a11y/useControllableState';
3
4
  import { BoxStyleProps, ComponentsAndVariants } from '@box-kite/core/types';
4
5
  import { DropdownItemProps } from './dropdown/dropdownContext';
6
+ /**
7
+ * Why the selection changed. `select-all` and `clear` are the two rows that act on the whole list —
8
+ * `Dropdown.SelectAll` and `Dropdown.Unselect` — rather than on the option under the pointer.
9
+ */
10
+ export type DropdownValueReason = 'select' | 'deselect' | 'select-all' | 'clear';
5
11
  interface Props<TVal, TKey extends keyof ComponentsAndVariants = 'dropdown'> extends Omit<BoxProps<'button', TKey>, 'ref' | 'tag'> {
12
+ /** What the selection submits under: the component renders a hidden input carrying it. */
6
13
  name?: string;
14
+ /** What is selected to begin with, when the dropdown owns its own value. An array in `multiple` mode. */
7
15
  defaultValue?: TVal | TVal[];
16
+ /** Controlled selection. Pair it with `onValueChange`, or nothing the user picks sticks. */
8
17
  value?: TVal | TVal[];
18
+ /**
19
+ * Open the listbox as soon as the dropdown mounts, highlighting the selected option the way a press on
20
+ * the trigger would. For a dropdown that only exists because the user asked to choose — a grid's cell
21
+ * editor — where a second press to open a list that is the whole control is a gesture nobody meant.
22
+ */
23
+ defaultOpen?: boolean;
24
+ /** Let more than one option be chosen. Enter and Space then toggle without closing the listbox. */
9
25
  multiple?: boolean;
10
26
  /**
11
27
  * Turn the control into the APG *editable* combobox: a text field that filters the listbox, and a
@@ -14,7 +30,9 @@ interface Props<TVal, TKey extends keyof ComponentsAndVariants = 'dropdown'> ext
14
30
  * the listbox before it clears the field.
15
31
  */
16
32
  isSearchable?: boolean;
33
+ /** The placeholder for the `isSearchable` field. Not a name — see `label`. */
17
34
  searchPlaceholder?: string;
35
+ /** Drop the chevron. It is decoration either way: it is `aria-hidden` and never focusable. */
18
36
  hideIcon?: boolean;
19
37
  /** Show checkbox for each item in multiple selection mode */
20
38
  showCheckbox?: boolean;
@@ -30,9 +48,21 @@ interface Props<TVal, TKey extends keyof ComponentsAndVariants = 'dropdown'> ext
30
48
  itemsProps?: BoxStyleProps;
31
49
  /** BoxProps applied to the chevron icon container (dropdown.icon) */
32
50
  iconProps?: BoxStyleProps;
51
+ /**
52
+ * Fires with the selection in whatever shape `value` takes — the whole array in `multiple` mode, the
53
+ * one chosen option otherwise, `undefined` for nothing — and why it changed.
54
+ */
55
+ onValueChange?: ChangeHandler<TVal | TVal[] | undefined, DropdownValueReason>;
56
+ /**
57
+ * The older callback, whose first argument is the option *acted on* rather than the selection. Both
58
+ * fire, so either one can be passed.
59
+ * @deprecated `onValueChange` is what every component reports a value change under, and it carries the
60
+ * reason — which is the thing a `(value, values)` pair cannot say. This spelling still works.
61
+ */
33
62
  onChange?: (value: TVal | undefined, values: TVal[]) => void;
34
63
  }
35
64
  interface DropdownDisplayProps<TVal> extends Omit<BoxProps, 'children'> {
65
+ /** What the trigger shows: a node, or a function given the selected values and whether it is open. */
36
66
  children: ((selectedValues: TVal[], isOpen: boolean) => React.ReactNode) | React.ReactNode;
37
67
  }
38
68
  interface DropdownType {