@hanzo/ui 8.28.0 → 8.29.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 (78) hide show
  1. package/dist/backends/gui/icon-picker.cjs +194 -0
  2. package/dist/backends/gui/icon-picker.d.ts +51 -0
  3. package/dist/backends/gui/icon-picker.d.ts.map +1 -0
  4. package/dist/backends/gui/icon-picker.js +155 -0
  5. package/dist/backends/gui/icon-picker.js.map +1 -0
  6. package/dist/backends/gui/icons.cjs +381 -0
  7. package/dist/backends/gui/icons.d.ts +53 -0
  8. package/dist/backends/gui/icons.d.ts.map +1 -0
  9. package/dist/backends/gui/icons.js +377 -0
  10. package/dist/backends/gui/icons.js.map +1 -0
  11. package/dist/backends/gui/index.cjs +13 -1
  12. package/dist/backends/gui/index.d.ts +2 -0
  13. package/dist/backends/gui/index.d.ts.map +1 -1
  14. package/dist/backends/gui/index.js +2 -0
  15. package/dist/backends/gui/index.js.map +1 -1
  16. package/dist/gallery/icons.cjs +19 -0
  17. package/dist/gallery/icons.d.ts +2 -0
  18. package/dist/gallery/icons.d.ts.map +1 -0
  19. package/dist/gallery/icons.js +17 -0
  20. package/dist/gallery/icons.js.map +1 -0
  21. package/dist/gallery/records.cjs +2 -1
  22. package/dist/gallery/records.d.ts.map +1 -1
  23. package/dist/gallery/records.js +2 -1
  24. package/dist/gallery/records.js.map +1 -1
  25. package/dist/gallery.html +2 -2
  26. package/dist/index.cjs +14 -2
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +3 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.node.cjs +14 -2
  32. package/dist/index.node.js +3 -0
  33. package/dist/primitives/CONCEPTS.cjs +8 -0
  34. package/dist/primitives/CONCEPTS.d.ts +2 -0
  35. package/dist/primitives/CONCEPTS.d.ts.map +1 -0
  36. package/dist/primitives/CONCEPTS.js +5 -0
  37. package/dist/primitives/CONCEPTS.js.map +1 -0
  38. package/dist/primitives/FIELD_ICONS.cjs +8 -0
  39. package/dist/primitives/FIELD_ICONS.d.ts +2 -0
  40. package/dist/primitives/FIELD_ICONS.d.ts.map +1 -0
  41. package/dist/primitives/FIELD_ICONS.js +5 -0
  42. package/dist/primitives/FIELD_ICONS.js.map +1 -0
  43. package/dist/primitives/Glyph.cjs +8 -0
  44. package/dist/primitives/Glyph.d.ts +2 -0
  45. package/dist/primitives/Glyph.d.ts.map +1 -0
  46. package/dist/primitives/Glyph.js +5 -0
  47. package/dist/primitives/Glyph.js.map +1 -0
  48. package/dist/primitives/IconPicker.cjs +8 -0
  49. package/dist/primitives/IconPicker.d.ts +2 -0
  50. package/dist/primitives/IconPicker.d.ts.map +1 -0
  51. package/dist/primitives/IconPicker.js +5 -0
  52. package/dist/primitives/IconPicker.js.map +1 -0
  53. package/dist/primitives/TABLER.cjs +8 -0
  54. package/dist/primitives/TABLER.d.ts +2 -0
  55. package/dist/primitives/TABLER.d.ts.map +1 -0
  56. package/dist/primitives/TABLER.js +5 -0
  57. package/dist/primitives/TABLER.js.map +1 -0
  58. package/dist/primitives/iconWords.cjs +8 -0
  59. package/dist/primitives/iconWords.d.ts +2 -0
  60. package/dist/primitives/iconWords.d.ts.map +1 -0
  61. package/dist/primitives/iconWords.js +5 -0
  62. package/dist/primitives/iconWords.js.map +1 -0
  63. package/dist/primitives/loadIcons.cjs +8 -0
  64. package/dist/primitives/loadIcons.d.ts +2 -0
  65. package/dist/primitives/loadIcons.d.ts.map +1 -0
  66. package/dist/primitives/loadIcons.js +5 -0
  67. package/dist/primitives/loadIcons.js.map +1 -0
  68. package/dist/primitives/resolveIcon.cjs +8 -0
  69. package/dist/primitives/resolveIcon.d.ts +2 -0
  70. package/dist/primitives/resolveIcon.d.ts.map +1 -0
  71. package/dist/primitives/resolveIcon.js +5 -0
  72. package/dist/primitives/resolveIcon.js.map +1 -0
  73. package/dist/primitives/useIcons.cjs +8 -0
  74. package/dist/primitives/useIcons.d.ts +2 -0
  75. package/dist/primitives/useIcons.d.ts.map +1 -0
  76. package/dist/primitives/useIcons.js +5 -0
  77. package/dist/primitives/useIcons.js.map +1 -0
  78. package/package.json +1 -1
