@box-kite/react 2.2.7 → 2.2.8

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 (96) hide show
  1. package/BOX_AI_CONTEXT.md +76 -0
  2. package/BOX_KITE_AI_CONTEXT.md +76 -0
  3. package/analytics.cjs +1 -0
  4. package/analytics.d.ts +10 -0
  5. package/analytics.mjs +121 -0
  6. package/behavior.cjs +1 -1
  7. package/behavior.mjs +42 -38
  8. package/box.cjs +1 -1
  9. package/box.d.ts +9 -0
  10. package/box.mjs +17 -16
  11. package/catalog.cjs +1 -1
  12. package/catalog.mjs +8 -0
  13. package/client.cjs +1 -1
  14. package/client.mjs +120 -120
  15. package/components/accordion.cjs +1 -1
  16. package/components/accordion.mjs +19 -10
  17. package/components/agent.cjs +1 -1
  18. package/components/agent.mjs +21 -8
  19. package/components/calendar.cjs +1 -1
  20. package/components/calendar.d.ts +3 -1
  21. package/components/calendar.mjs +154 -142
  22. package/components/combobox.cjs +1 -1
  23. package/components/combobox.mjs +184 -174
  24. package/components/dashboard.cjs +1 -1
  25. package/components/dashboard.mjs +183 -170
  26. package/components/dataGrid/models/columnModel.d.ts +1 -0
  27. package/components/dataGrid/models/gridModel.d.ts +18 -0
  28. package/components/dataGrid/models/rangeModel.d.ts +3 -0
  29. package/components/dataGrid.cjs +3 -3
  30. package/components/dataGrid.mjs +987 -896
  31. package/components/dateField.cjs +1 -1
  32. package/components/dateField.mjs +165 -159
  33. package/components/datePicker.cjs +1 -1
  34. package/components/datePicker.mjs +198 -183
  35. package/components/dialog.cjs +1 -1
  36. package/components/dialog.mjs +38 -33
  37. package/components/dropdown.cjs +1 -1
  38. package/components/dropdown.mjs +107 -93
  39. package/components/form.cjs +1 -1
  40. package/components/form.mjs +22 -18
  41. package/components/menu.cjs +1 -1
  42. package/components/menu.d.ts +2 -0
  43. package/components/menu.mjs +196 -175
  44. package/components/overlay.cjs +1 -1
  45. package/components/overlay.mjs +7 -7
  46. package/components/popover.cjs +1 -1
  47. package/components/popover.mjs +4 -0
  48. package/components/radioGroup.cjs +1 -1
  49. package/components/radioGroup.mjs +10 -5
  50. package/components/slider.cjs +1 -1
  51. package/components/slider.mjs +84 -83
  52. package/components/sortableList.cjs +1 -1
  53. package/components/sortableList.mjs +158 -150
  54. package/components/swipeItem.cjs +1 -1
  55. package/components/swipeItem.mjs +92 -84
  56. package/components/tabs.cjs +1 -1
  57. package/components/tabs.mjs +10 -5
  58. package/components/timeZoneSelect.cjs +1 -1
  59. package/components/timeZoneSelect.mjs +40 -35
  60. package/components/toaster.cjs +1 -1
  61. package/components/toaster.mjs +151 -113
  62. package/dataGridDateParts.cjs +1 -1
  63. package/dataGridDateParts.mjs +56 -55
  64. package/dataGridList.cjs +1 -1
  65. package/dataGridList.mjs +430 -429
  66. package/effects.cjs +1 -1
  67. package/effects.mjs +1 -1
  68. package/interactionListening.cjs +1 -0
  69. package/interactionListening.mjs +117 -0
  70. package/interactions.cjs +1 -0
  71. package/interactions.mjs +25 -0
  72. package/layer.cjs +1 -1
  73. package/layer.mjs +68 -66
  74. package/package.json +132 -68
  75. package/placement.cjs +1 -1
  76. package/placement.mjs +10 -10
  77. package/platform.cjs +1 -1
  78. package/platform.mjs +44 -25
  79. package/react/interactions/interactions.d.ts +30 -0
  80. package/react/popover/usePopoverLayer.d.ts +3 -0
  81. package/react/useStyles.d.ts +8 -1
  82. package/react-shared.cjs +1 -1
  83. package/react-shared.mjs +49 -48
  84. package/reporting.cjs +1 -0
  85. package/reporting.mjs +51 -0
  86. package/scrolling.cjs +1 -1
  87. package/scrolling.mjs +1 -1
  88. package/supabase/functions/collect/index.d.ts +30 -0
  89. package/supabase/functions/collect/index.test.d.ts +1 -0
  90. package/utils/analytics/analytics.d.ts +72 -0
  91. package/utils/analytics/analyticsIdentity.d.ts +13 -0
  92. package/utils/interactions/componentAttribute.d.ts +6 -0
  93. package/utils/interactions/interactionChannel.d.ts +35 -0
  94. package/utils/interactions/interactionJson.d.ts +6 -0
  95. package/utils/interactions/interactionListening.d.ts +6 -0
  96. package/utils/interactions/interactionTypes.d.ts +224 -0
package/platform.mjs CHANGED
@@ -1,48 +1,67 @@
1
+ //#region src/utils/interactions/componentAttribute.ts
2
+ var e = globalThis[Symbol.for("box-kite.componentAttribute")] ??= {
3
+ on: !1,
4
+ warnings: !0
5
+ }, t = () => e.on, n = () => e.warnings;
6
+ function r(t) {
7
+ e.on = t;
8
+ }
9
+ function i(t) {
10
+ e.warnings = t;
11
+ }
12
+ //#endregion
1
13
  //#region src/utils/dom/domUtils.ts
