@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box-kite/react",
3
- "version": "1.0.0",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "pages/**"
@@ -29,6 +29,11 @@
29
29
  "import": "./a11y.mjs",
30
30
  "require": "./a11y.cjs"
31
31
  },
32
+ "./anchor": {
33
+ "types": "./anchor.d.ts",
34
+ "import": "./anchor.mjs",
35
+ "require": "./anchor.cjs"
36
+ },
32
37
  "./ssg": {
33
38
  "types": "./ssg.d.ts",
34
39
  "import": "./ssg.mjs",
@@ -68,8 +73,15 @@
68
73
  "check:docs": "node scripts/check-docs-snippets.mjs",
69
74
  "check:props": "node scripts/check-props-api.mjs",
70
75
  "docs:props": "node scripts/check-props-api.mjs --fix",
76
+ "check:components": "node scripts/check-components-api.mjs",
77
+ "docs:components": "node scripts/check-components-api.mjs --fix",
78
+ "check:conventions": "node scripts/check-component-conventions.mjs",
79
+ "check:agents": "node scripts/check-agent-files.mjs",
80
+ "docs:agents": "node scripts/check-agent-files.mjs --fix",
71
81
  "check:package": "publint dist && attw --pack dist --ignore-rules false-esm cjs-resolves-to-esm internal-resolution-error && publint dist-core && attw --pack dist-core --ignore-rules false-esm cjs-resolves-to-esm internal-resolution-error",
72
- "size": "size-limit"
82
+ "size": "size-limit",
83
+ "size:published": "node dev/published-size.mjs",
84
+ "release": "node scripts/release.mjs"
73
85
  },
74
86
  "size-limit": [
75
87
  {
@@ -80,7 +92,7 @@
80
92
  "react-dom"
81
93
  ],
82
94
  "gzip": true,
83
- "limit": "26.20 KB"
95
+ "limit": "30.40 KB"
84
96
  },
85
97
  {
86
98
  "name": "Box in a Server Component (react-server entry)",
@@ -90,7 +102,7 @@
90
102
  "react-dom"
91
103
  ],
92
104
  "gzip": true,
93
- "limit": "24.70 KB"
105
+ "limit": "28.90 KB"
94
106
  },
95
107
  {
96
108
  "name": "Behavior primitives (a11y entry)",
@@ -100,13 +112,113 @@
100
112
  "react-dom"
101
113
  ],
102
114
  "gzip": true,
103
- "limit": "3.13 KB"
115
+ "limit": "3.2 KB"
116
+ },
117
+ {
118
+ "name": "Anchor positioning (anchor entry)",
119
+ "path": "dist/anchor.mjs",
120
+ "ignore": [
121
+ "react",
122
+ "react-dom"
123
+ ],
124
+ "gzip": true,
125
+ "limit": "2.25 KB"
104
126
  },
105
127
  {
106
128
  "name": "Core engine (@box-kite/core, no React)",
107
129
  "path": "dist-core/core.mjs",
108
130
  "gzip": true,
109
- "limit": "24.10 KB"
131
+ "limit": "28.17 KB"
132
+ },
133
+ {
134
+ "name": "Dialog",
135
+ "path": "dist/components/dialog.mjs",
136
+ "ignore": [
137
+ "react",
138
+ "react-dom"
139
+ ],
140
+ "gzip": true,
141
+ "limit": "32.55 KB"
142
+ },
143
+ {
144
+ "name": "Popover",
145
+ "path": "dist/components/popover.mjs",
146
+ "ignore": [
147
+ "react",
148
+ "react-dom"
149
+ ],
150
+ "gzip": true,
151
+ "limit": "34.02 KB"
152
+ },
153
+ {
154
+ "name": "Menu",
155
+ "path": "dist/components/menu.mjs",
156
+ "ignore": [
157
+ "react",
158
+ "react-dom"
159
+ ],
160
+ "gzip": true,
161
+ "limit": "36.27 KB"
162
+ },
163
+ {
164
+ "name": "Accordion",
165
+ "path": "dist/components/accordion.mjs",
166
+ "ignore": [
167
+ "react",
168
+ "react-dom"
169
+ ],
170
+ "gzip": true,
171
+ "limit": "31.76 KB"
172
+ },
173
+ {
174
+ "name": "Tabs",
175
+ "path": "dist/components/tabs.mjs",
176
+ "ignore": [
177
+ "react",
178
+ "react-dom"
179
+ ],
180
+ "gzip": true,
181
+ "limit": "32.96 KB"
182
+ },
183
+ {
184
+ "name": "Slider",
185
+ "path": "dist/components/slider.mjs",
186
+ "ignore": [
187
+ "react",
188
+ "react-dom"
189
+ ],
190
+ "gzip": true,
191
+ "limit": "32.12 KB"
192
+ },
193
+ {
194
+ "name": "Progress",
195
+ "path": "dist/components/progress.mjs",
196
+ "ignore": [
197
+ "react",
198
+ "react-dom"
199
+ ],
200
+ "gzip": true,
201
+ "limit": "30.28 KB"
202
+ },
203
+ {
204
+ "name": "Toaster",
205
+ "path": "dist/components/toaster.mjs",
206
+ "ignore": [
207
+ "react",
208
+ "react-dom"
209
+ ],
210
+ "gzip": true,
211
+ "limit": "33.77 KB"
212
+ },
213
+ {
214
+ "name": "Combobox",
215
+ "path": "dist/components/combobox.mjs",
216
+ "ignore": [
217
+ "react",
218
+ "react-dom"
219
+ ],
220
+ "gzip": true,
221
+ "limit": "39.54 KB"
110
222
  },