@@ -0,0 +1,194 @@
1
+ 'use client';"use strict";
2
+ 'use client';
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.PICKER_W = void 0;
38
+ exports.loadIcons = loadIcons;
39
+ exports.useIcons = useIcons;
40
+ exports.Glyph = Glyph;
41
+ exports.IconPicker = IconPicker;
42
+ const jsx_runtime_1 = require("react/jsx-runtime");
43
+ /**
44
+ * Glyph and IconPicker — a stored icon name, drawn; and the grid a person picks
45
+ * one from.
46
+ *
47
+ * Both load Lucide through ONE dynamic import of @hanzogui/lucide-icons-2
48
+ * (`loadIcons`), so a page that never draws a stored icon pays nothing, and a
49
+ * page that does loads one chunk once: every later Glyph reads the module-level
50
+ * cache and draws on its first render. The name is resolved by `resolveIcon`
51
+ * (icons.ts): a Lucide name, a Tabler name with its pair, a same-name match, or
52
+ * the kind's fallback.
53
+ *
54
+ * The picker is the data-model editor's icon picker (twenty-ui's icon picker,
55
+ * MIT, NOTICE): 176 wide, a search field over the names and the concepts each
56
+ * icon draws, and a grid of 32px cells five across, run by the arrows in two
57
+ * dimensions, Home/End, and Enter. It shows the first 150 matches and says how
58
+ * many more a search would narrow to, rather than mounting 1,760 icons at once.
59
+ */
60
+ const gui_1 = require("@hanzo/gui");
61
+ const react_1 = require("react");
62
+ const button_1 = require("./button.cjs");
63
+ const density_1 = require("./density.cjs");
64
+ const icons_1 = require("./icons.cjs");
65
+ const input_1 = require("./input.cjs");
66
+ const popover_1 = require("./popover.cjs");
67
+ const search_list_1 = require("./search-list.cjs");
68
+ const slot_1 = require("./slot.cjs");
69
+ let cache = null;
70
+ let pending = null;
71
+ /** Every Lucide icon, loaded once, by name. */
72
+ function loadIcons() {
73
+ if (cache)
74
+ return Promise.resolve(cache);
75
+ pending ??= Promise.resolve().then(() => __importStar(require('@hanzogui/lucide-icons-2'))).then((mod) => {
76
+ const table = mod;
77
+ // The barrel exports the icons and nothing else (1,760, each by its name).
78
+ const list = Object.keys(table).filter((k) => /^[A-Z]/.test(k)).sort();
79
+ cache = { names: new Set(list), get: (n) => table[n], list };
80
+ return cache;
81
+ });
82
+ return pending;
83
+ }
84
+ /** The icon set, once it has loaded (`null` until then). */
85
+ function useIcons() {
86
+ const [icons, setIcons] = (0, react_1.useState)(cache);
87
+ (0, react_1.useEffect)(() => {
88
+ if (icons)
89
+ return;
90
+ let live = true;
91
+ loadIcons().then((loaded) => live && setIcons(loaded));
92
+ return () => {
93
+ live = false;
94
+ };
95
+ }, [icons]);
96
+ return icons;
97
+ }
98
+ /**
99
+ * A stored icon name, drawn. Holds its box while the set loads, so a row of
100
+ * glyphs does not shift when they arrive; draws nothing (and still holds the
101
+ * box) for a name with no icon and no fallback.
102
+ */
103
+ function Glyph({ name, kind = 'other', size = 16, color }) {
104
+ const icons = useIcons();
105
+ const resolved = icons ? (0, icons_1.resolveIcon)(name, icons.names, kind) : null;
106
+ const Icon = resolved ? icons?.get(resolved) : undefined;
107
+ return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('glyph'), width: size, height: size, items: "center", justify: "center", shrink: 0, "aria-hidden": true, children: Icon ? (0, jsx_runtime_1.jsx)(Icon, { size: size, ...(color ? { color } : null) }) : null }));
108
+ }
109
+ const COLUMNS = 5;
110
+ const CELL = 32;
111
+ const GAP = 2;
112
+ const INSET = 4;
113
+ /** Five cells of 32 with 2 between and 4 round: twenty-ui's 176px picker. */
114
+ exports.PICKER_W = INSET * 2 + COLUMNS * CELL + (COLUMNS - 1) * GAP;
115
+ const SHOWN = 150;
116
+ /** The names a query keeps: every word of it in the name or a concept it draws. */
117
+ const filterIcons = (list, q) => {
118
+ const words = q.trim().toLowerCase().split(/\s+/).filter(Boolean);
119
+ if (!words.length)
120
+ return [...list];
121
+ return list.filter((n) => {
122
+ const hay = (0, icons_1.iconWords)(n);
123
+ return words.every((w) => hay.includes(w));
124
+ });
125
+ };
126
+ function IconPicker({ value, onValueChange, kind = 'other', trigger, open: openProp, defaultOpen, onOpenChange, label = 'Icon', searchLabel = 'Search icons', emptyLabel = 'No icon matches', disabled, }) {
127
+ const density = (0, density_1.useDensity)();
128
+ const [open, setOpen] = (0, search_list_1.useOpen)(openProp, defaultOpen, onOpenChange);
129
+ const icons = useIcons();
130
+ const [q, setQ] = (0, react_1.useState)('');
131
+ const [cursor, setCursor] = (0, react_1.useState)(0);
132
+ const grid = (0, react_1.useRef)(null);
133
+ const matches = (0, react_1.useMemo)(() => (icons ? filterIcons(icons.list, q) : []), [icons, q]);
134
+ const shown = matches.slice(0, SHOWN);
135
+ const chosen = icons ? (0, icons_1.resolveIcon)(value, icons.names, kind) : null;
136
+ // A fresh open starts on the chosen icon when it is in view, else the first.
137
+ (0, react_1.useEffect)(() => {
138
+ if (!open)
139
+ return;
140
+ const at = chosen ? shown.indexOf(chosen) : -1;
141
+ setCursor(at >= 0 ? at : 0);
142
+ // Only the opening and a new result set reset the cursor.
143
+ // eslint-disable-next-line react-hooks/exhaustive-deps
144
+ }, [open, q, icons]);
145
+ (0, react_1.useEffect)(() => {
146
+ if (!open)
147
+ setQ('');
148
+ }, [open]);
149
+ const pick = (name) => {
150
+ onValueChange?.(name);
151
+ setOpen(false);
152
+ };
153
+ const move = (e) => {
154
+ const last = shown.length - 1;
155
+ if (last < 0)
156
+ return;
157
+ const step = { ArrowRight: 1, ArrowLeft: -1, ArrowDown: COLUMNS, ArrowUp: -COLUMNS };
158
+ let next = cursor;
159
+ if (e.key && e.key in step)
160
+ next = Math.min(last, Math.max(0, cursor + step[e.key]));
161
+ else if (e.key === 'Home')
162
+ next = 0;
163
+ else if (e.key === 'End')
164
+ next = last;
165
+ else if (e.key === 'Enter') {
166
+ e.preventDefault?.();
167
+ if (shown[cursor])
168
+ pick(shown[cursor]);
169
+ return;
170
+ }
171
+ else
172
+ return;
173
+ e.preventDefault?.();
174
+ setCursor(next);
175
+ };
176
+ (0, react_1.useEffect)(() => {
177
+ const el = grid.current?.querySelector?.(`[data-index="${cursor}"]`);
178
+ el?.scrollIntoView?.({ block: 'nearest' });
179
+ }, [cursor]);
180
+ const ActiveIcon = chosen ? icons?.get(chosen) : undefined;
181
+ const id = `icon-picker-${(0, react_1.useId)().replace(/:/g, '')}`;
182
+ return ((0, jsx_runtime_1.jsxs)(popover_1.Popover, { open: open, onOpenChange: setOpen, placement: "bottom-start", children: [(0, jsx_runtime_1.jsx)(popover_1.PopoverTrigger, { asChild: true, children: trigger ?? ((0, jsx_runtime_1.jsx)(button_1.Button, { size: "icon-sm", variant: "outline", disabled: disabled, "aria-label": chosen ? `${label}: ${chosen}` : label, ...{ 'aria-haspopup': 'listbox' }, children: ActiveIcon ? (0, jsx_runtime_1.jsx)(ActiveIcon, { size: 16 }) : (0, jsx_runtime_1.jsx)(gui_1.XStack, { width: 16, height: 16 }) })) }), (0, jsx_runtime_1.jsx)(popover_1.PopoverContent, { ...(0, slot_1.slot)('icon-picker'), p: 0, width: exports.PICKER_W, sideOffset: 8, overflow: "hidden", children: (0, jsx_runtime_1.jsx)(density_1.Density, { value: density, children: (0, jsx_runtime_1.jsxs)(gui_1.YStack, { children: [(0, jsx_runtime_1.jsx)(gui_1.XStack, { p: INSET, borderBottomWidth: 1, borderColor: "$borderColor", children: (0, jsx_runtime_1.jsx)(input_1.Input, { size: "xs", value: q, onChangeText: (t) => setQ(t), placeholder: searchLabel, "aria-label": searchLabel, "aria-controls": id, "aria-activedescendant": shown[cursor] ? `${id}-${cursor}` : undefined, autoFocus: true, ...{ onKeyDown: move } }) }), !icons ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$hint", p: "$2", role: "status", "aria-live": "polite", children: "Loading\u2026" })) : shown.length === 0 ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$hint", p: "$2", role: "status", "aria-live": "polite", children: emptyLabel })) : ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ref: grid, ...(0, slot_1.slot)('icon-picker-grid'), ...{ id, role: 'listbox', 'aria-label': label }, flexWrap: "wrap", gap: GAP, p: INSET, maxH: CELL * 6 + GAP * 5 + INSET * 2, overflow: "scroll", children: shown.map((name, i) => {
183
+ const Icon = icons.get(name);
184
+ const on = name === chosen;
185
+ return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...{
186
+ id: `${id}-${i}`,
187
+ role: 'option',
188
+ 'aria-selected': on,
189
+ 'aria-label': name,
190
+ 'data-index': i,
191
+ title: name,
192
+ }, width: CELL, height: CELL, items: "center", justify: "center", rounded: "$xs", cursor: "pointer", bg: i === cursor ? '$hover' : on ? '$raised' : 'transparent', hoverStyle: { bg: '$hover' }, onPress: () => pick(name), children: Icon ? (0, jsx_runtime_1.jsx)(Icon, { size: 16, color: on ? '$ink' : '$aside' }) : null }, name));
193
+ }) })), icons && matches.length > SHOWN ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$hint", px: "$2", pb: "$2", role: "status", "aria-live": "polite", children: `${matches.length - SHOWN} more — type to narrow` })) : null] }) }) })] }));
194
+ }
@@ -0,0 +1,51 @@
1
+ import { type ComponentType, type ReactElement } from 'react';
2
+ import { type IconKind } from './icons.js';
3
+ type IconComponent = ComponentType<{
4
+ size?: number;
5
+ color?: string;
6
+ }>;
7
+ type Icons = {
8
+ names: ReadonlySet<string>;
9
+ get: (name: string) => IconComponent | undefined;
10
+ list: readonly string[];
11
+ };
12
+ /** Every Lucide icon, loaded once, by name. */
13
+ export declare function loadIcons(): Promise<Icons>;
14
+ /** The icon set, once it has loaded (`null` until then). */
15
+ export declare function useIcons(): Icons | null;
16
+ export type GlyphProps = {
17
+ /** The stored name: a Lucide name, or a Tabler one from an import. */
18
+ name: string | null | undefined;
19
+ /** What it names, which decides the fallback for an unknown name. */
20
+ kind?: IconKind;
21
+ size?: number;
22
+ color?: string;
23
+ };
24
+ /**
25
+ * A stored icon name, drawn. Holds its box while the set loads, so a row of
26
+ * glyphs does not shift when they arrive; draws nothing (and still holds the
27
+ * box) for a name with no icon and no fallback.
28
+ */
29
+ export declare function Glyph({ name, kind, size, color }: GlyphProps): import("react").JSX.Element;
30
+ /** Five cells of 32 with 2 between and 4 round: twenty-ui's 176px picker. */
31
+ export declare const PICKER_W: number;
32
+ export type IconPickerProps = {
33
+ /** The chosen icon's stored name. */
34
+ value?: string | null;
35
+ onValueChange?: (name: string) => void;
36
+ /** What the chosen name is for; its fallback draws the trigger when unknown. */
37
+ kind?: IconKind;
38
+ /** Replaces the default trigger (an outline icon button drawing the value). */
39
+ trigger?: ReactElement;
40
+ open?: boolean;
41
+ defaultOpen?: boolean;
42
+ onOpenChange?: (open: boolean) => void;
43
+ /** The trigger's and the grid's accessible name. */
44
+ label?: string;
45
+ searchLabel?: string;
46
+ emptyLabel?: string;
47
+ disabled?: boolean;
48
+ };
49
+ export declare function IconPicker({ value, onValueChange, kind, trigger, open: openProp, defaultOpen, onOpenChange, label, searchLabel, emptyLabel, disabled, }: IconPickerProps): import("react").JSX.Element;
50
+ export {};
51
+ //# sourceMappingURL=icon-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon-picker.d.ts","sourceRoot":"","sources":["../../../src/backends/gui/icon-picker.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAML,KAAK,aAAa,EAElB,KAAK,YAAY,EAClB,MAAM,OAAO,CAAA;AAGd,OAAO,EAA0B,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AAM/D,KAAK,aAAa,GAAG,aAAa,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AACrE,KAAK,KAAK,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAA;AAKtH,+CAA+C;AAC/C,wBAAgB,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,CAU1C;AAED,4DAA4D;AAC5D,wBAAgB,QAAQ,IAAI,KAAK,GAAG,IAAI,CAWvC;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,sEAAsE;IACtE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAC/B,qEAAqE;IACrE,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,EAAE,IAAI,EAAE,IAAc,EAAE,IAAS,EAAE,KAAK,EAAE,EAAE,UAAU,+BAS3E;AAMD,6EAA6E;AAC7E,eAAO,MAAM,QAAQ,QAAmD,CAAA;AAGxE,MAAM,MAAM,eAAe,GAAG;IAC5B,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,gFAAgF;IAChF,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,+EAA+E;IAC/E,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAYD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,aAAa,EACb,IAAc,EACd,OAAO,EACP,IAAI,EAAE,QAAQ,EACd,WAAW,EACX,YAAY,EACZ,KAAc,EACd,WAA4B,EAC5B,UAA8B,EAC9B,QAAQ,GACT,EAAE,eAAe,+BAiJjB"}
@@ -0,0 +1,155 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Glyph and IconPicker — a stored icon name, drawn; and the grid a person picks
5
+ * one from.
6
+ *
7
+ * Both load Lucide through ONE dynamic import of @hanzogui/lucide-icons-2
8
+ * (`loadIcons`), so a page that never draws a stored icon pays nothing, and a
9
+ * page that does loads one chunk once: every later Glyph reads the module-level
10
+ * cache and draws on its first render. The name is resolved by `resolveIcon`
11
+ * (icons.ts): a Lucide name, a Tabler name with its pair, a same-name match, or
12
+ * the kind's fallback.
13
+ *
14
+ * The picker is the data-model editor's icon picker (twenty-ui's icon picker,
15
+ * MIT, NOTICE): 176 wide, a search field over the names and the concepts each
16
+ * icon draws, and a grid of 32px cells five across, run by the arrows in two
17
+ * dimensions, Home/End, and Enter. It shows the first 150 matches and says how
18
+ * many more a search would narrow to, rather than mounting 1,760 icons at once.
19
+ */
20
+ import { SizableText, XStack, YStack } from '@hanzo/gui';
21
+ import { useEffect, useId, useMemo, useRef, useState, } from 'react';
22
+ import { Button } from './button.js';
23
+ import { Density, useDensity } from './density.js';
24
+ import { iconWords, resolveIcon } from './icons.js';
25
+ import { Input } from './input.js';
26
+ import { Popover, PopoverContent, PopoverTrigger } from './popover.js';
27
+ import { useOpen } from './search-list.js';
28
+ import { slot } from './slot.js';
29
+ let cache = null;
30
+ let pending = null;
31
+ /** Every Lucide icon, loaded once, by name. */
32
+ export function loadIcons() {
33
+ if (cache)
34
+ return Promise.resolve(cache);
35
+ pending ??= import('@hanzogui/lucide-icons-2').then((mod) => {
36
+ const table = mod;
37
+ // The barrel exports the icons and nothing else (1,760, each by its name).
38
+ const list = Object.keys(table).filter((k) => /^[A-Z]/.test(k)).sort();
39
+ cache = { names: new Set(list), get: (n) => table[n], list };
40
+ return cache;
41
+ });
42
+ return pending;
43
+ }
44
+ /** The icon set, once it has loaded (`null` until then). */
45
+ export function useIcons() {
46
+ const [icons, setIcons] = useState(cache);
47
+ useEffect(() => {
48
+ if (icons)
49
+ return;
50
+ let live = true;
51
+ loadIcons().then((loaded) => live && setIcons(loaded));
52
+ return () => {
53
+ live = false;
54
+ };
55
+ }, [icons]);
56
+ return icons;
57
+ }
58
+ /**
59
+ * A stored icon name, drawn. Holds its box while the set loads, so a row of
60
+ * glyphs does not shift when they arrive; draws nothing (and still holds the
61
+ * box) for a name with no icon and no fallback.
62
+ */
63
+ export function Glyph({ name, kind = 'other', size = 16, color }) {
64
+ const icons = useIcons();
65
+ const resolved = icons ? resolveIcon(name, icons.names, kind) : null;
66
+ const Icon = resolved ? icons?.get(resolved) : undefined;
67
+ return (_jsx(XStack, { ...slot('glyph'), width: size, height: size, items: "center", justify: "center", shrink: 0, "aria-hidden": true, children: Icon ? _jsx(Icon, { size: size, ...(color ? { color } : null) }) : null }));
68
+ }
69
+ const COLUMNS = 5;
70
+ const CELL = 32;
71
+ const GAP = 2;
72
+ const INSET = 4;
73
+ /** Five cells of 32 with 2 between and 4 round: twenty-ui's 176px picker. */
74
+ export const PICKER_W = INSET * 2 + COLUMNS * CELL + (COLUMNS - 1) * GAP;
75
+ const SHOWN = 150;
76
+ /** The names a query keeps: every word of it in the name or a concept it draws. */
77
+ const filterIcons = (list, q) => {
78
+ const words = q.trim().toLowerCase().split(/\s+/).filter(Boolean);
79
+ if (!words.length)
80
+ return [...list];
81
+ return list.filter((n) => {
82
+ const hay = iconWords(n);
83
+ return words.every((w) => hay.includes(w));
84
+ });
85
+ };
86
+ export function IconPicker({ value, onValueChange, kind = 'other', trigger, open: openProp, defaultOpen, onOpenChange, label = 'Icon', searchLabel = 'Search icons', emptyLabel = 'No icon matches', disabled, }) {
87
+ const density = useDensity();
88
+ const [open, setOpen] = useOpen(openProp, defaultOpen, onOpenChange);
89
+ const icons = useIcons();
90
+ const [q, setQ] = useState('');
91
+ const [cursor, setCursor] = useState(0);
92
+ const grid = useRef(null);
93
+ const matches = useMemo(() => (icons ? filterIcons(icons.list, q) : []), [icons, q]);
94
+ const shown = matches.slice(0, SHOWN);
95
+ const chosen = icons ? resolveIcon(value, icons.names, kind) : null;
96
+ // A fresh open starts on the chosen icon when it is in view, else the first.
97
+ useEffect(() => {
98
+ if (!open)
99
+ return;
100
+ const at = chosen ? shown.indexOf(chosen) : -1;
101
+ setCursor(at >= 0 ? at : 0);
102
+ // Only the opening and a new result set reset the cursor.
103
+ // eslint-disable-next-line react-hooks/exhaustive-deps
104
+ }, [open, q, icons]);
105
+ useEffect(() => {
106
+ if (!open)
107
+ setQ('');
108
+ }, [open]);
109
+ const pick = (name) => {
110
+ onValueChange?.(name);
111
+ setOpen(false);
112
+ };
113
+ const move = (e) => {
114
+ const last = shown.length - 1;
115
+ if (last < 0)
116
+ return;
117
+ const step = { ArrowRight: 1, ArrowLeft: -1, ArrowDown: COLUMNS, ArrowUp: -COLUMNS };
118
+ let next = cursor;
119
+ if (e.key && e.key in step)
120
+ next = Math.min(last, Math.max(0, cursor + step[e.key]));
121
+ else if (e.key === 'Home')
122
+ next = 0;
123
+ else if (e.key === 'End')
124
+ next = last;
125
+ else if (e.key === 'Enter') {
126
+ e.preventDefault?.();
127
+ if (shown[cursor])
128
+ pick(shown[cursor]);
129
+ return;
130
+ }
131
+ else
132
+ return;
133
+ e.preventDefault?.();
134
+ setCursor(next);
135
+ };
136
+ useEffect(() => {
137
+ const el = grid.current?.querySelector?.(`[data-index="${cursor}"]`);
138
+ el?.scrollIntoView?.({ block: 'nearest' });
139
+ }, [cursor]);
140
+ const ActiveIcon = chosen ? icons?.get(chosen) : undefined;
141
+ const id = `icon-picker-${useId().replace(/:/g, '')}`;
142
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, placement: "bottom-start", children: [_jsx(PopoverTrigger, { asChild: true, children: trigger ?? (_jsx(Button, { size: "icon-sm", variant: "outline", disabled: disabled, "aria-label": chosen ? `${label}: ${chosen}` : label, ...{ 'aria-haspopup': 'listbox' }, children: ActiveIcon ? _jsx(ActiveIcon, { size: 16 }) : _jsx(XStack, { width: 16, height: 16 }) })) }), _jsx(PopoverContent, { ...slot('icon-picker'), p: 0, width: PICKER_W, sideOffset: 8, overflow: "hidden", children: _jsx(Density, { value: density, children: _jsxs(YStack, { children: [_jsx(XStack, { p: INSET, borderBottomWidth: 1, borderColor: "$borderColor", children: _jsx(Input, { size: "xs", value: q, onChangeText: (t) => setQ(t), placeholder: searchLabel, "aria-label": searchLabel, "aria-controls": id, "aria-activedescendant": shown[cursor] ? `${id}-${cursor}` : undefined, autoFocus: true, ...{ onKeyDown: move } }) }), !icons ? (_jsx(SizableText, { size: "$1", color: "$hint", p: "$2", role: "status", "aria-live": "polite", children: "Loading\u2026" })) : shown.length === 0 ? (_jsx(SizableText, { size: "$1", color: "$hint", p: "$2", role: "status", "aria-live": "polite", children: emptyLabel })) : (_jsx(XStack, { ref: grid, ...slot('icon-picker-grid'), ...{ id, role: 'listbox', 'aria-label': label }, flexWrap: "wrap", gap: GAP, p: INSET, maxH: CELL * 6 + GAP * 5 + INSET * 2, overflow: "scroll", children: shown.map((name, i) => {
143
+ const Icon = icons.get(name);
144
+ const on = name === chosen;
145
+ return (_jsx(XStack, { ...{
146
+ id: `${id}-${i}`,
147
+ role: 'option',
148
+ 'aria-selected': on,
149
+ 'aria-label': name,
150
+ 'data-index': i,
151
+ title: name,
152
+ }, width: CELL, height: CELL, items: "center", justify: "center", rounded: "$xs", cursor: "pointer", bg: i === cursor ? '$hover' : on ? '$raised' : 'transparent', hoverStyle: { bg: '$hover' }, onPress: () => pick(name), children: Icon ? _jsx(Icon, { size: 16, color: on ? '$ink' : '$aside' }) : null }, name));
153
+ }) })), icons && matches.length > SHOWN ? (_jsx(SizableText, { size: "$1", color: "$hint", px: "$2", pb: "$2", role: "status", "aria-live": "polite", children: `${matches.length - SHOWN} more — type to narrow` })) : null] }) }) })] }));
154
+ }
155
+ //# sourceMappingURL=icon-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon-picker.js","sourceRoot":"","sources":["../../../src/backends/gui/icon-picker.tsx"],"names":[],"mappings":"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"}