@hanzo/ui 8.0.20 → 8.0.22

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 (31) hide show
  1. package/dist/ThemeToggleNext-AEDLHX5X.js +5 -0
  2. package/dist/{ThemeToggleNext-OMBC67MO.js.map → ThemeToggleNext-AEDLHX5X.js.map} +1 -1
  3. package/dist/ThemeToggleNext-N6ASYJ6J.cjs +20 -0
  4. package/dist/{ThemeToggleNext-LI3SBFW7.cjs.map → ThemeToggleNext-N6ASYJ6J.cjs.map} +1 -1
  5. package/dist/{chunk-T3UAC7ZZ.js → chunk-77AMCLN4.js} +4 -4
  6. package/dist/{chunk-T3UAC7ZZ.js.map → chunk-77AMCLN4.js.map} +1 -1
  7. package/dist/{chunk-57YEM34R.cjs → chunk-7XDEUEWI.cjs} +11 -2
  8. package/dist/chunk-7XDEUEWI.cjs.map +1 -0
  9. package/dist/{chunk-J3P63OX6.cjs → chunk-ARV3P4CE.cjs} +5 -5
  10. package/dist/{chunk-J3P63OX6.cjs.map → chunk-ARV3P4CE.cjs.map} +1 -1
  11. package/dist/{chunk-P6IHE2O3.js → chunk-FVQXROBK.js} +11 -3
  12. package/dist/chunk-FVQXROBK.js.map +1 -0
  13. package/dist/{chunk-XULZJEW2.cjs → chunk-NBZDIMP3.cjs} +21 -17
  14. package/dist/chunk-NBZDIMP3.cjs.map +1 -0
  15. package/dist/{chunk-3YH7AUKQ.js → chunk-P2P6ST6J.js} +14 -10
  16. package/dist/chunk-P2P6ST6J.js.map +1 -0
  17. package/dist/product/PrimaryButton.d.ts +1 -1
  18. package/dist/product/index.cjs +70 -66
  19. package/dist/product/index.cjs.map +1 -1
  20. package/dist/product/index.js +7 -7
  21. package/dist/product/index.js.map +1 -1
  22. package/dist/product/instrument.d.ts +6 -0
  23. package/dist/product/social/index.cjs +16 -16
  24. package/dist/product/social/index.js +2 -2
  25. package/package.json +3 -3
  26. package/dist/ThemeToggleNext-LI3SBFW7.cjs +0 -20
  27. package/dist/ThemeToggleNext-OMBC67MO.js +0 -5
  28. package/dist/chunk-3YH7AUKQ.js.map +0 -1
  29. package/dist/chunk-57YEM34R.cjs.map +0 -1
  30. package/dist/chunk-P6IHE2O3.js.map +0 -1
  31. package/dist/chunk-XULZJEW2.cjs.map +0 -1
@@ -0,0 +1,5 @@
1
+ 'use client';
2
+ export { ThemeToggleNext, ThemeToggleNext_default as default } from './chunk-77AMCLN4.js';
3
+ import './chunk-FVQXROBK.js';
4
+ //# sourceMappingURL=ThemeToggleNext-AEDLHX5X.js.map
5
+ //# sourceMappingURL=ThemeToggleNext-AEDLHX5X.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"ThemeToggleNext-OMBC67MO.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"ThemeToggleNext-AEDLHX5X.js"}
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var chunkARV3P4CE_cjs = require('./chunk-ARV3P4CE.cjs');
7
+ require('./chunk-7XDEUEWI.cjs');
8
+
9
+
10
+
11
+ Object.defineProperty(exports, "ThemeToggleNext", {
12
+ enumerable: true,
13
+ get: function () { return chunkARV3P4CE_cjs.ThemeToggleNext; }
14
+ });
15
+ Object.defineProperty(exports, "default", {
16
+ enumerable: true,
17
+ get: function () { return chunkARV3P4CE_cjs.ThemeToggleNext_default; }
18
+ });
19
+ //# sourceMappingURL=ThemeToggleNext-N6ASYJ6J.cjs.map
20
+ //# sourceMappingURL=ThemeToggleNext-N6ASYJ6J.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"ThemeToggleNext-LI3SBFW7.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"ThemeToggleNext-N6ASYJ6J.cjs"}
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { useEmit } from './chunk-P6IHE2O3.js';
2
+ import { useEmit } from './chunk-FVQXROBK.js';
3
3
  import { useThemeSetting } from '@hanzogui/next-theme';
4
4
  import { lazy, useState, Suspense, Component } from 'react';
5
5
  import { Button } from '@hanzo/gui';
@@ -64,7 +64,7 @@ function AgnosticThemeToggle({
64
64
  }
65
65
  );
66
66
  }