111
223
  {
112
224
  "name": "DataGrid",
@@ -116,7 +228,17 @@
116
228
  "react-dom"
117
229
  ],
118
230
  "gzip": true,
119
- "limit": "54.55 KB"
231
+ "limit": "74.86 KB"
232
+ },
233
+ {
234
+ "name": "DataGrid export, the chunk fetched on the first press",
235
+ "path": "dist/gridExport.mjs",
236
+ "ignore": [
237
+ "react",
238
+ "react-dom"
239
+ ],
240
+ "gzip": true,
241
+ "limit": "3.8 KB"
120
242
  },
121
243
  {
122
244
  "name": "Full library (Box + ssg + every component)",
@@ -126,7 +248,7 @@
126
248
  "react-dom"
127
249
  ],
128
250
  "gzip": true,
129
- "limit": "60.85 KB"
251
+ "limit": "96.82 KB"
130
252
  }
131
253
  ],
132
254
  "repository": {
@@ -154,13 +276,13 @@
154
276
  "url": "https://github.com/box-kite/box-kite/issues"
155
277
  },
156
278
  "homepage": "https://www.box-kite.dev",
157
- "description": "One React component with 212 typed CSS props that generates atomic CSS at runtime — no CSS files, no build step, renders in a Server Component.",
279
+ "description": "One React component with 221 typed CSS props that generates atomic CSS at runtime — no CSS files, no build step, renders in a Server Component.",
158
280
  "peerDependencies": {
159
281
  "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
160
282
  "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
161
283
  },
162
284
  "dependencies": {
163
- "@box-kite/core": "1.0.0",
285
+ "@box-kite/core": "2.0.1",
164
286
  "csstype": "^3.2.3",
165
287
  "use-sync-external-store": "^1.6.0"
166
288
  },
@@ -190,9 +312,11 @@
190
312
  "eslint-plugin-prettier": "^5.5.6",
191
313
  "eslint-plugin-react-hooks": "^7.1.1",
192
314
  "eslint-plugin-react-refresh": "^0.5.3",
315
+ "exceljs": "^4.4.0",
193
316
  "globals": "^17.9.0",
194
317
  "happy-dom": "^20.11.1",
195
318
  "lucide-react": "^1.28.0",
319
+ "marked": "^18.0.11",
196
320
  "prettier": "^3.9.6",
197
321
  "prismjs": "^1.30.0",
198
322
  "publint": "^0.3.24",
