@box-kite/react 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.claude/rules/box-kite-rules.md +58 -94
  2. package/.claude/skills/box-kite/SKILL.md +69 -104
  3. package/.claude/skills/box-kite/references/components.md +1 -1
  4. package/.claude/skills/box-kite/references/patterns.md +1 -1
  5. package/.claude/skills/box-kite/references/rules.md +115 -0
  6. package/.cursor/rules/box-kite.mdc +60 -96
  7. package/AGENTS.md +61 -97
  8. package/BOX_AI_CONTEXT.md +39 -38
  9. package/BOX_KITE_AI_CONTEXT.md +39 -38
  10. package/README.md +200 -721
  11. package/client.cjs +1 -1
  12. package/client.mjs +81 -81
  13. package/components/combobox/comboboxListbox.d.ts +2 -1
  14. package/components/combobox.cjs +1 -1
  15. package/components/combobox.d.ts +1 -1
  16. package/components/combobox.mjs +199 -188
  17. package/components/dataGrid/contracts/dataGridContract.d.ts +2 -1
  18. package/components/dataGrid/useListLayout.d.ts +1 -1
  19. package/components/dataGrid.cjs +3 -3
  20. package/components/dataGrid.mjs +453 -453
  21. package/components/radioGroup.cjs +1 -1
  22. package/components/radioGroup.mjs +1 -0
  23. package/components/semantics.d.ts +29 -29
  24. package/components/skeleton.cjs +1 -1
  25. package/components/skeleton.d.ts +1 -1
  26. package/components/skeleton.mjs +2 -1
  27. package/components/textarea.d.ts +1 -1
  28. package/components/textbox.d.ts +1 -1
  29. package/components/timeZoneSelect.d.ts +1 -1
  30. package/components/toaster.cjs +1 -1
  31. package/components/toaster.mjs +13 -14
  32. package/docs/a11y.md +1 -2
  33. package/docs/index.md +1 -1
  34. package/effects.cjs +1 -1
  35. package/effects.mjs +2 -2
  36. package/identity.cjs +1 -1
  37. package/identity.mjs +5 -7
  38. package/package.json +9 -9
  39. package/react/effects.d.ts +5 -6
  40. package/react/identity/useIdentifier.d.ts +0 -3
@@ -1 +1 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../rolldown-runtime.cjs"),t=require("./visuallyHidden.cjs");let n=require("react/jsx-runtime"),r=require("@box-kite/react");r=e.t(r,1);function i(e){let{lines:i=1,circle:a=!1,label:o,props:s,...c}=e,l=a?1:Math.max(1,Math.trunc(i));return(0,n.jsxs)(r.default,{component:`skeleton`,...c,props:{...o===void 0?{"aria-hidden":!0}:{role:`status`},...s},children:[Array.from({length:l},(e,t)=>(0,n.jsx)(r.default,{component:`skeleton.bar`,variant:{circle:a,short:!a&&l>1&&t===l-1},children:(0,n.jsx)(r.default,{component:`skeleton.gloss`})},t)),o!==void 0&&(0,n.jsx)(t.default,{children:o})]})}exports.default=i;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../rolldown-runtime.cjs"),t=require("./visuallyHidden.cjs");let n=require("react/jsx-runtime"),r=require("@box-kite/react");r=e.t(r,1);function i(e){let{lines:i=1,circle:a=!1,label:o,props:s,...c}=e,l=a?1:Math.max(1,Math.trunc(i));return(0,n.jsxs)(r.default,{component:`skeleton`,...c,props:{...o===void 0?{"aria-hidden":!0}:{role:`status`},...s},children:[Array.from({length:l},(e,t)=>(0,n.jsx)(r.default,{component:`skeleton.bar`,variant:{circle:a,short:!a&&l>1&&t===l-1,fill:!a&&l===1},children:(0,n.jsx)(r.default,{component:`skeleton.gloss`})},t)),o!==void 0&&(0,n.jsx)(t.default,{children:o})]})}exports.default=i;
@@ -2,7 +2,7 @@ import { ReactNode } from 'react';
2
2
  import { BoxProps } from '../box';
3
3
  import { ComponentsAndVariants } from '@box-kite/core/types';
4
4
  export interface SkeletonProps<TKey extends keyof ComponentsAndVariants = 'skeleton'> extends BoxProps<'div', TKey> {
5
- /** How many bars to draw. Default `1`; past that the last one is short, the way a paragraph's last line is. */
5
+ /** How many bars to draw. Default `1`, which fills the skeleton: `height={40}` is a block. Past that the last bar is short, the way a paragraph's last line is. */
6
6
  lines?: number;
7
7
  /** A round placeholder — an avatar, a thumbnail. `width` sets its size and the height follows. */
8
8
  circle?: boolean;
@@ -15,7 +15,8 @@ function i(i) {
15
15
  component: "skeleton.bar",
16
16
  variant: {
17
17
  circle: o,
18
- short: !o && u > 1 && n === u - 1
18
+ short: !o && u > 1 && n === u - 1,
19
+ fill: !o && u === 1
19
20
  },
20
21
  children: /* @__PURE__ */ t(r, { component: "skeleton.gloss" })
21
22
  }, n)), s !== void 0 && /* @__PURE__ */ t(e, { children: s })]