2
- function e(e) {
14
+ function a(e) {
3
15
  return e ? "current" in e ? e.current : e : null;
4
16
  }
5
- function t(t) {
6
- let n = e(t);
7
- return n instanceof HTMLElement ? n : null;
17
+ function o(e) {
18
+ let t = a(e);
19
+ return t instanceof HTMLElement ? t : null;
8
20
  }
9
- function n(t, n) {
10
- let r = typeof t.composedPath == "function" ? t.composedPath() : [];
11
- return n.some((n) => {
12
- let i = e(n);
13
- return i ? r.includes(i) || t.target instanceof Node && i.contains(t.target) : !1;
21
+ function s(e, t) {
22
+ let n = typeof e.composedPath == "function" ? e.composedPath() : [];
23
+ return t.some((t) => {
24
+ let r = a(t);
25
+ return r ? n.includes(r) || e.target instanceof Node && r.contains(e.target) : !1;
14
26
  });
15
27
  }
16
- function r(t) {
17
- let n = e(t), r = n?.ownerDocument?.defaultView;
18
- return !!n && !!r && r.getComputedStyle(n).direction === "rtl";
28
+ function c(e) {
29
+ let t = a(e), n = t?.ownerDocument?.defaultView;
30
+ return !!t && !!n && n.getComputedStyle(t).direction === "rtl";
19
31
  }
20
- function i(t) {
21
- let n = e(t)?.ownerDocument?.defaultView?.getSelection();
22
- n && !n.isCollapsed && n.removeAllRanges();
32
+ function l(e) {
33
+ let t = a(e)?.ownerDocument?.defaultView?.getSelection();
34
+ t && !t.isCollapsed && t.removeAllRanges();
23
35
  }
24
36
  //#endregion
25
37
  //#region src/utils/environment/environmentUtils.ts
26
- function a() {
38
+ function u() {
27
39
  return typeof window < "u" && window.document !== void 0;
28
40
  }
29
- function o() {
41
+ function d() {
42
+ try {
43
+ return process.env.NODE_ENV !== "production";
44
+ } catch {
45
+ return !1;
46
+ }
47
+ }
48
+ function f() {
30
49
  return typeof document < "u";
31
50
  }
32
- function s() {
33
- return o() ? document : null;
51
+ function p() {
52
+ return f() ? document : null;
34
53
  }
35
- function c() {
36
- return s()?.documentElement ?? null;
54
+ function m() {
55
+ return p()?.documentElement ?? null;
37
56
  }
38
- function l() {
57
+ function h() {
39
58
  return typeof HTMLElement < "u" && typeof HTMLElement.prototype.showPopover == "function";
40
59
  }
41
- function u() {
60
+ function g() {
42
61
  return typeof HTMLDialogElement < "u" && "closedBy" in HTMLDialogElement.prototype;
43
62
  }
44
- function d(e) {
63
+ function _(e) {
45
64
  return typeof window > "u" || typeof window.matchMedia != "function" ? null : window.matchMedia(e);
46
65
  }
47
66
  //#endregion
48
- export { u as a, e as c, r as d, d as i, t as l, c as n, l as o, a as r, i as s, s as t, n as u };
67
+ export { n as _, d as a, h as c, o as d, s as f, r as g, i as h, u as i, l, t as m, m as n, _ as o, c as p, f as r, g as s, p as t, a as u };
@@ -0,0 +1,30 @@
1
+ import { ReactNode } from 'react';
2
+ import { InteractionComponent, InteractionSource, InteractionType } from '../../utils/interactions/interactionChannel';
3
+ import { ChangeDetails, ControllableStateOptions, SetControllableState } from '../a11y/useControllableState';
4
+ export declare function QuietInteractions({ children }: {
5
+ children: ReactNode;
6
+ }): import('react').FunctionComponentElement<import('react').ProviderProps<boolean>>;
7
+ /** Where a quiet part renders the app's own content (a `rowDetail`, a column's `Cell`), which reports as usual. */
8
+ export declare function ReportInteractions({ children }: {
9
+ children: ReactNode;
10
+ }): import('react').FunctionComponentElement<import('react').ProviderProps<boolean>>;
11
+ /**
12
+ * A callback's details as they stand, or a record of them: `reason`, `event` and `content` are lifted out and the rest is
13
+ * `details`. `content` names what a person typed or picked as data (`['value', 'oldValue']`), which a listener has to ask for.
14
+ */
15
+ export type InteractionDetails = (Partial<ChangeDetails> | Record<string, unknown>) & {
16
+ content?: readonly string[];
17
+ };
18
+ export type ReportInteraction<C extends InteractionComponent> = (type: InteractionType<C>, value?: unknown, details?: InteractionDetails) => void;
19
+ /** `report(type, value, { reason, event, content, ...details })` for one component, silent inside `QuietInteractions`. */
20
+ export declare function useInteractionReporter<C extends InteractionComponent>(component: C | undefined): ReportInteraction<C>;
21
+ /** A stable change handler that `Box.onInteraction` hears as well, under `component` and `type`. */
22
+ export declare function useInteractionCallback<C extends InteractionComponent, T, TDetails extends ChangeDetails>(fn: ((value: T, details: TDetails) => void) | undefined, component: C, type: InteractionType<C>): (value: T, details: TDetails) => void;
23
+ /** Which component a value belongs to and which of its changes it is, plus what of it is content. */
24
+ export type ReportedAs = InteractionSource & {
25
+ content?: readonly string[];
26
+ };
27
+ /** `useControllableState`, with every change it makes also reaching `Box.onInteraction`. */
28
+ export declare function useReportedState<T, TReason extends string = string>(options: ControllableStateOptions<T, TReason> & {
29
+ interaction?: ReportedAs;
30
+ }): [T, SetControllableState<T, TReason>];
@@ -1,4 +1,5 @@
1
1
  import { ElementLike } from '../../utils/dom/domUtils';
2
+ import { InteractionSource } from '../../utils/interactions/interactionChannel';
2
3
  import { ChangeHandler, SetControllableState } from '../a11y/useControllableState';
3
4
  /** Why a layer opened or closed — every component built on this reports the same four. */
4
5
  export type PopoverReason = 'trigger' | 'escape' | 'outside-pointer' | 'imperative';
@@ -54,6 +55,8 @@ export interface PopoverLayerOptions<THasPopup extends PopoverHasPopup = Popover
54
55
  * one. The platform answers that question itself, by the popover nesting rules.
55
56
  */
56
57
  inside?: readonly ElementLike[];
58
+ /** Which component the layer is, so its open state also reaches `Box.onInteraction`. */
59
+ interaction?: InteractionSource;
57
60
  }
58
61
  export interface PopoverLayer<THasPopup extends PopoverHasPopup = PopoverHasPopup, TReason extends string = never> {
59
62
  /** Whether the browser's Popover API is placing the layer in the top layer. `false` is the portal path. */
@@ -2,6 +2,13 @@ import { StylesConfiguration } from '@box-kite/core';
2
2
  import { BoxStyleProps } from '@box-kite/core/types';
3
3
  import { ResolvedBoxStyles } from './resolveStyles';
4
4
  export type { StylesConfiguration };
5
+ export interface BoxConfiguration extends StylesConfiguration {
6
+ /**
7
+ * Write `data-bk="<component key>"` on every element a component styles, so one delegated listener can
8
+ * name what was pressed. Set it where the server and the browser both run, or hydration sees two trees.
9
+ */
10
+ componentAttribute?: boolean;
11
+ }
5
12
  export default function useStyles(props: BoxStyleProps<any>, isSvg: boolean): ResolvedBoxStyles;
6
13
  /**
7
14
  * Rules that target a root selector (`html`) instead of a class. Returns their style elements in
@@ -20,5 +27,5 @@ export declare namespace StylesContext {
20
27
  /** The id of the `<style>` element the default engine writes to. */
21
28
  function styleElementId(): string;
22
29
  /** Apply explicit engine configuration. Call before the first render — cached class names are dropped when the configuration changes. */
23
- function configure(config: StylesConfiguration): void;
30
+ function configure({ componentAttribute, ...config }: BoxConfiguration): void;
24
31
  }
package/react-shared.cjs CHANGED
@@ -1 +1 @@
1
- const e=require("./rolldown-runtime.cjs");let t=require("react");t=e.t(t,1);let n=require("@box-kite/core");function r({classNames:e,styleElements:t},r){return{className:(0,n.classNames)(e,r).join(` `),styles:t}}var i=parseInt(t.default.version,10)>=19;function a(e,n){let r=i?({ref:t,...n})=>e(n,t??null):(0,t.forwardRef)(e),a=(0,t.memo)(r);return r.displayName=n,a.displayName=n,a}var o={selected:`aria-selected`},s;(function(e){function t(e,t,n){e!==void 0&&e!=null&&(n[o[t]??t]=Array.isArray(e)?e[0]:e)}e.assignBooleanProp=t})(s||={});var c=s;function l(e,t){let r=e,{props:i,className:a,disabled:o,required:s,checked:l,selected:u}=r,d={...i,className:(0,n.classNames)(t,a).join(` `)};return c.assignBooleanProp(o,`disabled`,d),c.assignBooleanProp(s,`required`,d),c.assignBooleanProp(l,`checked`,d),c.assignBooleanProp(u,`selected`,d),`style`in r&&(d.style=r.style),`id`in r&&(d.id=r.id),d}var u=parseInt(t.default.version,10)>=19,d=!1,f=new WeakMap,p=new WeakMap;function m(e){let n=f.get(e);if(!n){let{href:r,css:i,precedence:a}=e;n=t.default.createElement(`style`,{key:r,href:r,precedence:a,dangerouslySetInnerHTML:{__html:i}}),f.set(e,n)}return n}function h(e){if(!e?.length)return;!u&&!d&&(d=!0,console.warn(`[box-kite] Box.configure({ sink: 'element' }) needs React 19 to hoist and dedupe its <style> elements; React ${t.default.version} will render them inline. Use the default sink instead.`));let n=p.get(e);return n||(n=e.map(m),p.set(e,n)),n}function g(e,t,r){let{classNames:i,signature:a,styleElements:o}=(0,n.getDefaultEngine)().resolveClassNames(e,t,r);return{classNames:i,signature:a,styleElements:h(o)}}var _=`__boxAttributesInProps`;function v(e){return e[_]=!0,e}function y(e){return typeof e==`function`||typeof e==`object`&&e?e[_]===!0:!1}var b=[`role`,`aria-label`,`aria-labelledby`,`aria-hidden`];function x(e,t){if(e!==void 0)return{role:`img`,"aria-label":e};if(!(t&&b.some(e=>e in t)))return{"aria-hidden":!0}}var S;(function(e){function t(e){return e.charAt(0).toUpperCase()+e.slice(1)}e.capitalize=t})(S||={});var C=S,w;(function(e){function t(e,t,n){let r={...e},i=r.props||{};return t.forEach(e=>{e in r&&(i[e]=r[e],delete r[e])}),n&&Object.entries(n).forEach(([e,t])=>{i[e]=t}),r.props=i,r}e.buildProps=t;function n(e){return!!e&&typeof e==`object`}e.isObject=n;function r(e,t){return e in t}e.isKeyOf=r})(w||={});var T=w,E=[`sky-500`,`emerald-500`,`amber-500`,`violet-500`,`rose-500`,`cyan-500`],D=[`sky-400`,`emerald-400`,`amber-400`,`violet-400`,`rose-400`,`cyan-400`];function O(e){return e.reduce((e,t,n)=>(e[`chart-${n+1}`]=t,e),{})}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return h}});
1
+ const e=require("./rolldown-runtime.cjs"),t=require("./platform.cjs");let n=require("react");n=e.t(n,1);let r=require("@box-kite/core");function i({classNames:e,styleElements:t},n){return{className:(0,r.classNames)(e,n).join(` `),styles:t}}var a=parseInt(n.default.version,10)>=19;function o(e,t){let r=a?({ref:t,...n})=>e(n,t??null):(0,n.forwardRef)(e),i=(0,n.memo)(r);return r.displayName=t,i.displayName=t,i}var s={selected:`aria-selected`},c;(function(e){function t(e,t,n){e!==void 0&&e!=null&&(n[s[t]??t]=Array.isArray(e)?e[0]:e)}e.assignBooleanProp=t})(c||={});var l=c;function u(e,n){let i=e,{props:a,className:o,disabled:s,required:c,checked:u,selected:d}=i,f={...a,className:(0,r.classNames)(n,o).join(` `)};return typeof i.component==`string`&&t.m()&&(f[`data-bk`]??=i.component),l.assignBooleanProp(s,`disabled`,f),l.assignBooleanProp(c,`required`,f),l.assignBooleanProp(u,`checked`,f),l.assignBooleanProp(d,`selected`,f),`style`in i&&(f.style=i.style),`id`in i&&(f.id=i.id),f}var d=parseInt(n.default.version,10)>=19,f=!1,p=new WeakMap,m=new WeakMap;function h(e){let t=p.get(e);if(!t){let{href:r,css:i,precedence:a}=e;t=n.default.createElement(`style`,{key:r,href:r,precedence:a,dangerouslySetInnerHTML:{__html:i}}),p.set(e,t)}return t}function g(e){if(!e?.length)return;!d&&!f&&(f=!0,console.warn(`[box-kite] Box.configure({ sink: 'element' }) needs React 19 to hoist and dedupe its <style> elements; React ${n.default.version} will render them inline. Use the default sink instead.`));let t=m.get(e);return t||(t=e.map(h),m.set(e,t)),t}function _(e,t,n){let{classNames:i,signature:a,styleElements:o}=(0,r.getDefaultEngine)().resolveClassNames(e,t,n);return{classNames:i,signature:a,styleElements:g(o)}}var v=`__boxAttributesInProps`;function y(e){return e[v]=!0,e}function b(e){return typeof e==`function`||typeof e==`object`&&e?e[v]===!0:!1}var x=[`role`,`aria-label`,`aria-labelledby`,`aria-hidden`];function S(e,t){if(e!==void 0)return{role:`img`,"aria-label":e};if(!(t&&x.some(e=>e in t)))return{"aria-hidden":!0}}var C;(function(e){function t(e){return e.charAt(0).toUpperCase()+e.slice(1)}e.capitalize=t})(C||={});var w=C,T;(function(e){function t(e,t,n){let r={...e},i=r.props||{};return t.forEach(e=>{e in r&&(i[e]=r[e],delete r[e])}),n&&Object.entries(n).forEach(([e,t])=>{i[e]=t}),r.props=i,r}e.buildProps=t;function n(e){return!!e&&typeof e==`object`}e.isObject=n;function r(e,t){return e in t}e.isKeyOf=r})(T||={});var E=T,D=[`sky-500`,`emerald-500`,`amber-500`,`violet-500`,`rose-500`,`cyan-500`],O=[`sky-400`,`emerald-400`,`amber-400`,`violet-400`,`rose-400`,`cyan-400`];function k(e){return e.reduce((e,t,n)=>(e[`chart-${n+1}`]=t,e),{})}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return g}});
package/react-shared.mjs CHANGED
@@ -1,104 +1,105 @@
1
- import e, { forwardRef as t, memo as n } from "react";
2
- import { classNames as r, getDefaultEngine as i } from "@box-kite/core";
1
+ import { m as e } from "./platform.mjs";
2
+ import t, { forwardRef as n, memo as r } from "react";
3
+ import { classNames as i, getDefaultEngine as a } from "@box-kite/core";
3
4
  //#region src/react/boxClassNames.ts
4
- function a({ classNames: e, styleElements: t }, n) {
5
+ function o({ classNames: e, styleElements: t }, n) {
5
6
  return {
6
- className: r(e, n).join(" "),
7
+ className: i(e, n).join(" "),
7
8
  styles: t
8
9
  };
9
10
  }
10
11
  //#endregion
11
12
  //#region src/react/boxComponent.ts
12
- var o = parseInt(e.version, 10) >= 19;
13
- function s(e, r) {
14
- let i = o ? ({ ref: t, ...n }) => e(n, t ?? null) : t(e), a = n(i);
15
- return i.displayName = r, a.displayName = r, a;
13
+ var s = parseInt(t.version, 10) >= 19;
14
+ function c(e, t) {
15
+ let i = s ? ({ ref: t, ...n }) => e(n, t ?? null) : n(e), a = r(i);
16
+ return i.displayName = t, a.displayName = t, a;
16
17
  }
17
18
  //#endregion
18
19
  //#region src/utils/box/boxUtils.ts
19
- var c = { selected: "aria-selected" }, l;
20
+ var l = { selected: "aria-selected" }, u;
20
21
  (function(e) {
21
22
  function t(e, t, n) {
22
- e !== void 0 && e != null && (n[c[t] ?? t] = Array.isArray(e) ? e[0] : e);
23
+ e !== void 0 && e != null && (n[l[t] ?? t] = Array.isArray(e) ? e[0] : e);
23
24
  }
24
25
  e.assignBooleanProp = t;
25
- })(l ||= {});
26
- var u = l;
26
+ })(u ||= {});
27
+ var d = u;
27
28
  //#endregion
28
29
  //#region src/react/boxTagProps.ts
29
- function d(e, t) {
30
- let n = e, { props: i, className: a, disabled: o, required: s, checked: c, selected: l } = n, d = {
31
- ...i,
32
- className: r(t, a).join(" ")
30
+ function f(t, n) {
31
+ let r = t, { props: a, className: o, disabled: s, required: c, checked: l, selected: u } = r, f = {
32
+ ...a,
33
+ className: i(n, o).join(" ")
33
34
  };
34
- return u.assignBooleanProp(o, "disabled", d), u.assignBooleanProp(s, "required", d), u.assignBooleanProp(c, "checked", d), u.assignBooleanProp(l, "selected", d), "style" in n && (d.style = n.style), "id" in n && (d.id = n.id), d;
35
+ return typeof r.component == "string" && e() && (f["data-bk"] ??= r.component), d.assignBooleanProp(s, "disabled", f), d.assignBooleanProp(c, "required", f), d.assignBooleanProp(l, "checked", f), d.assignBooleanProp(u, "selected", f), "style" in r && (f.style = r.style), "id" in r && (f.id = r.id), f;
35
36
  }
36
37
  //#endregion
37
38
  //#region src/react/styleElements.ts
38
- var f = parseInt(e.version, 10) >= 19, p = !1, m = /* @__PURE__ */ new WeakMap(), h = /* @__PURE__ */ new WeakMap();
39
- function g(t) {
40
- let n = m.get(t);
39
+ var p = parseInt(t.version, 10) >= 19, m = !1, h = /* @__PURE__ */ new WeakMap(), g = /* @__PURE__ */ new WeakMap();
40
+ function _(e) {
41
+ let n = h.get(e);
41
42
  if (!n) {
42
- let { href: r, css: i, precedence: a } = t;
43
- n = e.createElement("style", {
43
+ let { href: r, css: i, precedence: a } = e;
44
+ n = t.createElement("style", {
44
45
  key: r,
45
46
  href: r,
46
47
  precedence: a,
47
48
  dangerouslySetInnerHTML: { __html: i }
48
- }), m.set(t, n);
49
+ }), h.set(e, n);
49
50
  }
50
51
  return n;
51
52
  }
52
- function _(t) {
53
- if (!t?.length) return;
54
- !f && !p && (p = !0, console.warn(`[box-kite] Box.configure({ sink: 'element' }) needs React 19 to hoist and dedupe its <style> elements; React ${e.version} will render them inline. Use the default sink instead.`));
55
- let n = h.get(t);
56
- return n || (n = t.map(g), h.set(t, n)), n;
53
+ function v(e) {
54
+ if (!e?.length) return;
55
+ !p && !m && (m = !0, console.warn(`[box-kite] Box.configure({ sink: 'element' }) needs React 19 to hoist and dedupe its <style> elements; React ${t.version} will render them inline. Use the default sink instead.`));
56
+ let n = g.get(e);
57
+ return n || (n = e.map(_), g.set(e, n)), n;
57
58
  }
58
59
  //#endregion
59
60
  //#region src/react/resolveStyles.ts
60
- function v(e, t, n) {
61
- let { classNames: r, signature: a, styleElements: o } = i().resolveClassNames(e, t, n);
61
+ function y(e, t, n) {
62
+ let { classNames: r, signature: i, styleElements: o } = a().resolveClassNames(e, t, n);
62
63
  return {
63
64
  classNames: r,
64
- signature: a,
65
- styleElements: _(o)
65
+ signature: i,
66
+ styleElements: v(o)
66
67
  };
67
68
  }
68
69
  //#endregion
69
70
  //#region src/react/svg/attributesInProps.ts
70
- var y = "__boxAttributesInProps";
71
- function b(e) {
72
- return e[y] = !0, e;
73
- }
71
+ var b = "__boxAttributesInProps";
74
72
  function x(e) {
75
- return typeof e == "function" || typeof e == "object" && e ? e[y] === !0 : !1;
73
+ return e[b] = !0, e;
74
+ }
75
+ function S(e) {
76
+ return typeof e == "function" || typeof e == "object" && e ? e[b] === !0 : !1;
76
77
  }
77
78
  //#endregion
78
79
  //#region src/react/svg/svgNaming.ts
79
- var S = [
80
+ var C = [
80
81
  "role",
81
82
  "aria-label",
82
83
  "aria-labelledby",
83
84
  "aria-hidden"
84
85
  ];
85
- function C(e, t) {
86
+ function w(e, t) {
86
87
  if (e !== void 0) return {
87
88
  role: "img",
88
89
  "aria-label": e
89
90
  };
90
- if (!(t && S.some((e) => e in t))) return { "aria-hidden": !0 };
91
+ if (!(t && C.some((e) => e in t))) return { "aria-hidden": !0 };
91
92
  }
92
93
  //#endregion
93
94
  //#region src/utils/string/stringUtils.ts
94
- var w;
95
+ var T;
95
96
  (function(e) {
96
97
  function t(e) {
97
98
  return e.charAt(0).toUpperCase() + e.slice(1);
98
99
  }
99
100
  e.capitalize = t;
100
- })(w ||= {});
101
- var T = w, E;
101
+ })(T ||= {});
102
+ var E = T, D;
102
103
  (function(e) {
103
104
  function t(e, t, n) {
104
105
  let r = { ...e }, i = r.props || {};
@@ -117,15 +118,15 @@ var T = w, E;
117
118
  return e in t;
118
119
  }
119
120
  e.isKeyOf = r;
120
- })(E ||= {});
121
- var D = E, O = [
121
+ })(D ||= {});
122
+ var O = D, k = [
122
123
  "sky-500",
123
124
  "emerald-500",
124
125
  "amber-500",
125
126
  "violet-500",
126
127
  "rose-500",
127
128
  "cyan-500"
128
- ], k = [
129
+ ], A = [
129
130
  "sky-400",
130
131
  "emerald-400",
131
132
  "amber-400",
@@ -133,8 +134,8 @@ var D = E, O = [
133
134
  "rose-400",
134
135
  "cyan-400"
135
136
  ];
136
- function A(e) {
137
+ function j(e) {
137
138
  return e.reduce((e, t, n) => (e[`chart-${n + 1}`] = t, e), {});
138
139
  }
139
140
  //#endregion
140
- export { T as a, b as c, d, s as f, D as i, v as l, O as n, C as o, a as p, A as r, x as s, k as t, _ as u };
141
+ export { E as a, x as c, f as d, c as f, O as i, y as l, k as n, w as o, o as p, j as r, S as s, A as t, v as u };
package/reporting.cjs ADDED
@@ -0,0 +1 @@
1
+ const e=require("./interactions.cjs"),t=require("./behavior.cjs");let n=require("react");var r=(0,n.createContext)(!1);function i({children:e}){return(0,n.createElement)(r.Provider,{value:!0},e)}function a({children:e}){return(0,n.createElement)(r.Provider,{value:!1},e)}function o(t){let i=(0,n.useContext)(r);return(0,n.useCallback)((n,r,a={})=>{if(i||!t)return;let{reason:o,event:s,content:c,...l}=a;e.t({component:t,type:n,reason:o,value:r,details:l,event:s,content:c})},[i,t])}function s(e,r,i){let a=t.o(e),s=o(r);return(0,n.useCallback)((e,t)=>{a.current?.(e,t),s(i,e,t)},[a,s,i])}function c(e){let{interaction:n,onChange:r,...i}=e,a=o(n?.component);return t.i({...i,onChange:(e,t)=>{r?.(e,t),n&&a(n.type,e,{...t,content:n.content})}})}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
package/reporting.mjs ADDED
@@ -0,0 +1,51 @@
1
+ import { t as e } from "./interactions.mjs";
2
+ import { i as t, o as n } from "./behavior.mjs";
3
+ import { createContext as r, createElement as i, useCallback as a, useContext as o } from "react";
4
+ //#region src/react/interactions/interactions.ts
5
+ var s = r(!1);
6
+ function c({ children: e }) {
7
+ return i(s.Provider, { value: !0 }, e);
8
+ }
9
+ function l({ children: e }) {
10
+ return i(s.Provider, { value: !1 }, e);
11
+ }
12
+ function u(t) {
13
+ let n = o(s);
14
+ return a((r, i, a = {}) => {
15
+ if (n || !t) return;
16
+ let { reason: o, event: s, content: c, ...l } = a;
17
+ e({
18
+ component: t,
19
+ type: r,
20
+ reason: o,
21
+ value: i,
22
+ details: l,
23
+ event: s,
24
+ content: c
25
+ });
26
+ }, [n, t]);
27
+ }
28
+ function d(e, t, r) {
29
+ let i = n(e), o = u(t);
30
+ return a((e, t) => {
31
+ i.current?.(e, t), o(r, e, t);
32
+ }, [
33
+ i,
34
+ o,
35
+ r
36
+ ]);
37
+ }
38
+ function f(e) {
39
+ let { interaction: n, onChange: r, ...i } = e, a = u(n?.component);
40
+ return t({
41
+ ...i,
42
+ onChange: (e, t) => {
43
+ r?.(e, t), n && a(n.type, e, {
44
+ ...t,
45
+ content: n.content
46
+ });
47
+ }
48
+ });
49
+ }
50
+ //#endregion
51
+ export { f as a, u as i, l as n, d as r, c as t };
package/scrolling.cjs CHANGED
@@ -1 +1 @@
1
- const e=require("./platform.cjs");function t(e,t,n=e.length){let r=0,i=n-1;if(i<=0)return 0;for(;r<i;){let n=r+i+1>>>1;e[n]<=t?r=n:i=n-1}return r}function n(t){let n=e.c(t),r=n?.ownerDocument?.defaultView;if(!n||!r)return null;let i=n.ownerDocument.scrollingElement??n.ownerDocument.documentElement;for(let e=n.parentElement;e&&e!==i&&e!==n.ownerDocument.body;e=e.parentElement)if(/auto|scroll|overlay/.test(r.getComputedStyle(e).overflowY)&&e.scrollHeight>e.clientHeight)return e;return null}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return n}});
1
+ const e=require("./platform.cjs");function t(e,t,n=e.length){let r=0,i=n-1;if(i<=0)return 0;for(;r<i;){let n=r+i+1>>>1;e[n]<=t?r=n:i=n-1}return r}function n(t){let n=e.u(t),r=n?.ownerDocument?.defaultView;if(!n||!r)return null;let i=n.ownerDocument.scrollingElement??n.ownerDocument.documentElement;for(let e=n.parentElement;e&&e!==i&&e!==n.ownerDocument.body;e=e.parentElement)if(/auto|scroll|overlay/.test(r.getComputedStyle(e).overflowY)&&e.scrollHeight>e.clientHeight)return e;return null}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return n}});
package/scrolling.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { c as e } from "./platform.mjs";
1
+ import { u as e } from "./platform.mjs";
2
2
  //#region src/utils/virtual/rowSearch.ts
3
3
  function t(e, t, n = e.length) {
4
4
  let r = 0, i = n - 1;
@@ -0,0 +1,30 @@
1
+ /** What the collector needs from its environment: Supabase injects the first two into every Edge Function. */
2
+ export interface CollectorEnv {
3
+ SUPABASE_URL: string;
4
+ /** The legacy `service_role` JWT or a new `sb_secret_…` key; `ANALYTICS_WRITE_KEY` overrides it. */
5
+ SUPABASE_SERVICE_ROLE_KEY: string;
6
+ /** Comma-separated origins allowed to post. */
7
+ ANALYTICS_ORIGINS?: string;
8
+ }
9
+ /** One `analytics_events` row. Anyone can post to a collector, so every field is checked and capped first. */
10
+ export interface EventRow {
11
+ id: string;
12
+ occurred_at: string;
13
+ name: string;
14
+ page: string;
15
+ session_id: string;
16
+ visitor_id: string | null;
17
+ reason: string | null;
18
+ label: string | null;
19
+ referrer: string | null;
20
+ country: string | null;
21
+ data: Record<string, unknown>;
22
+ }
23
+ export declare const DEFAULT_ORIGINS = "https://www.box-kite.dev,https://box-kite.dev";
24
+ /** A batch is 20 records; more than this in one request is not the site's beacon. */
25
+ export declare const MAX_EVENTS = 50;
26
+ export declare const MAX_BODY: number;
27
+ /** The `{ events }` body `beacon()` posts, as rows; a record with no id, name or session is dropped. */
28
+ export declare function toRows(body: unknown, country: string, now: number): EventRow[];
29
+ /** The collector `beacon()` posts the site's records to: each one becomes an `analytics_events` row. */
30
+ export declare function collect(request: Request, env: CollectorEnv, send?: typeof fetch): Promise<Response>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ import { InteractionEvent, InteractionJson } from '../interactions/interactionChannel';
2
+ /** One interaction as a collector stores it: flat, plain JSON, and nothing that only means something inside this tab. */
3
+ export interface AnalyticsEvent {
4
+ /** Unique per event, so a collector that is sent a batch twice keeps it once. */
5
+ id: string;
6
+ /** `component.type`: `tabs.valueChange`, `button.click`, `router.navigate`. */
7
+ name: string;
8
+ kind: InteractionEvent['kind'];
9
+ component: string;
10
+ type: string;
11
+ reason?: string;
12
+ value?: InteractionJson;
13
+ details?: {
14
+ [key: string]: InteractionJson;
15
+ };
16
+ source: 'user' | 'app';
17
+ /** The DOM event's type (`click`, `keydown`) rather than the event, which is a live object. */
18
+ trigger?: string;
19
+ /** The control's own words, as the page shows them: a button's, a link's, a tab's. */
20
+ label?: string;
21
+ /** ISO 8601. */
22
+ time: string;
23
+ url: string;
24
+ /** One visit: a new one after `sessionTimeout` with nothing happening, and with every new tab. */
25
+ sessionId: string;
26
+ /** One browser across visits, with `visitor: true` and consent. */
27
+ visitorId?: string;
28
+ }
29
+ /** Where a batch goes: `beacon(url)`, `consoleLog()`, or a function that hands it to a vendor's SDK. */
30
+ export type AnalyticsTransport = (events: AnalyticsEvent[]) => void;
31
+ /** `'pending'` holds what happens in memory and stores nothing; `'denied'` drops it and forgets both ids. */
32
+ export type AnalyticsConsent = 'granted' | 'pending' | 'denied';
33
+ export interface AnalyticsOptions {
34
+ send: AnalyticsTransport | AnalyticsTransport[];
35
+ /** Default `'granted'`. Start at `'pending'` where a reader in the EU has not answered a consent banner yet. */
36
+ consent?: AnalyticsConsent;
37
+ /** A `visitorId` kept in `localStorage`, written only once consent is granted. Default `false`. */
38
+ visitor?: boolean;
39
+ /** What people typed, pasted or picked as data, toast text and the URL's query and hash. Default `false`. */
40
+ content?: boolean;
41
+ /** Milliseconds with nothing happening before the next event starts a new session. Default 30 minutes. */
42
+ sessionTimeout?: number;
43
+ /** Sent once this many are waiting, or `wait` milliseconds after the first of them. Default 20 and 5000. */
44
+ batch?: {
45
+ size?: number;
46
+ wait?: number;
47
+ };
48
+ /** Return `false` to leave an interaction out; it is handed over as `Box.onInteraction` hears it, element and all. */
49
+ filter?: (event: InteractionEvent) => boolean;
50
+ /** What the ids are stored under. Default `'box-kite'`. */
51
+ storageKey?: string;
52
+ }
53
+ export interface Analytics {
54
+ /** What the reader answered: granting sends what was held, denying drops it and forgets both ids. */
55
+ consent(next: AnalyticsConsent): void;
56
+ /** Send whatever is waiting, now. */
57
+ flush(): void;
58
+ /** Stop listening, after sending whatever is waiting. */
59
+ stop(): void;
60
+ }
61
+ /**
62
+ * `Box.onInteraction`, collected: every interaction as a flat JSON record with a session id, batched, held until consent is
63
+ * granted, and sent as the page is hidden. Framework-free, and inert on a server.
64
+ */
65
+ export declare function createAnalytics(options: AnalyticsOptions): Analytics;
66
+ /**
67
+ * A batch posted to `url` as `{ "events": [...] }`, with `sendBeacon` so it survives the page closing. The body is JSON
68
+ * sent as `text/plain`, which keeps it a simple request with no preflight, so the collector reads the body as JSON whatever the type.
69
+ */
70
+ export declare function beacon(url: string): AnalyticsTransport;
71
+ /** Every record to the console, one line each: what a developer reads while building. */
72
+ export declare function consoleLog(prefix?: string): AnalyticsTransport;
@@ -0,0 +1,13 @@
1
+ /** The two ids an analytics record carries: one visit, and (only when asked for and consented to) one browser across visits. */
2
+ export declare const DEFAULT_SESSION_TIMEOUT: number;
3
+ /** A random id: `crypto.randomUUID` where the page is secure, the same 122 random bits by hand where it is not. */
4
+ export declare function randomId(): string;
5
+ export interface Identity {
6
+ /** The visit `time` belongs to: a new one after `timeout` with nothing happening, and with every new tab. */
7
+ sessionAt(time: number): string;
8
+ /** The browser, across visits; the caller asks only once consent is granted. */
9
+ visitor(): string;
10
+ /** Consent withdrawn: both ids are forgotten, here and in storage. */
11
+ forget(): void;
12
+ }
13
+ export declare function createIdentity(prefix: string, timeout: number): Identity;
@@ -0,0 +1,6 @@
1
+ /** Whether a Box with a `component` writes `data-bk="<key>"` — what lets the channel name a click. */
2
+ export declare const marksComponents: () => boolean;
3
+ /** Whether the channel may say, in development, that it cannot name a click: `Box.configure({ warnings })`. */
4
+ export declare const warnsWithoutAttribute: () => boolean;
5
+ export declare function setComponentAttribute(enabled: boolean): void;
6
+ export declare function setAttributeWarnings(enabled: boolean): void;
@@ -0,0 +1,35 @@
1
+ import { InteractionEvent, InteractionListener, InteractionOptions, InteractionReport } from './interactionTypes';
2
+ export type { ComponentInteraction, ComponentInteractions, CustomInteraction, DomInteraction, InteractionComponent, InteractionEvent, InteractionJson, InteractionListener, InteractionOptions, InteractionReport, InteractionSource, InteractionType, } from './interactionTypes';
3
+ /** What happened, as it stood when it happened; everything else is worked out on delivery. */
4
+ export interface Entry {
5
+ kind: InteractionEvent['kind'];
6
+ input: InteractionReport;
7
+ event?: Event;
8
+ /** The element a React handler ran on, read now: `currentTarget` is gone once dispatch ends. */
9
+ handler?: unknown;
10
+ timeStamp: number;
11
+ time: number;
12
+ url: string;
13
+ }
14
+ export interface Channel {
15
+ listeners: Map<InteractionListener, InteractionOptions>;
16
+ queue: Entry[];
17
+ /** The event the browser is dispatching, so a change made inside a handler names it without being told. */
18
+ dispatching?: Event;
19
+ /** Both set by the delivery half when it loads; until then, what happens waits in the queue. */
20
+ schedule?: () => void;
21
+ flush?: () => void;
22
+ loading?: boolean;
23
+ warned?: boolean;
24
+ }
25
+ /**
26
+ * Hear every interaction from here on, until the returned function is called. Delivery is fire and forget: events arrive in order,
27
+ * batched, in a background task after the handler that caused them, and a listener that throws is reported rather than rethrown.
28
+ */
29
+ export declare function subscribeInteractions(listener: InteractionListener, options?: InteractionOptions): () => void;
30
+ /** Deliver whatever is queued, now: what an analytics sender calls on `pagehide` before it sends its batch. */
31
+ export declare const flushInteractions: () => void;
32
+ /** What a component reports, beside the callback it fires for the same change. */
33
+ export declare const emitInteraction: (input: InteractionReport) => void;
34
+ /** A moment of the app's own (a page view, a hover, a wizard step) to the same listeners, fire and forget. */
35
+ export declare const reportInteraction: (input: InteractionReport) => void;
@@ -0,0 +1,6 @@
1
+ import { InteractionJson } from './interactionTypes';
2
+ /**
3
+ * A value as plain JSON, or `undefined` for what has none: a function, a React element, a DOM node, a class instance.
4
+ * A `Date` is its ISO string, a `Set` an array and a `Map` a record; an object met a second time is left out, which cuts a cycle.
5
+ */
6
+ export declare function toInteractionJson(value: unknown): InteractionJson | undefined;
@@ -0,0 +1,6 @@
1
+ import { Channel } from './interactionChannel';
2
+ /**
3
+ * The half of the channel fetched with the first subscription: delivery, which event is being dispatched (so a change made
4
+ * inside a handler names it unasked), and a press on anything a component styled.
5
+ */
6
+ export default function deliver(channel: Channel): void;