package/placement.cjs ADDED
@@ -0,0 +1 @@
1
+ const e=require("./platform.cjs"),t=require("./effects.cjs"),n=require("./identity.cjs");let r=require("react");var i={top:`bottom`,bottom:`top`,start:`end`,end:`start`};function a(e){return e===`top`||e===`bottom`}function o(e,t){let n=a(e),r=n?e===`top`?`block-start`:`block-end`:e===`start`?`inline-start`:`inline-end`,i=t===`center`?`span-all`:`span-${n?`inline`:`block`}-${t===`start`?`end`:`start`}`;return n?`${r} ${i}`:`${i} ${r}`}function s(e){let[t,n]=e.trim().split(` `);return n===void 0?t===`block-start`?`top`:t===`block-end`?`bottom`:t===`inline-start`?`start`:t===`inline-end`?`end`:null:t===`start`?`top`:t===`end`?`bottom`:n===`start`?`start`:n===`end`?`end`:null}function c(e){return a(e)?`flip-block, flip-inline, flip-block flip-inline`:`flip-inline, flip-block, flip-inline flip-block`}function l(e,t,n,r){let i=u(t,r);return i===`top`?e.top-n.top:i===`bottom`?n.top+n.height-(e.top+e.height):i===`left`?e.left-n.left:n.left+n.width-(e.left+e.width)}function u(e,t){return e===`top`||e===`bottom`?e:e===`start`===t?`right`:`left`}function d(e,t,n,r){return Math.max(n,Math.min(e,n+r-t))}function f(e,t,n,r){let{align:o,offset:s,flip:c,rtl:f}=r,p=(a(r.side)?t.height:t.width)+s,m=c&&l(e,r.side,n,f)<p&&l(e,i[r.side],n,f)>=p?i[r.side]:r.side,h=u(m,f),g={top:e.top-t.height-s,bottom:e.top+e.height+s,left:e.left-t.width-s,right:e.left+e.width+s}[h],_=a(m),v=_?e.left:e.top,y=_?e.width:e.height,b=_?t.width:t.height,x=o===`center`?v+y/2-b/2:o===`start`===(_&&f)?v+y-b:v,S=_?d(x,t.width,n.left,n.width):d(x,t.height,n.top,n.height);return _?{top:g,left:S,side:m}:{top:S,left:g,side:m}}var p=4,m=16,h={top:`mb`,bottom:`mt`,start:`me`,end:`ms`};function g(){return typeof CSS<`u`&&typeof CSS.supports==`function`&&CSS.supports(`anchor-name: --a`)}function _(){let e=typeof document>`u`?null:document.documentElement,t=e?parseFloat(getComputedStyle(e).fontSize):NaN;return Number.isFinite(t)&&t>0?t:m}function v(e){let{top:t,left:n,width:r,height:i}=e.getBoundingClientRect();return{top:t,left:n,width:r,height:i}}function y(e,t){return e!==null&&e.top===t.top&&e.left===t.left&&e.side===t.side&&e.anchorWidth===t.anchorWidth}function b(i={}){let{side:a=`bottom`,align:l=`center`,offset:u=0,flip:d=!0,matchWidth:m=!1,name:b,anchor:x,trackSide:S=!1}=i,C=n.t(`anchor`),w=`--${(b??C).replace(/^--/,``)}`,[T,E]=(0,r.useState)(!0),[D,O]=(0,r.useState)(null),[k,A]=(0,r.useState)(null),[j,M]=(0,r.useState)(null),[N,P]=(0,r.useState)(null);t.n(()=>{g()||E(!1)},[]),t.n(()=>{let t=e.c(x);if(t)return t.style.setProperty(`anchor-name`,w),()=>{t.style.removeProperty(`anchor-name`)}},[x,w]),t.n(()=>{!T||!S||!k||P(s(getComputedStyle(k).getPropertyValue(`position-area`)))},[T,S,k,a,l,d]),t.n(()=>{let t=e.c(x)??D;if(T||!t||!k)return;let n=()=>{let n=v(t),r=v(k),i={top:0,left:0,width:window.innerWidth,height:window.innerHeight},o=m?Math.max(r.width,n.width):r.width,s={...f(n,{...r,width:o},i,{side:a,align:l,offset:u/p*_(),flip:d,rtl:e.u(t)}),anchorWidth:n.width};M(e=>y(e,s)?e:s)};n();let r=new AbortController;return document.addEventListener(`scroll`,n,{signal:r.signal,capture:!0,passive:!0}),window.addEventListener(`resize`,n,{signal:r.signal,passive:!0}),()=>r.abort()},[T,x,D,k,a,l,u,d,m]);let F=(0,r.useCallback)(e=>O(e),[]),I=(0,r.useCallback)(e=>A(e),[]),L={ref:T?void 0:F,style:{anchorName:w}};return T?{css:T,side:N??a,anchorProps:L,layerProps:{...S?{ref:I}:{},position:`fixed`,positionArea:o(a,l),...d?{positionTryFallbacks:c(a)}:{},...m?{minWidth:`anchor-size(width)`}:{},...u?{[h[a]]:u}:{},style:{positionAnchor:w}}}:{css:T,side:j?.side??a,anchorProps:L,layerProps:{ref:I,position:`fixed`,style:j?{top:`${j.top}px`,left:`${j.left}px`,...m?{minWidth:`${j.anchorWidth}px`}:{}}:{top:0,left:0,visibility:`hidden`}}}}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return b}});
package/placement.mjs ADDED
@@ -0,0 +1,180 @@
1
+ import { c as e, u as t } from "./platform.mjs";
2
+ import { n } from "./effects.mjs";
3
+ import { t as r } from "./identity.mjs";
4
+ import { useCallback as i, useState as a } from "react";
5
+ //#region src/utils/anchor/anchorUtils.ts
6
+ var o = {
7
+ top: "bottom",
8
+ bottom: "top",
9
+ start: "end",
10
+ end: "start"
11
+ };
12
+ function s(e) {
13
+ return e === "top" || e === "bottom";
14
+ }
15
+ function c(e, t) {
16
+ let n = s(e), r = n ? e === "top" ? "block-start" : "block-end" : e === "start" ? "inline-start" : "inline-end", i = t === "center" ? "span-all" : `span-${n ? "inline" : "block"}-${t === "start" ? "end" : "start"}`;
17
+ return n ? `${r} ${i}` : `${i} ${r}`;
18
+ }
19
+ function l(e) {
20
+ let [t, n] = e.trim().split(" ");
21
+ return n === void 0 ? t === "block-start" ? "top" : t === "block-end" ? "bottom" : t === "inline-start" ? "start" : t === "inline-end" ? "end" : null : t === "start" ? "top" : t === "end" ? "bottom" : n === "start" ? "start" : n === "end" ? "end" : null;
22
+ }
23
+ function u(e) {
24
+ return s(e) ? "flip-block, flip-inline, flip-block flip-inline" : "flip-inline, flip-block, flip-inline flip-block";
25
+ }
26
+ function d(e, t, n, r) {
27
+ let i = f(t, r);
28
+ return i === "top" ? e.top - n.top : i === "bottom" ? n.top + n.height - (e.top + e.height) : i === "left" ? e.left - n.left : n.left + n.width - (e.left + e.width);
29
+ }
30
+ function f(e, t) {
31
+ return e === "top" || e === "bottom" ? e : e === "start" === t ? "right" : "left";
32
+ }
33
+ function p(e, t, n, r) {
34
+ return Math.max(n, Math.min(e, n + r - t));
35
+ }
36
+ function m(e, t, n, r) {
37
+ let { align: i, offset: a, flip: c, rtl: l } = r, u = (s(r.side) ? t.height : t.width) + a, m = c && d(e, r.side, n, l) < u && d(e, o[r.side], n, l) >= u ? o[r.side] : r.side, h = f(m, l), g = {
38
+ top: e.top - t.height - a,
39
+ bottom: e.top + e.height + a,
40
+ left: e.left - t.width - a,
41
+ right: e.left + e.width + a
42
+ }[h], _ = s(m), v = _ ? e.left : e.top, y = _ ? e.width : e.height, b = _ ? t.width : t.height, x = i === "center" ? v + y / 2 - b / 2 : i === "start" === (_ && l) ? v + y - b : v, S = _ ? p(x, t.width, n.left, n.width) : p(x, t.height, n.top, n.height);
43
+ return _ ? {
44
+ top: g,
45
+ left: S,
46
+ side: m
47
+ } : {
48
+ top: S,
49
+ left: g,
50
+ side: m
51
+ };
52
+ }
53
+ //#endregion
54
+ //#region src/react/anchor/useAnchorPosition.ts
55
+ var h = 4, g = 16, _ = {
56
+ top: "mb",
57
+ bottom: "mt",
58
+ start: "me",
59
+ end: "ms"
60
+ };
61
+ function v() {
62
+ return typeof CSS < "u" && typeof CSS.supports == "function" && CSS.supports("anchor-name: --a");
63
+ }
64
+ function y() {
65
+ let e = typeof document > "u" ? null : document.documentElement, t = e ? parseFloat(getComputedStyle(e).fontSize) : NaN;
66
+ return Number.isFinite(t) && t > 0 ? t : g;
67
+ }
68
+ function b(e) {
69
+ let { top: t, left: n, width: r, height: i } = e.getBoundingClientRect();
70
+ return {
71
+ top: t,
72
+ left: n,
73
+ width: r,
74
+ height: i
75
+ };
76
+ }
77
+ function x(e, t) {
78
+ return e !== null && e.top === t.top && e.left === t.left && e.side === t.side && e.anchorWidth === t.anchorWidth;
79
+ }
80
+ function S(o = {}) {
81
+ let { side: s = "bottom", align: d = "center", offset: f = 0, flip: p = !0, matchWidth: g = !1, name: S, anchor: C, trackSide: w = !1 } = o, T = r("anchor"), E = `--${(S ?? T).replace(/^--/, "")}`, [D, O] = a(!0), [k, A] = a(null), [j, M] = a(null), [N, P] = a(null), [F, I] = a(null);
82
+ n(() => {
83
+ v() || O(!1);
84
+ }, []), n(() => {
85
+ let t = e(C);
86
+ if (t) return t.style.setProperty("anchor-name", E), () => {
87
+ t.style.removeProperty("anchor-name");
88
+ };
89
+ }, [C, E]), n(() => {
90
+ !D || !w || !j || I(l(getComputedStyle(j).getPropertyValue("position-area")));
91
+ }, [
92
+ D,
93
+ w,
94
+ j,
95
+ s,
96
+ d,
97
+ p
98
+ ]), n(() => {
99
+ let n = e(C) ?? k;
100
+ if (D || !n || !j) return;
101
+ let r = () => {
102
+ let e = b(n), r = b(j), i = {
103
+ top: 0,
104
+ left: 0,
105
+ width: window.innerWidth,
106
+ height: window.innerHeight
107
+ }, a = g ? Math.max(r.width, e.width) : r.width, o = {
108
+ ...m(e, {
109
+ ...r,
110
+ width: a
111
+ }, i, {
112
+ side: s,
113
+ align: d,
114
+ offset: f / h * y(),
115
+ flip: p,
116
+ rtl: t(n)
117
+ }),
118
+ anchorWidth: e.width
119
+ };
120
+ P((e) => x(e, o) ? e : o);
121
+ };
122
+ r();
123
+ let i = new AbortController();
124
+ return document.addEventListener("scroll", r, {
125
+ signal: i.signal,
126
+ capture: !0,
127
+ passive: !0
128
+ }), window.addEventListener("resize", r, {
129
+ signal: i.signal,
130
+ passive: !0
131
+ }), () => i.abort();
132
+ }, [
133
+ D,
134
+ C,
135
+ k,
136
+ j,
137
+ s,
138
+ d,
139
+ f,
140
+ p,
141
+ g
142
+ ]);
143
+ let L = i((e) => A(e), []), R = i((e) => M(e), []), z = {
144
+ ref: D ? void 0 : L,
145
+ style: { anchorName: E }
146
+ };
147
+ return D ? {
148
+ css: D,
149
+ side: F ?? s,
150
+ anchorProps: z,
151
+ layerProps: {
152
+ ...w ? { ref: R } : {},
153
+ position: "fixed",
154
+ positionArea: c(s, d),
155
+ ...p ? { positionTryFallbacks: u(s) } : {},
156
+ ...g ? { minWidth: "anchor-size(width)" } : {},
157
+ ...f ? { [_[s]]: f } : {},
158
+ style: { positionAnchor: E }
159
+ }
160
+ } : {
161
+ css: D,
162
+ side: N?.side ?? s,
163
+ anchorProps: z,
164
+ layerProps: {
165
+ ref: R,
166
+ position: "fixed",
167
+ style: N ? {
168
+ top: `${N.top}px`,
169
+ left: `${N.left}px`,
170
+ ...g ? { minWidth: `${N.anchorWidth}px` } : {}
171
+ } : {
172
+ top: 0,
173
+ left: 0,
174
+ visibility: "hidden"
175
+ }
176
+ }
177
+ };
178
+ }
179
+ //#endregion
180
+ export { S as t };
package/platform.cjs CHANGED
@@ -1 +1 @@
1
- function e(e){return e?`current`in e?e.current:e:null}function t(t){let n=e(t);return n instanceof HTMLElement?n:null}function n(t,n){let r=typeof t.composedPath==`function`?t.composedPath():[];return n.some(n=>{let i=e(n);return i?r.includes(i)||t.target instanceof Node&&i.contains(t.target):!1})}function r(t){let n=e(t),r=n?.ownerDocument?.defaultView;return!!n&&!!r&&r.getComputedStyle(n).direction===`rtl`}function i(){return typeof window<`u`&&window.document!==void 0}function a(){return typeof document<`u`}function o(){return a()?document:null}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return o}});
1
+ function e(e){return e?`current`in e?e.current:e:null}function t(t){let n=e(t);return n instanceof HTMLElement?n:null}function n(t,n){let r=typeof t.composedPath==`function`?t.composedPath():[];return n.some(n=>{let i=e(n);return i?r.includes(i)||t.target instanceof Node&&i.contains(t.target):!1})}function r(t){let n=e(t),r=n?.ownerDocument?.defaultView;return!!n&&!!r&&r.getComputedStyle(n).direction===`rtl`}function i(t){let n=e(t)?.ownerDocument?.defaultView?.getSelection();n&&!n.isCollapsed&&n.removeAllRanges()}function a(){return typeof window<`u`&&window.document!==void 0}function o(){return typeof document<`u`}function s(){return o()?document:null}function c(){return s()?.documentElement??null}function l(){return typeof HTMLElement<`u`&&typeof HTMLElement.prototype.showPopover==`function`}function u(){return typeof HTMLDialogElement<`u`&&`closedBy`in HTMLDialogElement.prototype}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return r}});
package/platform.mjs CHANGED
@@ -17,16 +17,29 @@ function r(t) {
17
17
  let n = e(t), r = n?.ownerDocument?.defaultView;
18
18
  return !!n && !!r && r.getComputedStyle(n).direction === "rtl";
19
19
  }