@@ -10,7 +10,7 @@ type TextareaTagProps = OmitTagProps<BoxTagProps<'textarea'>, TagPropsType | 'ty
10
10
  interface Props<TKey extends keyof ComponentsAndVariants> extends TextareaProps<TKey> {
11
11
  /** What the field submits under, and what a `<label htmlFor>` of your own would point at. */
12
12
  name?: string;
13
- /** Attributes for the `<textarea>` itself — an `id`, an `aria-label`, `autoComplete`, `wrap`. */
13
+ /** Attributes for the `<textarea>` itself — an `aria-label`, `autoComplete`, `wrap`. Its `id` is the top-level prop. */
14
14
  props?: TextareaTagProps;
15
15
  /** Fires on every keystroke. `onChange` is React's alias for the same event. */
16
16
  onInput?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
@@ -11,7 +11,7 @@ type TextboxType = 'date' | 'datetime-local' | 'email' | 'hidden' | 'month' | 'n
11
11
  interface Props<TKey extends keyof ComponentsAndVariants> extends TextareaProps<TKey> {
12
12
  /** What the field submits under, and what a `<label htmlFor>` of your own would point at. */
13
13
  name?: string;
14
- /** Attributes for the `<input>` itself — an `id`, an `aria-label`, `inputMode`, `autoComplete`. */
14
+ /** Attributes for the `<input>` itself — an `aria-label`, `inputMode`, `autoComplete`. Its `id` is the top-level prop. */
15
15
  props?: TextboxTagProps;
16
16
  /** Fires on every keystroke. `onChange` is React's alias for the same event. */
17
17
  onInput?: (e: React.ChangeEvent<HTMLInputElement>) => void;
@@ -21,7 +21,7 @@ export interface TimeZoneSelectProps extends TimeZoneSelectBoxProps {
21
21
  name?: string;
22
22
  /** Not editable and not openable, but still read out. */
23
23
  disabled?: boolean;
24
- /** Attributes for the `<input>` itself — an `aria-label`, an `id`. */
24
+ /** Attributes for the `<input>` itself — an `aria-label`, or the `id` a `<label htmlFor>` of your own points at. */
25
25
  props?: Record<string, unknown>;
26
26
  /** What the list says when nothing matches. Default `'No time zone matches'`. */
27
27
  emptyText?: React.ReactNode;
@@ -1 +1 @@
1
- "use client";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../react-shared.cjs"),t=require("../platform.cjs"),n=require("../client.cjs"),r=require("../effects.cjs"),i=require("../interactions.cjs"),a=require("../box.cjs"),o=require("../reporting.cjs"),s=require("../layer.cjs"),c=require("../motion.cjs");let l=require("react"),u=require("react/jsx-runtime"),d=require("react-dom"),f=require("use-sync-external-store/shim");var p=[`value`],m={toasts:[],overflow:0},h=0;function g(){return h+=1,`toast-${h}`}function _(e){let t=[],n=m,r=e?.limit??3,a=e?.duration??5e3,o=!1,s=new Set,c=new Map,l=e=>{let t=c.get(e);t?.handle&&clearTimeout(t.handle),c.delete(e)},u=()=>{t=t.filter(e=>e.open||e.visible);let e=t.filter(e=>!e.open).length,i=0;t=t.map(t=>{if(!t.open)return t;let n=e<r;return n?e++:i++,t.visible===n?t:{...t,visible:n}}),n={toasts:t,overflow:i},d(),s.forEach(e=>e())};function d(){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=c.get(n.id)??{handle:null,remaining:n.duration,startedAt:0};c.set(n.id,t),!(o||t.handle)&&(t.startedAt=Date.now(),t.handle=setTimeout(()=>{c.delete(n.id),h(n.id,`timeout`)},t.remaining))}for(let t of[...c.keys()])e.has(t)||l(t)}let f=(e,t)=>t??(e===`loading`?1/0:a);function h(e,n=`imperative`){let r=[];t=t.map(t=>!t.open||e!==void 0&&t.id!==e?t:(r.push(t),l(t.id),{...t,open:!1})),r.length&&(u(),r.forEach(e=>{e.onDismiss?.(n),i.t({component:`toaster`,type:`dismiss`,reason:n,value:e.message,details:{id:e.id,kind:e.kind},content:p})}))}function _(e,n,r){let a=!1;t=t.map(t=>{if(t.id!==e)return t;a=!0,l(e);let i=r?.kind??t.kind;return{...t,...r,id:e,message:n,kind:i,duration:r?.duration??(r?.kind?f(i):t.duration),open:!0}}),a&&(u(),i.t({component:`toaster`,type:`update`,reason:r?.kind,value:n,details:{id:e},source:`app`,content:p}))}function v(e,n){let r=n?.id??g();if(n?.id&&t.some(e=>e.id===r))return _(r,e,n),r;let a=n?.kind??`default`;return t=[...t,{id:r,kind:a,message:e,description:n?.description,duration:f(a,n?.duration),action:n?.action,dismissible:n?.dismissible??!0,onDismiss:n?.onDismiss,open:!0,visible:!1}],u(),i.t({component:`toaster`,type:`show`,reason:a,value:e,details:{id:r,kind:a},source:`app`,content:p}),r}return{subscribe(e){return s.add(e),()=>s.delete(e)},getSnapshot:()=>n,getServerSnapshot:()=>m,add:v,update:_,dismiss:h,remove(e){let n=t.filter(t=>t.id!==e);n.length!==t.length&&(l(e),t=n,u())},setLimit(e){e!==r&&(r=e,u())},setDefaultDuration(e){a=e},pause(){if(!o){o=!0;for(let e of c.values())e.handle&&(clearTimeout(e.handle),e.handle=null,e.remaining=Math.max(0,e.remaining-(Date.now()-e.startedAt)))}},resume(){o&&(o=!1,d())},reset(){for(let e of[...c.keys()])l(e);t=[],n=m,s.forEach(e=>e())}}}var v=_(),y=e=>(t,n)=>v.add(t,{...n,kind:e}),b=Object.assign((e,t)=>v.add(e,t),{success:y(`success`),error:y(`error`),warning:y(`warning`),info:y(`info`),loading:y(`loading`),update:(e,t,n)=>v.update(e,t,n),dismiss:e=>v.dismiss(e,`imperative`),promise(e,t,n){let r=v.add(t.loading,{...n,id:n?.id,kind:`loading`}),i=(e,t)=>typeof e==`function`?e(t):e;return e.then(e=>v.update(r,i(t.success,e),{kind:`success`}),e=>v.update(r,i(t.error,e),{kind:`error`})),e}}),x={"top-start":`topStart`,"top-center":`topCenter`,"top-end":`topEnd`,"bottom-start":`bottomStart`,"bottom-center":`bottomCenter`,"bottom-end":`bottomEnd`};function S(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 C(e){let{toast:t,store:n,fromTop:i,closeLabel:s}=e,{mounted:l,ref:d,props:f}=c.r({present:t.open}),p=o.i(`toaster`);if(r.n(()=>{l||n.remove(t.id)},[l,n,t.id]),!l)return null;let m=t.action,h=()=>{m?.onClick(),m?.closeOnClick===!1?p(`action`,t.message,{reason:`action`,id:t.id,kind:t.kind,content:[`value`]}):n.dismiss(t.id,`action`)};return(0,u.jsxs)(a.default,{ref:d,component:`toaster.toast`,variant:{[t.kind]:t.kind!=="default",fromTop:i},props:{...t.kind===`error`?{role:`alert`}:{},"data-toast-id":t.id,...f},children:[(0,u.jsx)(a.default,{component:`toaster.message`,children:t.message}),t.description!==void 0&&(0,u.jsx)(a.default,{component:`toaster.description`,children:t.description}),m&&(0,u.jsx)(a.default,{tag:`button`,component:`toaster.action`,props:{type:`button`,onClick:h},children:m.label}),t.dismissible&&(0,u.jsx)(a.default,{tag:`button`,component:`toaster.close`,props:{type:`button`,"aria-label":s,onClick:()=>n.dismiss(t.id,`close`)}})]})}function w(e,i){let{position:o=`bottom-end`,limit:c=3,duration:p=5e3,label:m=`Notifications`,closeLabel:h=`Close`,overflowLabel:g=e=>`+${e} more`,hotkey:_=`F6`,store:y=v,props:b,...w}=e,T=(0,f.useSyncExternalStore)(y.subscribe,y.getSnapshot,y.getServerSnapshot),E=s.n(),D=n.t(!E),O=(0,l.useRef)(null),k=(0,l.useCallback)(e=>{O.current=e,t.d(i,e)},[i]),A=(0,l.useRef)(null),[j,M]=(0,l.useState)(null),N=(0,l.useRef)({hovered:!1,focused:!1,hidden:!1}),P=(0,l.useCallback)(()=>{let{hovered:e,focused:t,hidden:n}=N.current;e||t||n?y.pause():y.resume()},[y]);r.n(()=>y.setLimit(c),[y,c]),r.n(()=>y.setDefaultDuration(p),[y,p]),r.n(()=>{let e=O.current;e&&(N.current.hovered=e.matches(`:hover`),N.current.focused=e.contains(e.ownerDocument.activeElement),P())},[T,j,P]),r.n(()=>{let e=O.current;!E||!t.c()||!e||!e.isConnected||e.matches(`:popover-open`)||e.showPopover()}),r.n(()=>{let e=t.t();if(!e)return;let n=[],r=new AbortController;return e.addEventListener(t.l,e=>{let{dialog:t,open:r}=e.detail,i=n.indexOf(t);i>=0&&n.splice(i,1),r&&n.push(t),M(n[n.length-1]??null)},{signal:r.signal}),()=>r.abort()},[]),r.n(()=>{let e=t.t();if(!e)return;let n=new AbortController;return e.addEventListener(`visibilitychange`,()=>{N.current.hidden=e.hidden,P()},{signal:n.signal}),()=>n.abort()},[P]),r.n(()=>{let e=t.t();if(!_||!e)return;let n=new AbortController;return e.addEventListener(`keydown`,t=>{!S(t,_)||!O.current||(t.preventDefault(),A.current=e.activeElement,O.current.focus())},{signal:n.signal}),()=>n.abort()},[_]);let F=e=>!!e&&!!O.current?.contains(e),I=()=>{N.current.hovered=!0,P()},L=e=>{F(e.relatedTarget)||(N.current.hovered=!1,P())},R=e=>{N.current.focused=!0,P(),F(e.relatedTarget)||(A.current=e.relatedTarget)},z=e=>{F(e.relatedTarget)||(N.current.focused=!1,P())},B=e=>{if(e.key!==`Escape`)return;j&&e.preventDefault();let t=(e.target.closest?.(`[data-toast-id]`))?.getAttribute(`data-toast-id`);t&&y.dismiss(t,`close`),y.getSnapshot().toasts.some(e=>e.open)?O.current?.focus():A.current?.focus()},V=o.startsWith(`top`),H=T.toasts.filter(e=>e.visible),U=V?[...H].reverse():H,W=T.overflow>0&&(0,u.jsx)(a.default,{component:`toaster.overflow`,children:g(T.overflow)}),G=(0,u.jsxs)(a.default,{tag:`section`,ref:k,component:`toaster`,...w,variant:[w.variant,{[x[o]]:!0}],props:{...E?{popover:`manual`}:{},"aria-live":`polite`,"aria-atomic":`false`,"aria-relevant":`additions text`,"aria-label":m,tabIndex:-1,...b,onPointerOver:I,onPointerOut:L,onFocus:R,onBlur:z,onKeyDown:B},children:[!V&&W,U.map(e=>(0,u.jsx)(C,{toast:e,store:y,fromTop:V,closeLabel:h},e.id)),V&&W]});return j?(0,d.createPortal)(G,j):E?G:D?(0,d.createPortal)(G,D):null}var T=e.f(w,`Toaster`);exports.createToastStore=_,exports.default=T,exports.defaultToastStore=v,exports.toast=b;
1
+ "use client";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../react-shared.cjs"),t=require("../platform.cjs"),n=require("../client.cjs"),r=require("../effects.cjs"),i=require("../interactions.cjs"),a=require("../box.cjs"),o=require("../reporting.cjs"),s=require("../layer.cjs"),c=require("../motion.cjs");let l=require("react"),u=require("react/jsx-runtime"),d=require("react-dom");var f=[`value`],p={toasts:[],overflow:0},m=0;function h(){return m+=1,`toast-${m}`}function g(e){let t=[],n=p,r=e?.limit??3,a=e?.duration??5e3,o=!1,s=new Set,c=new Map,l=e=>{let t=c.get(e);t?.handle&&clearTimeout(t.handle),c.delete(e)},u=()=>{t=t.filter(e=>e.open||e.visible);let e=t.filter(e=>!e.open).length,i=0;t=t.map(t=>{if(!t.open)return t;let n=e<r;return n?e++:i++,t.visible===n?t:{...t,visible:n}}),n={toasts:t,overflow:i},d(),s.forEach(e=>e())};function d(){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=c.get(n.id)??{handle:null,remaining:n.duration,startedAt:0};c.set(n.id,t),!(o||t.handle)&&(t.startedAt=Date.now(),t.handle=setTimeout(()=>{c.delete(n.id),g(n.id,`timeout`)},t.remaining))}for(let t of[...c.keys()])e.has(t)||l(t)}let m=(e,t)=>t??(e===`loading`?1/0:a);function g(e,n=`imperative`){let r=[];t=t.map(t=>!t.open||e!==void 0&&t.id!==e?t:(r.push(t),l(t.id),{...t,open:!1})),r.length&&(u(),r.forEach(e=>{e.onDismiss?.(n),i.t({component:`toaster`,type:`dismiss`,reason:n,value:e.message,details:{id:e.id,kind:e.kind},content:f})}))}function _(e,n,r){let a=!1;t=t.map(t=>{if(t.id!==e)return t;a=!0,l(e);let i=r?.kind??t.kind;return{...t,...r,id:e,message:n,kind:i,duration:r?.duration??(r?.kind?m(i):t.duration),open:!0}}),a&&(u(),i.t({component:`toaster`,type:`update`,reason:r?.kind,value:n,details:{id:e},source:`app`,content:f}))}function v(e,n){let r=n?.id??h();if(n?.id&&t.some(e=>e.id===r))return _(r,e,n),r;let a=n?.kind??`default`;return t=[...t,{id:r,kind:a,message:e,description:n?.description,duration:m(a,n?.duration),action:n?.action,dismissible:n?.dismissible??!0,onDismiss:n?.onDismiss,open:!0,visible:!1}],u(),i.t({component:`toaster`,type:`show`,reason:a,value:e,details:{id:r,kind:a},source:`app`,content:f}),r}return{subscribe(e){return s.add(e),()=>s.delete(e)},getSnapshot:()=>n,getServerSnapshot:()=>p,add:v,update:_,dismiss:g,remove(e){let n=t.filter(t=>t.id!==e);n.length!==t.length&&(l(e),t=n,u())},setLimit(e){e!==r&&(r=e,u())},setDefaultDuration(e){a=e},pause(){if(!o){o=!0;for(let e of c.values())e.handle&&(clearTimeout(e.handle),e.handle=null,e.remaining=Math.max(0,e.remaining-(Date.now()-e.startedAt)))}},resume(){o&&(o=!1,d())},reset(){for(let e of[...c.keys()])l(e);t=[],n=p,s.forEach(e=>e())}}}var _=g(),v=e=>(t,n)=>_.add(t,{...n,kind:e}),y=Object.assign((e,t)=>_.add(e,t),{success:v(`success`),error:v(`error`),warning:v(`warning`),info:v(`info`),loading:v(`loading`),update:(e,t,n)=>_.update(e,t,n),dismiss:e=>_.dismiss(e,`imperative`),promise(e,t,n){let r=_.add(t.loading,{...n,id:n?.id,kind:`loading`}),i=(e,t)=>typeof e==`function`?e(t):e;return e.then(e=>_.update(r,i(t.success,e),{kind:`success`}),e=>_.update(r,i(t.error,e),{kind:`error`})),e}}),b={"top-start":`topStart`,"top-center":`topCenter`,"top-end":`topEnd`,"bottom-start":`bottomStart`,"bottom-center":`bottomCenter`,"bottom-end":`bottomEnd`};function x(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 S(e){let{toast:t,store:n,fromTop:i,closeLabel:s}=e,{mounted:l,ref:d,props:f}=c.r({present:t.open}),p=o.i(`toaster`);if(r.n(()=>{l||n.remove(t.id)},[l,n,t.id]),!l)return null;let m=t.action,h=()=>{m?.onClick(),m?.closeOnClick===!1?p(`action`,t.message,{reason:`action`,id:t.id,kind:t.kind,content:[`value`]}):n.dismiss(t.id,`action`)};return(0,u.jsxs)(a.default,{ref:d,component:`toaster.toast`,variant:{[t.kind]:t.kind!=="default",fromTop:i},props:{...t.kind===`error`?{role:`alert`}:{},"data-toast-id":t.id,...f},children:[(0,u.jsx)(a.default,{component:`toaster.message`,children:t.message}),t.description!==void 0&&(0,u.jsx)(a.default,{component:`toaster.description`,children:t.description}),m&&(0,u.jsx)(a.default,{tag:`button`,component:`toaster.action`,props:{type:`button`,onClick:h},children:m.label}),t.dismissible&&(0,u.jsx)(a.default,{tag:`button`,component:`toaster.close`,props:{type:`button`,"aria-label":s,onClick:()=>n.dismiss(t.id,`close`)}})]})}function C(e,i){let{position:o=`bottom-end`,limit:c=3,duration:f=5e3,label:p=`Notifications`,closeLabel:m=`Close`,overflowLabel:h=e=>`+${e} more`,hotkey:g=`F6`,store:v=_,props:y,...C}=e,w=(0,l.useSyncExternalStore)(v.subscribe,v.getSnapshot,v.getServerSnapshot),T=s.n(),E=n.t(!T),D=(0,l.useRef)(null),O=(0,l.useCallback)(e=>{D.current=e,t.d(i,e)},[i]),k=(0,l.useRef)(null),[A,j]=(0,l.useState)(null),M=(0,l.useRef)({hovered:!1,focused:!1,hidden:!1}),N=(0,l.useCallback)(()=>{let{hovered:e,focused:t,hidden:n}=M.current;e||t||n?v.pause():v.resume()},[v]);r.n(()=>v.setLimit(c),[v,c]),r.n(()=>v.setDefaultDuration(f),[v,f]),r.n(()=>{let e=D.current;e&&(M.current.hovered=e.matches(`:hover`),M.current.focused=e.contains(e.ownerDocument.activeElement),N())},[w,A,N]),r.n(()=>{let e=D.current;!T||!t.c()||!e||!e.isConnected||e.matches(`:popover-open`)||e.showPopover()}),r.n(()=>{let e=t.t();if(!e)return;let n=[],r=new AbortController;return e.addEventListener(t.l,e=>{let{dialog:t,open:r}=e.detail,i=n.indexOf(t);i>=0&&n.splice(i,1),r&&n.push(t),j(n[n.length-1]??null)},{signal:r.signal}),()=>r.abort()},[]),r.n(()=>{let e=t.t();if(!e)return;let n=new AbortController;return e.addEventListener(`visibilitychange`,()=>{M.current.hidden=e.hidden,N()},{signal:n.signal}),()=>n.abort()},[N]),r.n(()=>{let e=t.t();if(!g||!e)return;let n=new AbortController;return e.addEventListener(`keydown`,t=>{!x(t,g)||!D.current||(t.preventDefault(),k.current=e.activeElement,D.current.focus())},{signal:n.signal}),()=>n.abort()},[g]);let P=e=>!!e&&!!D.current?.contains(e),F=()=>{M.current.hovered=!0,N()},I=e=>{P(e.relatedTarget)||(M.current.hovered=!1,N())},L=e=>{M.current.focused=!0,N(),P(e.relatedTarget)||(k.current=e.relatedTarget)},R=e=>{P(e.relatedTarget)||(M.current.focused=!1,N())},z=e=>{if(e.key!==`Escape`)return;A&&e.preventDefault();let t=(e.target.closest?.(`[data-toast-id]`))?.getAttribute(`data-toast-id`);t&&v.dismiss(t,`close`),v.getSnapshot().toasts.some(e=>e.open)?D.current?.focus():k.current?.focus()},B=o.startsWith(`top`),V=w.toasts.filter(e=>e.visible),H=B?[...V].reverse():V,U=w.overflow>0&&(0,u.jsx)(a.default,{component:`toaster.overflow`,children:h(w.overflow)}),W=(0,u.jsxs)(a.default,{tag:`section`,ref:O,component:`toaster`,...C,variant:[C.variant,{[b[o]]:!0}],props:{...T?{popover:`manual`}:{},"aria-live":`polite`,"aria-atomic":`false`,"aria-relevant":`additions text`,"aria-label":p,tabIndex:-1,...y,onPointerOver:F,onPointerOut:I,onFocus:L,onBlur:R,onKeyDown:z},children:[!B&&U,H.map(e=>(0,u.jsx)(S,{toast:e,store:v,fromTop:B,closeLabel:m},e.id)),B&&U]});return A?(0,d.createPortal)(W,A):T?W:E?(0,d.createPortal)(W,E):null}var w=e.f(C,`Toaster`);exports.createToastStore=g,exports.default=w,exports.defaultToastStore=_,exports.toast=y;
@@ -8,10 +8,9 @@ import c from "../box.mjs";
8
8
  import { i as l } from "../reporting.mjs";
9
9
  import { n as u } from "../layer.mjs";
10
10
  import { r as d } from "../motion.mjs";
11
- import { useCallback as f, useRef as p, useState as m } from "react";
12
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
13
- import { createPortal as _ } from "react-dom";
14
- import { useSyncExternalStore as v } from "use-sync-external-store/shim";
11
+ import { useCallback as f, useRef as p, useState as m, useSyncExternalStore as h } from "react";
12
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
13
+ import { createPortal as v } from "react-dom";
15
14
  //#region src/utils/toast/toastStore.ts
16
15
  var y = ["value"], b = {
17
16
  toasts: [],
@@ -212,7 +211,7 @@ function k(e) {
212
211
  content: ["value"]
213
212
  }) : n.dismiss(t.id, "action");
214
213
  };
215
- return /* @__PURE__ */ g(c, {
214
+ return /* @__PURE__ */ _(c, {
216
215
  ref: s,
217
216
  component: "toaster.toast",
218
217
  variant: {
@@ -225,15 +224,15 @@ function k(e) {
225
224
  ...u
226
225
  },
227
226
  children: [
228
- /* @__PURE__ */ h(c, {
227
+ /* @__PURE__ */ g(c, {
229
228
  component: "toaster.message",
230
229
  children: t.message
231
230
  }),
232
- t.description !== void 0 && /* @__PURE__ */ h(c, {
231
+ t.description !== void 0 && /* @__PURE__ */ g(c, {
233
232
  component: "toaster.description",
234
233
  children: t.description
235
234
  }),
236
- p && /* @__PURE__ */ h(c, {
235
+ p && /* @__PURE__ */ g(c, {
237
236
  tag: "button",
238
237
  component: "toaster.action",
239
238
  props: {
@@ -242,7 +241,7 @@ function k(e) {
242
241
  },
243
242
  children: p.label
244
243
  }),
245
- t.dismissible && /* @__PURE__ */ h(c, {
244
+ t.dismissible && /* @__PURE__ */ g(c, {
246
245
  tag: "button",
247
246
  component: "toaster.close",
248
247
  props: {
@@ -255,7 +254,7 @@ function k(e) {
255
254
  });
256
255
  }
257
256
  function A(e, s) {
258
- let { position: l = "bottom-end", limit: d = 3, duration: y = 5e3, label: b = "Notifications", closeLabel: x = "Close", overflowLabel: S = (e) => `+${e} more`, hotkey: C = "F6", store: T = w, props: E, ...A } = e, j = v(T.subscribe, T.getSnapshot, T.getServerSnapshot), M = u(), N = a(!M), P = p(null), F = f((e) => {
257
+ let { position: l = "bottom-end", limit: d = 3, duration: y = 5e3, label: b = "Notifications", closeLabel: x = "Close", overflowLabel: S = (e) => `+${e} more`, hotkey: C = "F6", store: T = w, props: E, ...A } = e, j = h(T.subscribe, T.getSnapshot, T.getServerSnapshot), M = u(), N = a(!M), P = p(null), F = f((e) => {
259
258
  P.current = e, n(s, e);
260
259
  }, [s]), I = p(null), [L, R] = m(null), z = p({
261
260
  hovered: !1,
@@ -311,10 +310,10 @@ function A(e, s) {
311
310
  L && e.preventDefault();
312
311
  let t = (e.target.closest?.("[data-toast-id]"))?.getAttribute("data-toast-id");
313
312
  t && T.dismiss(t, "close"), T.getSnapshot().toasts.some((e) => e.open) ? P.current?.focus() : I.current?.focus();
314
- }, q = l.startsWith("top"), J = j.toasts.filter((e) => e.visible), Y = q ? [...J].reverse() : J, X = j.overflow > 0 && /* @__PURE__ */ h(c, {
313
+ }, q = l.startsWith("top"), J = j.toasts.filter((e) => e.visible), Y = q ? [...J].reverse() : J, X = j.overflow > 0 && /* @__PURE__ */ g(c, {
315
314
  component: "toaster.overflow",
316
315
  children: S(j.overflow)
317
- }), Z = /* @__PURE__ */ g(c, {
316
+ }), Z = /* @__PURE__ */ _(c, {
318
317
  tag: "section",
319
318
  ref: F,
320
319
  component: "toaster",
@@ -336,7 +335,7 @@ function A(e, s) {
336
335
  },
337
336
  children: [
338
337
  !q && X,
339
- Y.map((e) => /* @__PURE__ */ h(k, {
338
+ Y.map((e) => /* @__PURE__ */ g(k, {
340
339
  toast: e,
341
340
  store: T,
342
341
  fromTop: q,
@@ -345,7 +344,7 @@ function A(e, s) {
345
344
  q && X
346
345
  ]
347
346
  });
348
- return L ? _(Z, L) : M ? Z : N ? _(Z, N) : null;
347
+ return L ? v(Z, L) : M ? Z : N ? v(Z, N) : null;
349
348
  }
350
349
  var j = e(A, "Toaster");
351
350
  //#endregion
package/docs/a11y.md CHANGED
@@ -158,8 +158,7 @@ const id = useIdentifier('select');
158
158
 
159
159
  React's `useId` with the punctuation removed: `:r1:` (React 18) and `«r1»` (React 19) are both
160
160
  rejected by `querySelector('#…')`, and the part that varies is the word characters. Derive related
161
- ids from one call rather than calling the hook once per element. On React 16/17, which have no
162
- `useId`, the fallback is a module counter — pass ids in explicitly there if the tree is hydrated.
161
+ ids from one call rather than calling the hook once per element.
163
162
 
164
163
  ## `VisuallyHidden`
165
164
 
package/docs/index.md CHANGED
@@ -11,4 +11,4 @@ The markdown `@box-kite/react` ships for whatever is reading its source tree. No
11
11
  - [`interop.md`](interop.md) — the agentic runtimes (`@box-kite/react/interop`): AI SDK, assistant-ui, CopilotKit, A2UI and AG-UI, each verified against its own package
12
12
  - [`mcp.md`](mcp.md) — the MCP server (`npx @box-kite/mcp`), whose `check_styles` tool is the only way to be sure a value works
13
13
 
14
- The rest sits at the package root: `BOX_KITE_AI_CONTEXT.md`, the long-form reference (prop tables, the DataGrid API, debugging); `.claude/skills/box-kite/`, the same rules as an installable skill with four references beside it; and `.cursor/rules/box-kite.mdc`, which is that skill as a Cursor rule — copy either into the project rather than reading it from here, so it is loaded without anyone asking.
14
+ The rest sits at the package root: `BOX_KITE_AI_CONTEXT.md`, the long-form reference (prop tables, the DataGrid API, debugging); `.claude/skills/box-kite/`, the same rules as an installable skill with five references beside it; and `.cursor/rules/box-kite.mdc`, which is that skill as a Cursor rule — copy either into the project rather than reading it from here, so it is loaded without anyone asking.
package/effects.cjs CHANGED
@@ -1 +1 @@
1
- const e=require("./rolldown-runtime.cjs"),t=require("./platform.cjs");let n=require("react");n=e.t(n,1);var r=t.i(),i=r?n.useLayoutEffect:n.useEffect,a=r?n.default.useInsertionEffect??n.useLayoutEffect:n.useEffect;Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return a}});
1
+ const e=require("./platform.cjs");let t=require("react");var n=e.i(),r=n?t.useLayoutEffect:t.useEffect,i=n?t.useInsertionEffect:t.useEffect;Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
package/effects.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { i as e } from "./platform.mjs";
2
- import t, { useEffect as n, useLayoutEffect as r } from "react";
2
+ import { useEffect as t, useInsertionEffect as n, useLayoutEffect as r } from "react";
3
3
  //#region src/react/effects.ts
4
- var i = e(), a = i ? r : n, o = i ? t.useInsertionEffect ?? r : n;
4
+ var i = e(), a = i ? r : t, o = i ? n : t;
5
5
  //#endregion
6
6
  export { a as n, o as t };
package/identity.cjs CHANGED
@@ -1 +1 @@
1
- const e=require("./rolldown-runtime.cjs");let t=require("react");t=e.t(t,1);var n=t.default.useId??(()=>void 0),r=0;function i(e){return e.replace(/[^\w-]/g,``)}function a(e=`box`){let a=n(),[o]=(0,t.useState)(()=>`${++r}`);return`${e}-${a?i(a):o}`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return a}});
1
+ let e=require("react");function t(e){return e.replace(/[^\w-]/g,``)}function n(n=`box`){return`${n}-${t((0,e.useId)())}`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return n}});
package/identity.mjs CHANGED
@@ -1,12 +1,10 @@
1
- import e, { useState as t } from "react";
1
+ import { useId as e } from "react";
2
2
  //#region src/react/identity/useIdentifier.ts
3
- var n = e.useId ?? (() => void 0), r = 0;
4
- function i(e) {
3
+ function t(e) {
5
4
  return e.replace(/[^\w-]/g, "");
6
5
  }
7
- function a(e = "box") {
8
- let a = n(), [o] = t(() => `${++r}`);
9
- return `${e}-${a ? i(a) : o}`;
6
+ function n(n = "box") {
7
+ return `${n}-${t(e())}`;
10
8
  }
11
9
  //#endregion
12
- export { a as t };
10
+ export { n as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box-kite/react",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "pages/**"
@@ -104,6 +104,8 @@
104
104
  "docs:components": "node scripts/check-components-api.mjs --fix",
105
105
  "check:catalog": "node scripts/check-catalog-api.mjs",
106
106
  "docs:catalog": "node scripts/check-catalog-api.mjs --fix",
107
+ "check:csstype": "node scripts/check-csstype.mjs",
108
+ "docs:csstype": "node scripts/check-csstype.mjs --fix",
107
109
  "check:create": "node scripts/check-create-templates.mjs",
108
110
  "docs:create": "node scripts/check-create-templates.mjs --fix",
109
111
  "check:conventions": "node scripts/check-component-conventions.mjs",
@@ -650,13 +652,8 @@
650
652
  "homepage": "https://www.box-kite.dev",
651
653
  "description": "One React component that takes CSS properties as typed props and generates atomic CSS at runtime — no CSS files, no build step, renders in a Server Component.",
652
654
  "peerDependencies": {
653
- "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
654
- "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
655
- },
656
- "dependencies": {
657
- "@box-kite/core": "2.3.1",
658
- "csstype": "^3.2.3",
659
- "use-sync-external-store": "^1.6.0"
655
+ "react": ">=18.0.0",
656
+ "react-dom": ">=18.0.0"
660
657
  },
661
658
  "devDependencies": {
662
659
  "@arethetypeswrong/cli": "^0.18.5",
@@ -686,13 +683,13 @@
686
683
  "@types/node": "^26.1.2",
687
684
  "@types/react": "^19.2.18",
688
685
  "@types/react-dom": "^19.2.4",
689
- "@types/use-sync-external-store": "^1.5.0",
690
686
  "@vitejs/plugin-react": "^6.0.5",
691
687
  "@vitest/coverage-v8": "^4.1.11",
692
688
  "ag-grid-community": "^36.2.0",
693
689
  "ag-grid-react": "^36.2.0",
694
690
  "axe-core": "^4.13.0",
695
691
  "create-vite": "^9.3.0",
692
+ "csstype": "^3.2.3",
696
693
  "eslint": "^10.8.0",
697
694
  "eslint-config-prettier": "^10.1.8",
698
695
  "eslint-plugin-import-x": "^4.17.1",
@@ -719,5 +716,8 @@
719
716
  "vite-plugin-dts": "^5.0.3",
720
717
  "vitest": "^4.1.10",
721
718
  "zod": "^4.6.5"
719
+ },
720
+ "dependencies": {
721
+ "@box-kite/core": "2.4.0"
722
722
  }
723
723
  }
@@ -1,10 +1,9 @@
1
- import { default as React, useLayoutEffect } from 'react';
1
+ import { useEffect, useLayoutEffect } from 'react';
2
2
  /** A layout effect on the browser, a passive one everywhere else. */
3
- export declare const useIsomorphicLayoutEffect: typeof React.useEffect;
3
+ export declare const useIsomorphicLayoutEffect: typeof useEffect;
4
4
  /**
5
- * An insertion effect on the browser, falling back to a layout effect on React 16/17 — React's own
6
- * recommendation for injecting CSS-in-JS. Insertion effects run during the commit ahead of *every* layout
7
- * effect, so a component measuring its DOM already sees the styles. Off the browser nothing paints and
8
- * `getStyles()` flushes for itself, so `useEffect` keeps React quiet.
5
+ * An insertion effect on the browser — React's own recommendation for injecting CSS-in-JS. It runs during
6
+ * the commit ahead of *every* layout effect, so a component measuring its DOM already sees the styles. Off
7
+ * the browser nothing paints and `getStyles()` flushes for itself, so `useEffect` keeps React quiet.
9
8
  */
10
9
  export declare const useIsomorphicInsertionEffect: typeof useLayoutEffect;
@@ -10,8 +10,5 @@
10
10
  * const id = useIdentifier('select');
11
11
  * // `${id}-trigger`, `${id}-listbox`
12
12
  * ```
13
- *
14
- * On React 16/17 the fallback is a module counter, which cannot match between a server render and
15
- * the client one — pass ids in explicitly there if the tree is hydrated.
16
13
  */
17
14
  export default function useIdentifier(prefix?: string): string;