67
- var NextThemeToggle = lazy(() => import('./ThemeToggleNext-OMBC67MO.js'));
67
+ var NextThemeToggle = lazy(() => import('./ThemeToggleNext-AEDLHX5X.js'));
68
68
  var NextThemeBoundary = class extends Component {
69
69
  state = { failed: false };
70
70
  static getDerivedStateFromError() {
@@ -96,5 +96,5 @@ function ThemeToggleNext({ size, label }) {
96
96
  var ThemeToggleNext_default = ThemeToggleNext;
97
97
 
98
98
  export { AgnosticThemeToggle, ThemeToggle, ThemeToggleNext, ThemeToggleNext_default };
99
- //# sourceMappingURL=chunk-T3UAC7ZZ.js.map
100
- //# sourceMappingURL=chunk-T3UAC7ZZ.js.map
99
+ //# sourceMappingURL=chunk-77AMCLN4.js.map
100
+ //# sourceMappingURL=chunk-77AMCLN4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/product/ThemeToggle.tsx","../src/product/ThemeToggleNext.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-T3UAC7ZZ.js","sourcesContent":["'use client'\n\n/**\n * ThemeToggle — flips between dark and light. Framework-agnostic by default so\n * Vite / Tauri / Express hosts can use it with NO Next dependency:\n *\n * • Controlled: <ThemeToggle theme={theme} onToggle={setTheme} /> (host owns theme)\n * • Uncontrolled (agnostic): <ThemeToggle onThemeChange={fn} /> (toggles the DOM\n * `.dark` class + persists to localStorage)\n * • Uncontrolled (no props): <ThemeToggle /> (console/Next —\n * falls back to the OPTIONAL @hanzogui/next-theme path;\n * if it cannot load, degrades to the agnostic DOM toggle)\n *\n * Shows the action's target icon (a sun in dark mode, a moon in light mode).\n */\nimport type { ReactNode } from 'react'\nimport { Component, Suspense, lazy, useState } from 'react'\nimport { Button } from '@hanzo/gui'\nimport { Moon, Sun } from '@hanzogui/lucide-icons-2'\n\nimport { useEmit } from './instrument'\n\nexport type ThemeMode = 'light' | 'dark'\n\nexport type ThemeToggleProps = {\n /** Controlled theme. Pair with `onToggle`/`onThemeChange` to fully control it. */\n theme?: ThemeMode\n /** Seed for uncontrolled mode (default: read from the DOM `.dark` class, else 'dark'). */\n defaultTheme?: ThemeMode\n /** Called with the next theme on toggle (alias of `onThemeChange`). */\n onToggle?: (next: ThemeMode) => void\n /** Called with the next theme on toggle. */\n onThemeChange?: (next: ThemeMode) => void\n /** @hanzo/gui Button size token (default \"$2\"). */\n size?: string\n /** aria-label override. */\n label?: string\n}\n\nconst STORAGE_KEY = 'theme'\n\nfunction readDomTheme(): ThemeMode | undefined {\n if (typeof document === 'undefined') return undefined\n const el = document.documentElement\n if (el.classList.contains('dark')) return 'dark'\n if (el.classList.contains('light')) return 'light'\n try {\n const ls = window.localStorage.getItem(STORAGE_KEY)\n if (ls === 'light' || ls === 'dark') return ls\n } catch {\n /* localStorage may be unavailable */\n }\n return undefined\n}\n\nfunction applyDomTheme(next: ThemeMode): void {\n if (typeof document === 'undefined') return\n const el = document.documentElement\n el.classList.toggle('dark', next === 'dark')\n el.classList.toggle('light', next === 'light')\n el.style.colorScheme = next\n try {\n window.localStorage.setItem(STORAGE_KEY, next)\n } catch {\n /* ignore */\n }\n}\n\n/**\n * The framework-agnostic toggle button. Controlled when `theme` is provided; otherwise\n * self-managed via the DOM `.dark` class. No framework dependency — safe on any host.\n */\nexport function AgnosticThemeToggle({\n theme,\n defaultTheme,\n onToggle,\n onThemeChange,\n size = '$2',\n label,\n}: ThemeToggleProps) {\n const controlled = theme !== undefined\n const [internal, setInternal] = useState<ThemeMode>(() => theme ?? defaultTheme ?? readDomTheme() ?? 'dark')\n const current: ThemeMode = controlled ? (theme as ThemeMode) : internal\n const isDark = current === 'dark'\n const track = useEmit()\n\n const toggle = () => {\n const next: ThemeMode = isDark ? 'light' : 'dark'\n track({ component: 'ThemeToggle', action: 'change', value: next })\n if (!controlled) {\n setInternal(next)\n applyDomTheme(next)\n }\n onToggle?.(next)\n onThemeChange?.(next)\n }\n\n return (\n <Button\n size={size as never}\n chromeless\n icon={isDark ? <Sun size={16} /> : <Moon size={16} />}\n onPress={toggle}\n aria-label={label ?? (isDark ? 'Switch to light theme' : 'Switch to dark theme')}\n />\n )\n}\n\n// @hanzogui/next-theme is an OPTIONAL dependency — loaded only on the uncontrolled,\n// no-props path (console/Next). Lazily code-split so non-Next hosts never need it at\n// runtime; if it fails to load, the boundary below degrades to the agnostic toggle.\nconst NextThemeToggle = lazy(() => import('./ThemeToggleNext'))\n\nclass NextThemeBoundary extends Component<{ fallback: ReactNode; children: ReactNode }, { failed: boolean }> {\n state = { failed: false }\n static getDerivedStateFromError() {\n return { failed: true }\n }\n render() {\n return this.state.failed ? this.props.fallback : this.props.children\n }\n}\n\nexport function ThemeToggle(props: ThemeToggleProps) {\n const injected =\n props.theme !== undefined || props.onToggle !== undefined || props.onThemeChange !== undefined\n if (injected) return <AgnosticThemeToggle {...props} />\n\n // No props → keep the existing console/Next behaviour via the optional next-theme\n // path, degrading to the agnostic DOM toggle if it is not installed.\n const fallback = <AgnosticThemeToggle {...props} />\n return (\n <NextThemeBoundary fallback={fallback}>\n <Suspense fallback={fallback}>\n <NextThemeToggle size={props.size} label={props.label} />\n </Suspense>\n </NextThemeBoundary>\n )\n}\n","'use client'\n\n/**\n * ThemeToggleNext — the @hanzogui/next-theme binding (console / Next). This is the ONLY\n * module that imports @hanzogui/next-theme, so it stays an OPTIONAL dependency: the base\n * ThemeToggle lazy-loads it (default export) and non-Next hosts never pull it in unless\n * they import this component directly. UI is delegated to the framework-agnostic button\n * in controlled mode, so every toggle looks identical.\n */\nimport { useThemeSetting } from '@hanzogui/next-theme'\nimport { AgnosticThemeToggle, type ThemeToggleProps } from './ThemeToggle'\n\nfunction ThemeToggleNext({ size, label }: Pick<ThemeToggleProps, 'size' | 'label'>) {\n const { current, resolvedTheme, set } = useThemeSetting()\n const isDark = (resolvedTheme ?? current ?? 'dark') !== 'light'\n return (\n <AgnosticThemeToggle\n theme={isDark ? 'dark' : 'light'}\n onToggle={(next) => set(next)}\n size={size}\n label={label}\n />\n )\n}\n\nexport default ThemeToggleNext\nexport { ThemeToggleNext }\n"]}
1
+ {"version":3,"sources":["../src/product/ThemeToggle.tsx","../src/product/ThemeToggleNext.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-77AMCLN4.js","sourcesContent":["'use client'\n\n/**\n * ThemeToggle — flips between dark and light. Framework-agnostic by default so\n * Vite / Tauri / Express hosts can use it with NO Next dependency:\n *\n * • Controlled: <ThemeToggle theme={theme} onToggle={setTheme} /> (host owns theme)\n * • Uncontrolled (agnostic): <ThemeToggle onThemeChange={fn} /> (toggles the DOM\n * `.dark` class + persists to localStorage)\n * • Uncontrolled (no props): <ThemeToggle /> (console/Next —\n * falls back to the OPTIONAL @hanzogui/next-theme path;\n * if it cannot load, degrades to the agnostic DOM toggle)\n *\n * Shows the action's target icon (a sun in dark mode, a moon in light mode).\n */\nimport type { ReactNode } from 'react'\nimport { Component, Suspense, lazy, useState } from 'react'\nimport { Button } from '@hanzo/gui'\nimport { Moon, Sun } from '@hanzogui/lucide-icons-2'\n\nimport { useEmit } from './instrument'\n\nexport type ThemeMode = 'light' | 'dark'\n\nexport type ThemeToggleProps = {\n /** Controlled theme. Pair with `onToggle`/`onThemeChange` to fully control it. */\n theme?: ThemeMode\n /** Seed for uncontrolled mode (default: read from the DOM `.dark` class, else 'dark'). */\n defaultTheme?: ThemeMode\n /** Called with the next theme on toggle (alias of `onThemeChange`). */\n onToggle?: (next: ThemeMode) => void\n /** Called with the next theme on toggle. */\n onThemeChange?: (next: ThemeMode) => void\n /** @hanzo/gui Button size token (default \"$2\"). */\n size?: string\n /** aria-label override. */\n label?: string\n}\n\nconst STORAGE_KEY = 'theme'\n\nfunction readDomTheme(): ThemeMode | undefined {\n if (typeof document === 'undefined') return undefined\n const el = document.documentElement\n if (el.classList.contains('dark')) return 'dark'\n if (el.classList.contains('light')) return 'light'\n try {\n const ls = window.localStorage.getItem(STORAGE_KEY)\n if (ls === 'light' || ls === 'dark') return ls\n } catch {\n /* localStorage may be unavailable */\n }\n return undefined\n}\n\nfunction applyDomTheme(next: ThemeMode): void {\n if (typeof document === 'undefined') return\n const el = document.documentElement\n el.classList.toggle('dark', next === 'dark')\n el.classList.toggle('light', next === 'light')\n el.style.colorScheme = next\n try {\n window.localStorage.setItem(STORAGE_KEY, next)\n } catch {\n /* ignore */\n }\n}\n\n/**\n * The framework-agnostic toggle button. Controlled when `theme` is provided; otherwise\n * self-managed via the DOM `.dark` class. No framework dependency — safe on any host.\n */\nexport function AgnosticThemeToggle({\n theme,\n defaultTheme,\n onToggle,\n onThemeChange,\n size = '$2',\n label,\n}: ThemeToggleProps) {\n const controlled = theme !== undefined\n const [internal, setInternal] = useState<ThemeMode>(() => theme ?? defaultTheme ?? readDomTheme() ?? 'dark')\n const current: ThemeMode = controlled ? (theme as ThemeMode) : internal\n const isDark = current === 'dark'\n const track = useEmit()\n\n const toggle = () => {\n const next: ThemeMode = isDark ? 'light' : 'dark'\n track({ component: 'ThemeToggle', action: 'change', value: next })\n if (!controlled) {\n setInternal(next)\n applyDomTheme(next)\n }\n onToggle?.(next)\n onThemeChange?.(next)\n }\n\n return (\n <Button\n size={size as never}\n chromeless\n icon={isDark ? <Sun size={16} /> : <Moon size={16} />}\n onPress={toggle}\n aria-label={label ?? (isDark ? 'Switch to light theme' : 'Switch to dark theme')}\n />\n )\n}\n\n// @hanzogui/next-theme is an OPTIONAL dependency — loaded only on the uncontrolled,\n// no-props path (console/Next). Lazily code-split so non-Next hosts never need it at\n// runtime; if it fails to load, the boundary below degrades to the agnostic toggle.\nconst NextThemeToggle = lazy(() => import('./ThemeToggleNext'))\n\nclass NextThemeBoundary extends Component<{ fallback: ReactNode; children: ReactNode }, { failed: boolean }> {\n state = { failed: false }\n static getDerivedStateFromError() {\n return { failed: true }\n }\n render() {\n return this.state.failed ? this.props.fallback : this.props.children\n }\n}\n\nexport function ThemeToggle(props: ThemeToggleProps) {\n const injected =\n props.theme !== undefined || props.onToggle !== undefined || props.onThemeChange !== undefined\n if (injected) return <AgnosticThemeToggle {...props} />\n\n // No props → keep the existing console/Next behaviour via the optional next-theme\n // path, degrading to the agnostic DOM toggle if it is not installed.\n const fallback = <AgnosticThemeToggle {...props} />\n return (\n <NextThemeBoundary fallback={fallback}>\n <Suspense fallback={fallback}>\n <NextThemeToggle size={props.size} label={props.label} />\n </Suspense>\n </NextThemeBoundary>\n )\n}\n","'use client'\n\n/**\n * ThemeToggleNext — the @hanzogui/next-theme binding (console / Next). This is the ONLY\n * module that imports @hanzogui/next-theme, so it stays an OPTIONAL dependency: the base\n * ThemeToggle lazy-loads it (default export) and non-Next hosts never pull it in unless\n * they import this component directly. UI is delegated to the framework-agnostic button\n * in controlled mode, so every toggle looks identical.\n */\nimport { useThemeSetting } from '@hanzogui/next-theme'\nimport { AgnosticThemeToggle, type ThemeToggleProps } from './ThemeToggle'\n\nfunction ThemeToggleNext({ size, label }: Pick<ThemeToggleProps, 'size' | 'label'>) {\n const { current, resolvedTheme, set } = useThemeSetting()\n const isDark = (resolvedTheme ?? current ?? 'dark') !== 'light'\n return (\n <AgnosticThemeToggle\n theme={isDark ? 'dark' : 'light'}\n onToggle={(next) => set(next)}\n size={size}\n label={label}\n />\n )\n}\n\nexport default ThemeToggleNext\nexport { ThemeToggleNext }\n"]}
@@ -24,12 +24,21 @@ function useEmit() {
24
24
  [surface]
25
25
  );
26
26
  }
27
+ function labelOf(children) {
28
+ if (typeof children === "string") return children.trim() || void 0;
29
+ if (Array.isArray(children)) {
30
+ const text = children.filter((c) => typeof c === "string" || typeof c === "number").join("");
31
+ return text.trim() || void 0;
32
+ }
33
+ return void 0;
34
+ }
27
35
  var textSize = (s) => s ? s.length : 0;
28
36
 
29
37
  exports.InstrumentSurface = InstrumentSurface;
30
38
  exports.emit = emit;
39
+ exports.labelOf = labelOf;
31
40
  exports.textSize = textSize;
32
41
  exports.useEmit = useEmit;
33
42
  exports.useSurface = useSurface;
34
- //# sourceMappingURL=chunk-57YEM34R.cjs.map
35
- //# sourceMappingURL=chunk-57YEM34R.cjs.map
43
+ //# sourceMappingURL=chunk-7XDEUEWI.cjs.map
44
+ //# sourceMappingURL=chunk-7XDEUEWI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/product/instrument.ts"],"names":["createContext","useContext","track","EVENTS","useCallback"],"mappings":";;;;;;AAkEA,IAAM,cAAA,GAAiBA,oBAAkC,MAAS,CAAA;AAI3D,IAAM,oBAAoB,cAAA,CAAe;AAGzC,IAAM,UAAA,GAAa,MAA0BC,gBAAA,CAAW,cAAc;AAItE,SAAS,KAAK,CAAA,EAAkB;AACrC,EAAAC,eAAA,CAAMC,iBAAO,YAAA,EAAc;AAAA,IACzB,WAAW,CAAA,CAAE,SAAA;AAAA,IACb,QAAQ,CAAA,CAAE,MAAA;AAAA,IACV,GAAI,EAAE,EAAA,KAAO,MAAA,GAAY,EAAE,EAAA,EAAI,CAAA,CAAE,IAAG,GAAI,IAAA;AAAA,IACxC,GAAI,EAAE,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,CAAA,CAAE,OAAM,GAAI,IAAA;AAAA,IACjD,GAAI,EAAE,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,CAAA,CAAE,SAAQ,GAAI;AAAA,GACxD,CAAA;AACH;AAIO,SAAS,OAAA,GAAgC;AAC9C,EAAA,MAAM,UAAU,UAAA,EAAW;AAC3B,EAAA,OAAOC,iBAAA;AAAA,IACL,CAAC,CAAA,KAAe,IAAA,CAAK,OAAA,KAAY,MAAA,IAAa,CAAA,CAAE,OAAA,KAAY,MAAA,GAAY,EAAE,GAAG,CAAA,EAAG,OAAA,KAAY,CAAC,CAAA;AAAA,IAC7F,CAAC,OAAO;AAAA,GACV;AACF;AAOO,SAAS,QAAQ,QAAA,EAAuC;AAC7D,EAAA,IAAI,OAAO,QAAA,KAAa,QAAA,EAAU,OAAO,QAAA,CAAS,MAAK,IAAK,MAAA;AAC5D,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,CAAA,KAAM,QAAQ,CAAA,CAAE,KAAK,EAAE,CAAA;AAC3F,IAAA,OAAO,IAAA,CAAK,MAAK,IAAK,MAAA;AAAA,EACxB;AACA,EAAA,OAAO,MAAA;AACT;AAKO,IAAM,QAAA,GAAW,CAAC,CAAA,KAAmC,CAAA,GAAI,EAAE,MAAA,GAAS","file":"chunk-7XDEUEWI.cjs","sourcesContent":["// The ONE place a shared component says what a user just did.\n//\n// Instrumenting the COMPONENT beats instrumenting 100 apps: a product that\n// renders `DataTable`, `PrimaryButton`, `SlideOver`, `ConfirmDelete`, `Field*`,\n// `ComboBox`, `Segmented`, `SearchInput`, `OrgSwitcher`, `MenuItemView`,\n// `EmptyState` or `ThemeToggle` reports the SAME interaction vocabulary with\n// zero app code. Nothing to wire, nothing to remember, nothing to drift.\n//\n// import { emit, useEmit, InstrumentSurface } from '@hanzo/ui'\n// <InstrumentSurface name=\"billing\">…</InstrumentSurface> // optional context\n//\n// ONE event name, structured properties — the taxonomy in @hanzo/event is a\n// CLOSED set, and its own rule for a product-specific moment is \"the `action`\n// property, never a new event name\". So every UI interaction is\n// EVENTS.FEATURE_USED carrying { component, action, surface, id, value }.\n// Funnel moments (signup, checkout, deploy) keep their own dedicated names and\n// are emitted by the surface that owns them, not by a button.\n//\n// One stream: `track` from @hanzogui/telemetry — already a dependency of this\n// package and already THE front door (POST api.hanzo.ai/v1/event). No second\n// client, no CDN script, no `window` poking. It is SSR-safe, consent-aware,\n// honors DNT/GPC, and is fail-soft by construction, so this module inherits all\n// of that and adds no error policy of its own.\n\nimport { createContext, useCallback, useContext } from 'react'\n// ONE dependency edge: @hanzogui/telemetry owns the transport AND re-exports the\n// @hanzo/event vocabulary, so this package never names a second source of truth.\nimport { EVENTS, track } from '@hanzogui/telemetry'\n\n/** What a user did to a component. A closed set — it is the verb half of the\n * vocabulary, and a closed verb set is what makes cross-product funnels join. */\nexport type UiAction =\n | 'click'\n | 'open'\n | 'close'\n | 'select'\n | 'change'\n | 'sort'\n | 'filter'\n | 'search'\n | 'confirm'\n | 'cancel'\n | 'dismiss'\n | 'expand'\n | 'view'\n | 'error'\n\n/** One interaction. `component` + `action` are required; everything else is the\n * detail a lens groups by. Values are scrubbed downstream by @hanzo/event. */\nexport interface UiEvent {\n /** The shared component that observed it — `DataTable`, `PrimaryButton`, … */\n component: string\n action: UiAction\n /** The thing acted on: a column key, an option value, a menu item id. */\n id?: string\n /** A small scalar detail (sort direction, boolean state, count). Never PII —\n * free-text values (search terms, field contents) are reported as a LENGTH,\n * by the caller, not as the text. */\n value?: string | number | boolean\n /** The product area, when the app declared one via `<InstrumentSurface/>`. */\n surface?: string\n}\n\n/** The enclosing product area (route/module). Optional: with no provider the\n * events still carry component+action, and the product+path already come from\n * the telemetry client. */\nconst SurfaceContext = createContext<string | undefined>(undefined)\n\n/** Names the product area every shared component inside it reports under.\n * Plain provider, no element — it must not perturb any layout. */\nexport const InstrumentSurface = SurfaceContext.Provider\n\n/** The current product area, or undefined outside a provider. */\nexport const useSurface = (): string | undefined => useContext(SurfaceContext)\n\n/** Report an interaction. Callable from anywhere (module scope, event handler,\n * a non-React host) — the ambient telemetry client is built on first use. */\nexport function emit(e: UiEvent): void {\n track(EVENTS.FEATURE_USED, {\n component: e.component,\n action: e.action,\n ...(e.id !== undefined ? { id: e.id } : null),\n ...(e.value !== undefined ? { value: e.value } : null),\n ...(e.surface !== undefined ? { surface: e.surface } : null),\n })\n}\n\n/** `emit` with the surrounding `<InstrumentSurface/>` already bound — what the\n * shared components themselves use, so an app never labels a surface twice. */\nexport function useEmit(): (e: UiEvent) => void {\n const surface = useSurface()\n return useCallback(\n (e: UiEvent) => emit(surface !== undefined && e.surface === undefined ? { ...e, surface } : e),\n [surface],\n )\n}\n\n/** A component's own children ARE its identity — \"Deploy\", \"Log in with Hanzo\n * Cloud\". React hands them over as a string, or as an ARRAY when the label is\n * interpolated (`Log in with {brand}`), which is the common case; flattening the\n * string parts is the difference between a named event and an anonymous one.\n * Anything non-textual (an icon element) yields undefined rather than a guess. */\nexport function labelOf(children: unknown): string | undefined {\n if (typeof children === 'string') return children.trim() || undefined\n if (Array.isArray(children)) {\n const text = children.filter((c) => typeof c === 'string' || typeof c === 'number').join('')\n return text.trim() || undefined\n }\n return undefined\n}\n\n/** Free text (a search box, a text field) is reported as its LENGTH — the shape\n * of the behaviour without the content. One helper so no component invents its\n * own idea of \"safe to send\". */\nexport const textSize = (s: string | undefined): number => (s ? s.length : 0)\n"]}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunk57YEM34R_cjs = require('./chunk-57YEM34R.cjs');
4
+ var chunk7XDEUEWI_cjs = require('./chunk-7XDEUEWI.cjs');
5
5
  var nextTheme = require('@hanzogui/next-theme');
6
6
  var react = require('react');
7
7
  var gui = require('@hanzo/gui');
@@ -44,7 +44,7 @@ function AgnosticThemeToggle({
44
44
  const [internal, setInternal] = react.useState(() => theme ?? defaultTheme ?? readDomTheme() ?? "dark");
45
45
  const current = controlled ? theme : internal;
46
46
  const isDark = current === "dark";
47
- const track = chunk57YEM34R_cjs.useEmit();
47
+ const track = chunk7XDEUEWI_cjs.useEmit();
48
48
  const toggle = () => {
49
49
  const next = isDark ? "light" : "dark";
50
50
  track({ component: "ThemeToggle", action: "change", value: next });
@@ -66,7 +66,7 @@ function AgnosticThemeToggle({
66
66
  }
67
67
  );
68
68
  }
69
- var NextThemeToggle = react.lazy(() => import('./ThemeToggleNext-LI3SBFW7.cjs'));
69
+ var NextThemeToggle = react.lazy(() => import('./ThemeToggleNext-N6ASYJ6J.cjs'));
70
70
  var NextThemeBoundary = class extends react.Component {
71
71
  state = { failed: false };
72
72
  static getDerivedStateFromError() {
@@ -101,5 +101,5 @@ exports.AgnosticThemeToggle = AgnosticThemeToggle;
101
101
  exports.ThemeToggle = ThemeToggle;
102
102
  exports.ThemeToggleNext = ThemeToggleNext;
103
103
  exports.ThemeToggleNext_default = ThemeToggleNext_default;
104
- //# sourceMappingURL=chunk-J3P63OX6.cjs.map
105
- //# sourceMappingURL=chunk-J3P63OX6.cjs.map
104
+ //# sourceMappingURL=chunk-ARV3P4CE.cjs.map
105
+ //# sourceMappingURL=chunk-ARV3P4CE.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/product/ThemeToggle.tsx","../src/product/ThemeToggleNext.tsx"],"names":["useState","useEmit","jsx","Button","Sun","Moon","lazy","Component","Suspense","useThemeSetting"],"mappings":"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","file":"chunk-J3P63OX6.cjs","sourcesContent":["'use client'\n\n/**\n * ThemeToggle — flips between dark and light. Framework-agnostic by default so\n * Vite / Tauri / Express hosts can use it with NO Next dependency:\n *\n * • Controlled: <ThemeToggle theme={theme} onToggle={setTheme} /> (host owns theme)\n * • Uncontrolled (agnostic): <ThemeToggle onThemeChange={fn} /> (toggles the DOM\n * `.dark` class + persists to localStorage)\n * • Uncontrolled (no props): <ThemeToggle /> (console/Next —\n * falls back to the OPTIONAL @hanzogui/next-theme path;\n * if it cannot load, degrades to the agnostic DOM toggle)\n *\n * Shows the action's target icon (a sun in dark mode, a moon in light mode).\n */\nimport type { ReactNode } from 'react'\nimport { Component, Suspense, lazy, useState } from 'react'\nimport { Button } from '@hanzo/gui'\nimport { Moon, Sun } from '@hanzogui/lucide-icons-2'\n\nimport { useEmit } from './instrument'\n\nexport type ThemeMode = 'light' | 'dark'\n\nexport type ThemeToggleProps = {\n /** Controlled theme. Pair with `onToggle`/`onThemeChange` to fully control it. */\n theme?: ThemeMode\n /** Seed for uncontrolled mode (default: read from the DOM `.dark` class, else 'dark'). */\n defaultTheme?: ThemeMode\n /** Called with the next theme on toggle (alias of `onThemeChange`). */\n onToggle?: (next: ThemeMode) => void\n /** Called with the next theme on toggle. */\n onThemeChange?: (next: ThemeMode) => void\n /** @hanzo/gui Button size token (default \"$2\"). */\n size?: string\n /** aria-label override. */\n label?: string\n}\n\nconst STORAGE_KEY = 'theme'\n\nfunction readDomTheme(): ThemeMode | undefined {\n if (typeof document === 'undefined') return undefined\n const el = document.documentElement\n if (el.classList.contains('dark')) return 'dark'\n if (el.classList.contains('light')) return 'light'\n try {\n const ls = window.localStorage.getItem(STORAGE_KEY)\n if (ls === 'light' || ls === 'dark') return ls\n } catch {\n /* localStorage may be unavailable */\n }\n return undefined\n}\n\nfunction applyDomTheme(next: ThemeMode): void {\n if (typeof document === 'undefined') return\n const el = document.documentElement\n el.classList.toggle('dark', next === 'dark')\n el.classList.toggle('light', next === 'light')\n el.style.colorScheme = next\n try {\n window.localStorage.setItem(STORAGE_KEY, next)\n } catch {\n /* ignore */\n }\n}\n\n/**\n * The framework-agnostic toggle button. Controlled when `theme` is provided; otherwise\n * self-managed via the DOM `.dark` class. No framework dependency — safe on any host.\n */\nexport function AgnosticThemeToggle({\n theme,\n defaultTheme,\n onToggle,\n onThemeChange,\n size = '$2',\n label,\n}: ThemeToggleProps) {\n const controlled = theme !== undefined\n const [internal, setInternal] = useState<ThemeMode>(() => theme ?? defaultTheme ?? readDomTheme() ?? 'dark')\n const current: ThemeMode = controlled ? (theme as ThemeMode) : internal\n const isDark = current === 'dark'\n const track = useEmit()\n\n const toggle = () => {\n const next: ThemeMode = isDark ? 'light' : 'dark'\n track({ component: 'ThemeToggle', action: 'change', value: next })\n if (!controlled) {\n setInternal(next)\n applyDomTheme(next)\n }\n onToggle?.(next)\n onThemeChange?.(next)\n }\n\n return (\n <Button\n size={size as never}\n chromeless\n icon={isDark ? <Sun size={16} /> : <Moon size={16} />}\n onPress={toggle}\n aria-label={label ?? (isDark ? 'Switch to light theme' : 'Switch to dark theme')}\n />\n )\n}\n\n// @hanzogui/next-theme is an OPTIONAL dependency — loaded only on the uncontrolled,\n// no-props path (console/Next). Lazily code-split so non-Next hosts never need it at\n// runtime; if it fails to load, the boundary below degrades to the agnostic toggle.\nconst NextThemeToggle = lazy(() => import('./ThemeToggleNext'))\n\nclass NextThemeBoundary extends Component<{ fallback: ReactNode; children: ReactNode }, { failed: boolean }> {\n state = { failed: false }\n static getDerivedStateFromError() {\n return { failed: true }\n }\n render() {\n return this.state.failed ? this.props.fallback : this.props.children\n }\n}\n\nexport function ThemeToggle(props: ThemeToggleProps) {\n const injected =\n props.theme !== undefined || props.onToggle !== undefined || props.onThemeChange !== undefined\n if (injected) return <AgnosticThemeToggle {...props} />\n\n // No props → keep the existing console/Next behaviour via the optional next-theme\n // path, degrading to the agnostic DOM toggle if it is not installed.\n const fallback = <AgnosticThemeToggle {...props} />\n return (\n <NextThemeBoundary fallback={fallback}>\n <Suspense fallback={fallback}>\n <NextThemeToggle size={props.size} label={props.label} />\n </Suspense>\n </NextThemeBoundary>\n )\n}\n","'use client'\n\n/**\n * ThemeToggleNext — the @hanzogui/next-theme binding (console / Next). This is the ONLY\n * module that imports @hanzogui/next-theme, so it stays an OPTIONAL dependency: the base\n * ThemeToggle lazy-loads it (default export) and non-Next hosts never pull it in unless\n * they import this component directly. UI is delegated to the framework-agnostic button\n * in controlled mode, so every toggle looks identical.\n */\nimport { useThemeSetting } from '@hanzogui/next-theme'\nimport { AgnosticThemeToggle, type ThemeToggleProps } from './ThemeToggle'\n\nfunction ThemeToggleNext({ size, label }: Pick<ThemeToggleProps, 'size' | 'label'>) {\n const { current, resolvedTheme, set } = useThemeSetting()\n const isDark = (resolvedTheme ?? current ?? 'dark') !== 'light'\n return (\n <AgnosticThemeToggle\n theme={isDark ? 'dark' : 'light'}\n onToggle={(next) => set(next)}\n size={size}\n label={label}\n />\n )\n}\n\nexport default ThemeToggleNext\nexport { ThemeToggleNext }\n"]}
1
+ {"version":3,"sources":["../src/product/ThemeToggle.tsx","../src/product/ThemeToggleNext.tsx"],"names":["useState","useEmit","jsx","Button","Sun","Moon","lazy","Component","Suspense","useThemeSetting"],"mappings":"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","file":"chunk-ARV3P4CE.cjs","sourcesContent":["'use client'\n\n/**\n * ThemeToggle — flips between dark and light. Framework-agnostic by default so\n * Vite / Tauri / Express hosts can use it with NO Next dependency:\n *\n * • Controlled: <ThemeToggle theme={theme} onToggle={setTheme} /> (host owns theme)\n * • Uncontrolled (agnostic): <ThemeToggle onThemeChange={fn} /> (toggles the DOM\n * `.dark` class + persists to localStorage)\n * • Uncontrolled (no props): <ThemeToggle /> (console/Next —\n * falls back to the OPTIONAL @hanzogui/next-theme path;\n * if it cannot load, degrades to the agnostic DOM toggle)\n *\n * Shows the action's target icon (a sun in dark mode, a moon in light mode).\n */\nimport type { ReactNode } from 'react'\nimport { Component, Suspense, lazy, useState } from 'react'\nimport { Button } from '@hanzo/gui'\nimport { Moon, Sun } from '@hanzogui/lucide-icons-2'\n\nimport { useEmit } from './instrument'\n\nexport type ThemeMode = 'light' | 'dark'\n\nexport type ThemeToggleProps = {\n /** Controlled theme. Pair with `onToggle`/`onThemeChange` to fully control it. */\n theme?: ThemeMode\n /** Seed for uncontrolled mode (default: read from the DOM `.dark` class, else 'dark'). */\n defaultTheme?: ThemeMode\n /** Called with the next theme on toggle (alias of `onThemeChange`). */\n onToggle?: (next: ThemeMode) => void\n /** Called with the next theme on toggle. */\n onThemeChange?: (next: ThemeMode) => void\n /** @hanzo/gui Button size token (default \"$2\"). */\n size?: string\n /** aria-label override. */\n label?: string\n}\n\nconst STORAGE_KEY = 'theme'\n\nfunction readDomTheme(): ThemeMode | undefined {\n if (typeof document === 'undefined') return undefined\n const el = document.documentElement\n if (el.classList.contains('dark')) return 'dark'\n if (el.classList.contains('light')) return 'light'\n try {\n const ls = window.localStorage.getItem(STORAGE_KEY)\n if (ls === 'light' || ls === 'dark') return ls\n } catch {\n /* localStorage may be unavailable */\n }\n return undefined\n}\n\nfunction applyDomTheme(next: ThemeMode): void {\n if (typeof document === 'undefined') return\n const el = document.documentElement\n el.classList.toggle('dark', next === 'dark')\n el.classList.toggle('light', next === 'light')\n el.style.colorScheme = next\n try {\n window.localStorage.setItem(STORAGE_KEY, next)\n } catch {\n /* ignore */\n }\n}\n\n/**\n * The framework-agnostic toggle button. Controlled when `theme` is provided; otherwise\n * self-managed via the DOM `.dark` class. No framework dependency — safe on any host.\n */\nexport function AgnosticThemeToggle({\n theme,\n defaultTheme,\n onToggle,\n onThemeChange,\n size = '$2',\n label,\n}: ThemeToggleProps) {\n const controlled = theme !== undefined\n const [internal, setInternal] = useState<ThemeMode>(() => theme ?? defaultTheme ?? readDomTheme() ?? 'dark')\n const current: ThemeMode = controlled ? (theme as ThemeMode) : internal\n const isDark = current === 'dark'\n const track = useEmit()\n\n const toggle = () => {\n const next: ThemeMode = isDark ? 'light' : 'dark'\n track({ component: 'ThemeToggle', action: 'change', value: next })\n if (!controlled) {\n setInternal(next)\n applyDomTheme(next)\n }\n onToggle?.(next)\n onThemeChange?.(next)\n }\n\n return (\n <Button\n size={size as never}\n chromeless\n icon={isDark ? <Sun size={16} /> : <Moon size={16} />}\n onPress={toggle}\n aria-label={label ?? (isDark ? 'Switch to light theme' : 'Switch to dark theme')}\n />\n )\n}\n\n// @hanzogui/next-theme is an OPTIONAL dependency — loaded only on the uncontrolled,\n// no-props path (console/Next). Lazily code-split so non-Next hosts never need it at\n// runtime; if it fails to load, the boundary below degrades to the agnostic toggle.\nconst NextThemeToggle = lazy(() => import('./ThemeToggleNext'))\n\nclass NextThemeBoundary extends Component<{ fallback: ReactNode; children: ReactNode }, { failed: boolean }> {\n state = { failed: false }\n static getDerivedStateFromError() {\n return { failed: true }\n }\n render() {\n return this.state.failed ? this.props.fallback : this.props.children\n }\n}\n\nexport function ThemeToggle(props: ThemeToggleProps) {\n const injected =\n props.theme !== undefined || props.onToggle !== undefined || props.onThemeChange !== undefined\n if (injected) return <AgnosticThemeToggle {...props} />\n\n // No props → keep the existing console/Next behaviour via the optional next-theme\n // path, degrading to the agnostic DOM toggle if it is not installed.\n const fallback = <AgnosticThemeToggle {...props} />\n return (\n <NextThemeBoundary fallback={fallback}>\n <Suspense fallback={fallback}>\n <NextThemeToggle size={props.size} label={props.label} />\n </Suspense>\n </NextThemeBoundary>\n )\n}\n","'use client'\n\n/**\n * ThemeToggleNext — the @hanzogui/next-theme binding (console / Next). This is the ONLY\n * module that imports @hanzogui/next-theme, so it stays an OPTIONAL dependency: the base\n * ThemeToggle lazy-loads it (default export) and non-Next hosts never pull it in unless\n * they import this component directly. UI is delegated to the framework-agnostic button\n * in controlled mode, so every toggle looks identical.\n */\nimport { useThemeSetting } from '@hanzogui/next-theme'\nimport { AgnosticThemeToggle, type ThemeToggleProps } from './ThemeToggle'\n\nfunction ThemeToggleNext({ size, label }: Pick<ThemeToggleProps, 'size' | 'label'>) {\n const { current, resolvedTheme, set } = useThemeSetting()\n const isDark = (resolvedTheme ?? current ?? 'dark') !== 'light'\n return (\n <AgnosticThemeToggle\n theme={isDark ? 'dark' : 'light'}\n onToggle={(next) => set(next)}\n size={size}\n label={label}\n />\n )\n}\n\nexport default ThemeToggleNext\nexport { ThemeToggleNext }\n"]}
@@ -22,8 +22,16 @@ function useEmit() {
22
22
  [surface]
23
23
  );
24
24
  }
25
+ function labelOf(children) {
26
+ if (typeof children === "string") return children.trim() || void 0;
27
+ if (Array.isArray(children)) {
28
+ const text = children.filter((c) => typeof c === "string" || typeof c === "number").join("");
29
+ return text.trim() || void 0;
30
+ }
31
+ return void 0;
32
+ }
25
33
  var textSize = (s) => s ? s.length : 0;
26
34
 
27
- export { InstrumentSurface, emit, textSize, useEmit, useSurface };
28
- //# sourceMappingURL=chunk-P6IHE2O3.js.map
29
- //# sourceMappingURL=chunk-P6IHE2O3.js.map
35
+ export { InstrumentSurface, emit, labelOf, textSize, useEmit, useSurface };
36
+ //# sourceMappingURL=chunk-FVQXROBK.js.map
37
+ //# sourceMappingURL=chunk-FVQXROBK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/product/instrument.ts"],"names":[],"mappings":";;;;AAkEA,IAAM,cAAA,GAAiB,cAAkC,MAAS,CAAA;AAI3D,IAAM,oBAAoB,cAAA,CAAe;AAGzC,IAAM,UAAA,GAAa,MAA0B,UAAA,CAAW,cAAc;AAItE,SAAS,KAAK,CAAA,EAAkB;AACrC,EAAA,KAAA,CAAM,OAAO,YAAA,EAAc;AAAA,IACzB,WAAW,CAAA,CAAE,SAAA;AAAA,IACb,QAAQ,CAAA,CAAE,MAAA;AAAA,IACV,GAAI,EAAE,EAAA,KAAO,MAAA,GAAY,EAAE,EAAA,EAAI,CAAA,CAAE,IAAG,GAAI,IAAA;AAAA,IACxC,GAAI,EAAE,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,CAAA,CAAE,OAAM,GAAI,IAAA;AAAA,IACjD,GAAI,EAAE,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,CAAA,CAAE,SAAQ,GAAI;AAAA,GACxD,CAAA;AACH;AAIO,SAAS,OAAA,GAAgC;AAC9C,EAAA,MAAM,UAAU,UAAA,EAAW;AAC3B,EAAA,OAAO,WAAA;AAAA,IACL,CAAC,CAAA,KAAe,IAAA,CAAK,OAAA,KAAY,MAAA,IAAa,CAAA,CAAE,OAAA,KAAY,MAAA,GAAY,EAAE,GAAG,CAAA,EAAG,OAAA,KAAY,CAAC,CAAA;AAAA,IAC7F,CAAC,OAAO;AAAA,GACV;AACF;AAOO,SAAS,QAAQ,QAAA,EAAuC;AAC7D,EAAA,IAAI,OAAO,QAAA,KAAa,QAAA,EAAU,OAAO,QAAA,CAAS,MAAK,IAAK,MAAA;AAC5D,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,CAAA,KAAM,QAAQ,CAAA,CAAE,KAAK,EAAE,CAAA;AAC3F,IAAA,OAAO,IAAA,CAAK,MAAK,IAAK,MAAA;AAAA,EACxB;AACA,EAAA,OAAO,MAAA;AACT;AAKO,IAAM,QAAA,GAAW,CAAC,CAAA,KAAmC,CAAA,GAAI,EAAE,MAAA,GAAS","file":"chunk-FVQXROBK.js","sourcesContent":["// The ONE place a shared component says what a user just did.\n//\n// Instrumenting the COMPONENT beats instrumenting 100 apps: a product that\n// renders `DataTable`, `PrimaryButton`, `SlideOver`, `ConfirmDelete`, `Field*`,\n// `ComboBox`, `Segmented`, `SearchInput`, `OrgSwitcher`, `MenuItemView`,\n// `EmptyState` or `ThemeToggle` reports the SAME interaction vocabulary with\n// zero app code. Nothing to wire, nothing to remember, nothing to drift.\n//\n// import { emit, useEmit, InstrumentSurface } from '@hanzo/ui'\n// <InstrumentSurface name=\"billing\">…</InstrumentSurface> // optional context\n//\n// ONE event name, structured properties — the taxonomy in @hanzo/event is a\n// CLOSED set, and its own rule for a product-specific moment is \"the `action`\n// property, never a new event name\". So every UI interaction is\n// EVENTS.FEATURE_USED carrying { component, action, surface, id, value }.\n// Funnel moments (signup, checkout, deploy) keep their own dedicated names and\n// are emitted by the surface that owns them, not by a button.\n//\n// One stream: `track` from @hanzogui/telemetry — already a dependency of this\n// package and already THE front door (POST api.hanzo.ai/v1/event). No second\n// client, no CDN script, no `window` poking. It is SSR-safe, consent-aware,\n// honors DNT/GPC, and is fail-soft by construction, so this module inherits all\n// of that and adds no error policy of its own.\n\nimport { createContext, useCallback, useContext } from 'react'\n// ONE dependency edge: @hanzogui/telemetry owns the transport AND re-exports the\n// @hanzo/event vocabulary, so this package never names a second source of truth.\nimport { EVENTS, track } from '@hanzogui/telemetry'\n\n/** What a user did to a component. A closed set — it is the verb half of the\n * vocabulary, and a closed verb set is what makes cross-product funnels join. */\nexport type UiAction =\n | 'click'\n | 'open'\n | 'close'\n | 'select'\n | 'change'\n | 'sort'\n | 'filter'\n | 'search'\n | 'confirm'\n | 'cancel'\n | 'dismiss'\n | 'expand'\n | 'view'\n | 'error'\n\n/** One interaction. `component` + `action` are required; everything else is the\n * detail a lens groups by. Values are scrubbed downstream by @hanzo/event. */\nexport interface UiEvent {\n /** The shared component that observed it — `DataTable`, `PrimaryButton`, … */\n component: string\n action: UiAction\n /** The thing acted on: a column key, an option value, a menu item id. */\n id?: string\n /** A small scalar detail (sort direction, boolean state, count). Never PII —\n * free-text values (search terms, field contents) are reported as a LENGTH,\n * by the caller, not as the text. */\n value?: string | number | boolean\n /** The product area, when the app declared one via `<InstrumentSurface/>`. */\n surface?: string\n}\n\n/** The enclosing product area (route/module). Optional: with no provider the\n * events still carry component+action, and the product+path already come from\n * the telemetry client. */\nconst SurfaceContext = createContext<string | undefined>(undefined)\n\n/** Names the product area every shared component inside it reports under.\n * Plain provider, no element — it must not perturb any layout. */\nexport const InstrumentSurface = SurfaceContext.Provider\n\n/** The current product area, or undefined outside a provider. */\nexport const useSurface = (): string | undefined => useContext(SurfaceContext)\n\n/** Report an interaction. Callable from anywhere (module scope, event handler,\n * a non-React host) — the ambient telemetry client is built on first use. */\nexport function emit(e: UiEvent): void {\n track(EVENTS.FEATURE_USED, {\n component: e.component,\n action: e.action,\n ...(e.id !== undefined ? { id: e.id } : null),\n ...(e.value !== undefined ? { value: e.value } : null),\n ...(e.surface !== undefined ? { surface: e.surface } : null),\n })\n}\n\n/** `emit` with the surrounding `<InstrumentSurface/>` already bound — what the\n * shared components themselves use, so an app never labels a surface twice. */\nexport function useEmit(): (e: UiEvent) => void {\n const surface = useSurface()\n return useCallback(\n (e: UiEvent) => emit(surface !== undefined && e.surface === undefined ? { ...e, surface } : e),\n [surface],\n )\n}\n\n/** A component's own children ARE its identity — \"Deploy\", \"Log in with Hanzo\n * Cloud\". React hands them over as a string, or as an ARRAY when the label is\n * interpolated (`Log in with {brand}`), which is the common case; flattening the\n * string parts is the difference between a named event and an anonymous one.\n * Anything non-textual (an icon element) yields undefined rather than a guess. */\nexport function labelOf(children: unknown): string | undefined {\n if (typeof children === 'string') return children.trim() || undefined\n if (Array.isArray(children)) {\n const text = children.filter((c) => typeof c === 'string' || typeof c === 'number').join('')\n return text.trim() || undefined\n }\n return undefined\n}\n\n/** Free text (a search box, a text field) is reported as its LENGTH — the shape\n * of the behaviour without the content. One helper so no component invents its\n * own idea of \"safe to send\". */\nexport const textSize = (s: string | undefined): number => (s ? s.length : 0)\n"]}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunk57YEM34R_cjs = require('./chunk-57YEM34R.cjs');
4
+ var chunk7XDEUEWI_cjs = require('./chunk-7XDEUEWI.cjs');
5
5
  var chunkMWBFAV3D_cjs = require('./chunk-MWBFAV3D.cjs');
6
6
  var react = require('react');
7
7
  var gui = require('@hanzo/gui');
@@ -94,7 +94,7 @@ function DataTable({
94
94
  sort,
95
95
  onSortChange
96
96
  }) {
97
- const track = chunk57YEM34R_cjs.useEmit();
97
+ const track = chunk7XDEUEWI_cjs.useEmit();
98
98
  const minTableW = columns.reduce((sum, c) => sum + (c.width ?? FLEX_MIN_COL_W), 0) + (columns.length + 1) * 12;
99
99
  return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { borderWidth: 1, borderColor: "$borderColor", rounded: "$4", overflow: "hidden", children: [
100
100
  /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { style: { overflowX: "auto", overflowY: "visible" }, children: /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { minW: minTableW, children: [
@@ -242,18 +242,22 @@ function useAccent() {
242
242
  () => DEFAULT
243
243
  );
244
244
  }
245
- function PrimaryButton(props) {
245
+ function PrimaryButton({ onPress, ...rest }) {
246
246
  const { accent, contrast } = useAccent();
247
- const track = chunk57YEM34R_cjs.useEmit();
248
- const onPress = (e) => {
249
- track({ component: "PrimaryButton", action: "click", id: typeof props.children === "string" ? props.children : props["aria-label"] });
250
- props.onPress?.(e);
247
+ const track = chunk7XDEUEWI_cjs.useEmit();
248
+ const press = (e) => {
249
+ track({
250
+ component: "PrimaryButton",
251
+ action: "click",
252
+ id: chunk7XDEUEWI_cjs.labelOf(rest.children) ?? rest["aria-label"]
253
+ });
254
+ onPress?.(e);
251
255
  };
252
- props = { ...props, onPress };
256
+ const handler = press;
253
257
  if (accent) {
254
- return /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { style: { backgroundColor: accent, color: contrast, borderColor: accent }, ...props });
258
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { style: { backgroundColor: accent, color: contrast, borderColor: accent }, onPress: handler, ...rest });
255
259
  }
256
- return /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { theme: "light", ...props });
260
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { theme: "light", onPress: handler, ...rest });
257
261
  }
258
262
  function openHref(href) {
259
263
  if (typeof window !== "undefined") window.open(href, "_blank", "noopener");
@@ -266,7 +270,7 @@ function EmptyState({
266
270
  primary,
267
271
  secondary
268
272
  }) {
269
- const track = chunk57YEM34R_cjs.useEmit();
273
+ const track = chunk7XDEUEWI_cjs.useEmit();
270
274
  return /* @__PURE__ */ jsxRuntime.jsxs(
271
275
  gui.Card,
272
276
  {
@@ -335,7 +339,7 @@ function EmptyState({
335
339
  }
336
340
  var FieldNameContext = react.createContext(void 0);
337
341
  function useFieldTrack(component) {
338
- const track = chunk57YEM34R_cjs.useEmit();
342
+ const track = chunk7XDEUEWI_cjs.useEmit();
339
343
  const name = react.useContext(FieldNameContext);
340
344
  return (e) => track({ component, id: name, ...e });
341
345
  }
@@ -358,7 +362,7 @@ function FieldText({
358
362
  {
359
363
  value,
360
364
  onChangeText: (v) => {
361
- track({ action: "change", value: secure ? 0 : chunk57YEM34R_cjs.textSize(v) });
365
+ track({ action: "change", value: secure ? 0 : chunk7XDEUEWI_cjs.textSize(v) });
362
366
  onChange(v);
363
367
  },
364
368
  disabled,
@@ -380,7 +384,7 @@ function FieldTextArea({
380
384
  {
381
385
  value,
382
386
  onChangeText: (v) => {
383
- track({ action: "change", value: chunk57YEM34R_cjs.textSize(v) });
387
+ track({ action: "change", value: chunk7XDEUEWI_cjs.textSize(v) });
384
388
  onChange(v);
385
389
  },
386
390
  disabled,
@@ -570,7 +574,7 @@ function SlideOver({
570
574
  zIndex = 1e3,
571
575
  children
572
576
  }) {
573
- const track = chunk57YEM34R_cjs.useEmit();
577
+ const track = chunk7XDEUEWI_cjs.useEmit();
574
578
  const panelRef = react.useRef(null);
575
579
  const openerRef = react.useRef(null);
576
580
  react.useEffect(() => {
@@ -1248,5 +1252,5 @@ exports.resolveAccent = resolveAccent;
1248
1252
  exports.setOrgAccent = setOrgAccent;
1249
1253
  exports.useAccent = useAccent;
1250
1254
  exports.useHost = useHost;
1251
- //# sourceMappingURL=chunk-XULZJEW2.cjs.map
1252
- //# sourceMappingURL=chunk-XULZJEW2.cjs.map
1255
+ //# sourceMappingURL=chunk-NBZDIMP3.cjs.map
1256
+ //# sourceMappingURL=chunk-NBZDIMP3.cjs.map