20
+ function i(t) {
21
+ let n = e(t)?.ownerDocument?.defaultView?.getSelection();
22
+ n && !n.isCollapsed && n.removeAllRanges();
23
+ }
20
24
  //#endregion
21
25
  //#region src/utils/environment/environmentUtils.ts
22
- function i() {
26
+ function a() {
23
27
  return typeof window < "u" && window.document !== void 0;
24
28
  }
25
- function a() {
29
+ function o() {
26
30
  return typeof document < "u";
27
31
  }
28
- function o() {
29
- return a() ? document : null;
32
+ function s() {
33
+ return o() ? document : null;
34
+ }
35
+ function c() {
36
+ return s()?.documentElement ?? null;
37
+ }
38
+ function l() {
39
+ return typeof HTMLElement < "u" && typeof HTMLElement.prototype.showPopover == "function";
40
+ }
41
+ function u() {
42
+ return typeof HTMLDialogElement < "u" && "closedBy" in HTMLDialogElement.prototype;
30
43
  }
31
44
  //#endregion
32
- export { n as a, t as i, i as n, r as o, e as r, o as t };
45
+ export { l as a, t as c, u as i, n as l, c as n, i as o, a as r, e as s, s as t, r as u };
@@ -0,0 +1,79 @@
1
+ import { CSSProperties } from 'react';
2
+ import { BoxStyleProps } from '@box-kite/core/types';
3
+ import { AnchorAlign, AnchorSide } from '../../utils/anchor/anchorUtils';
4
+ import { ElementLike } from '../../utils/dom/domUtils';
5
+ export interface AnchorPositionOptions {
6
+ /** Which side of the anchor to sit on. `top`/`bottom` are the block axis, `start`/`end` the inline one. Default `'bottom'`. */
7
+ side?: AnchorSide;
8
+ /** Which of the anchor's edges to line up with along the other axis. Default `'center'`. */
9
+ align?: AnchorAlign;
10
+ /** The gap between anchor and layer, on the ÷4 spacing scale — `offset: 2` is 8px. Default `0`. */
11
+ offset?: number;
12
+ /**
13
+ * Whether the browser may move the layer where it does not fit: the side swapped for its opposite, the
14
+ * alignment mirrored, or both — three candidates, since a candidate has to fit on both axes. Default `true`.
15
+ */
16
+ flip?: boolean;
17
+ /** Whether the layer is at least as wide as its anchor, the way a select popup is. Default `false`. */
18
+ matchWidth?: boolean;
19
+ /** The anchor's name. Generated per instance when omitted, which is what keeps two layers apart. */
20
+ name?: string;
21
+ /**
22
+ * The anchor as an element rather than props to spread — for a caller handed a trigger it does not
23
+ * render itself. The name is written onto it in a layout effect, so a ref is read when the layer mounts.
24
+ */
25
+ anchor?: ElementLike;
26
+ /**
27
+ * Whether `side` reports where the layer ended up rather than where it was asked to go. Off by default,
28
+ * because on the CSS path it costs the one thing that path otherwise never does: a read after layout.
29
+ */
30
+ trackSide?: boolean;
31
+ }
32
+ /** The two anchor-positioning properties, which csstype does not know yet. An inline style, deliberately — see the hook. */
33
+ type AnchorStyle = CSSProperties & {
34
+ anchorName?: string;
35
+ positionAnchor?: string;
36
+ };
37
+ /** What goes on the anchor: its name, and — where the browser cannot place the layer — a ref to measure it by. */
38
+ export interface AnchorElementProps {
39
+ ref?: (element: HTMLElement | null) => void;
40
+ style: AnchorStyle;
41
+ }
42
+ /** What goes on the floating layer. The geometry is shared props; only the identity and the fallback's coordinates are inline. */
43
+ export interface AnchorLayerProps extends Pick<BoxStyleProps, 'position' | 'positionArea' | 'positionTryFallbacks' | 'minWidth' | 'mt' | 'mb' | 'ms' | 'me'> {
44
+ ref?: (element: HTMLElement | null) => void;
45
+ style: AnchorStyle;
46
+ }
47
+ export interface AnchorPosition {
48
+ /** Whether the browser is placing the layer. `false` means this hook measured it instead. */
49
+ css: boolean;
50
+ /** The side the layer is on: the requested one, unless `trackSide` is on and a flip moved it. */
51
+ side: AnchorSide;
52
+ anchorProps: AnchorElementProps;
53
+ layerProps: AnchorLayerProps;
54
+ }
55
+ /**
56
+ * A floating layer placed against an anchor — in CSS where the browser has anchor positioning, and by
57
+ * measurement where it does not. Spread `anchorProps` on the trigger and `layerProps` on the layer;
58
+ * nothing else is needed, and on the CSS path nothing runs at all: no scroll listener, no state, no
59
+ * measurement, because `position-area` and `position-try-fallbacks` are the flip a positioning library
60
+ * ships JS for.
61
+ *
62
+ * ```tsx
63
+ * const { anchorProps, layerProps } = useAnchorPosition({ side: 'bottom', offset: 2, matchWidth: true });
64
+ *
65
+ * <Button {...anchorProps} onClick={toggle}>Options</Button>
66
+ * {open && <Box {...layerProps} component="menu">…</Box>}
67
+ * ```
68
+ *
69
+ * Two things worth knowing. The layer is `position: fixed`, so it escapes every `overflow: hidden`
70
+ * ancestor without a portal — but not a *transformed* one, which is a fixed element's containing block in
71
+ * either path, and not the stacking order, which is still the page's. And the anchor's **name is an inline
72
+ * style rather than a prop**: an identity is per-instance, so a class for it would be a rule per instance
73
+ * that is never freed — the same rule that makes a sparkline's `d` an attribute and its stroke a class.
74
+ *
75
+ * @a11y None of it. A layer is not a pattern: the role, the dismissal and the focus belong to whatever
76
+ * renders one — `useDismiss` and `useFocusReturn` from `@box-kite/react/a11y` are the other half.
77
+ */
78
+ export default function useAnchorPosition(options?: AnchorPositionOptions): AnchorPosition;
79
+ export {};
@@ -0,0 +1,12 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Stop the page behind a layer from scrolling, with a class rather than an inline style — so it is one
4
+ * shared rule like every other value this library writes, and a consumer can see what did it. Returns
5
+ * the style elements to render, which is element mode's way of getting a rule onto the page at all.
6
+ *
7
+ * `overflow: hidden` on `<html>` is the whole mechanism, which means two things worth knowing: the
8
+ * scrollbar's width leaves the page as it is applied, so a document that wants no shift should carry
9
+ * `scrollbarGutter="stable"`; and iOS Safari scrolls anyway, where nothing short of `position: fixed`
10
+ * on the body holds it.
11
+ */
12
+ export default function useScrollLock(enabled: boolean): React.ReactElement[] | undefined;
@@ -1 +1,6 @@
1
- export default function usePortalContainer(): HTMLElement | null;
1
+ /**
2
+ * The container every portalled layer shares, created on first use. Pass `false` on the top-layer path,
3
+ * where nothing is portalled: the container is a DOM node plus a theme-class subscription, and a layer
4
+ * that stays where it was declared inherits the theme instead of needing one copied onto it.
5
+ */
6
+ export default function usePortalContainer(enabled?: boolean): HTMLElement | null;
@@ -1,43 +1,32 @@
1
+ import { VirtualWindow } from '../../utils/virtual/virtualUtils';
1
2
  export interface UseVirtualizationOptions {
2
- /** Total number of items */
3
- itemCount: number;
4
- /** Height of each item in pixels */
5
- itemHeight: number;
6
- /** Height of the visible container in pixels */
7
- containerHeight: number;
8
- /** Number of items to render outside visible area (default: 3) */
3
+ /** How many rows there are in total — not how many are rendered. */
4
+ count: number;
5
+ /** The scrolling element: what it shows at once is the viewport, and its own rows are the pitch. */
6
+ scrollerRef: React.RefObject<HTMLElement | null>;
7
+ /** The pitch of a row, when it should be declared rather than measured. */
8
+ itemHeight?: number;
9
+ /** What the scroller shows, when it should be declared rather than measured. */
10
+ viewHeight?: number;
9
11
  overscan?: number;
10
- /** Whether virtualization is enabled (default: true when itemCount > threshold) */
11
- enabled?: boolean;
12
- /** Threshold for enabling virtualization (default: 50) */
13
12
  threshold?: number;
13
+ /** Forces windowing on or off. Left off, it follows the row count against `threshold`. */
14
+ enabled?: boolean;
15
+ /** The row the keyboard is on. Always rendered, whatever the scroll position says. */
16
+ activeIndex?: number;
14
17
  }
15
- export interface UseVirtualizationResult {
16
- /** First item index to render */
17
- startIndex: number;
18
- /** Last item index to render (inclusive) */
19
- endIndex: number;
20
- /** Total height of all items (for scroll container) */
21
- totalHeight: number;
22
- /** Y offset for positioning visible items */
23
- offsetY: number;
24
- /** Number of visible items */
25
- visibleCount: number;
26
- /** Whether virtualization is active */
27
- isVirtualized: boolean;
28
- /** Scroll event handler - attach to container's onScroll */
29
- handleScroll: (e: React.UIEvent<HTMLElement>) => void;
30
- /** Current scroll position */
31
- scrollTop: number;
32
- /** Container style for the scroll area */
33
- containerStyle: React.CSSProperties;
34
- /** Inner wrapper style (total height) */
35
- innerStyle: React.CSSProperties;
36
- /** Content style (transform offset) */
37
- contentStyle: React.CSSProperties;
18
+ export interface UseVirtualizationResult extends VirtualWindow {
19
+ /** Whether the list is being windowed at all. `false` means render every row and ignore the rest. */
20
+ virtualized: boolean;
21
+ /** Goes on the element that holds the rendered rows — the one the pitch is measured from. */
22
+ contentRef: (element: HTMLElement | null) => void;
23
+ /** Goes on the scrolling element. */
24
+ onScroll: (event: React.UIEvent<HTMLElement>) => void;
38
25
  }
39
26
  /**
40
- * Hook for virtualizing large lists.
41
- * Only renders items that are visible in the viewport plus overscan buffer.
27
+ * Renders a window of a long list instead of all of it, over the framework-free arithmetic in
28
+ * `VirtualUtils`. The two measurements it needs are taken from the DOM rather than declared, so a row
29
+ * restyled by the caller still windows correctly; until something has been laid out (a first render, or
30
+ * a test environment that computes none) the defaults in the model stand in.
42
31
  */
43
32
  export default function useVirtualization(options: UseVirtualizationOptions): UseVirtualizationResult;