@pixerate/editor-react 0.14.0 → 0.16.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 (54) hide show
  1. package/README.md +6 -1
  2. package/dist/canvas/index.cjs +352 -118
  3. package/dist/canvas/index.cjs.map +1 -1
  4. package/dist/canvas/index.d.cts +112 -8
  5. package/dist/canvas/index.d.ts +112 -8
  6. package/dist/canvas/index.js +258 -19
  7. package/dist/canvas/index.js.map +1 -1
  8. package/dist/chunk-4ZC2WCUO.js +196 -0
  9. package/dist/chunk-4ZC2WCUO.js.map +1 -0
  10. package/dist/chunk-7SPRQZ6H.js +216 -0
  11. package/dist/chunk-7SPRQZ6H.js.map +1 -0
  12. package/dist/{chunk-25S5EHH4.js → chunk-FYIPXHAE.js} +22 -13
  13. package/dist/chunk-FYIPXHAE.js.map +1 -0
  14. package/dist/{chunk-TL27COKM.js → chunk-XTFR3IMK.js} +683 -286
  15. package/dist/chunk-XTFR3IMK.js.map +1 -0
  16. package/dist/chunk-XWFU2CSG.js +167 -0
  17. package/dist/chunk-XWFU2CSG.js.map +1 -0
  18. package/dist/commands/index.cjs +232 -0
  19. package/dist/commands/index.cjs.map +1 -0
  20. package/dist/commands/index.d.cts +69 -0
  21. package/dist/commands/index.d.ts +69 -0
  22. package/dist/commands/index.js +13 -0
  23. package/dist/commands/index.js.map +1 -0
  24. package/dist/generation/index.cjs +235 -0
  25. package/dist/generation/index.cjs.map +1 -0
  26. package/dist/generation/index.d.cts +60 -0
  27. package/dist/generation/index.d.ts +60 -0
  28. package/dist/generation/index.js +13 -0
  29. package/dist/generation/index.js.map +1 -0
  30. package/dist/image-editor/index.cjs +688 -299
  31. package/dist/image-editor/index.cjs.map +1 -1
  32. package/dist/image-editor/index.d.cts +65 -5
  33. package/dist/image-editor/index.d.ts +65 -5
  34. package/dist/image-editor/index.js +13 -3
  35. package/dist/index.cjs +2200 -683
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +201 -23
  38. package/dist/index.d.ts +201 -23
  39. package/dist/index.js +743 -129
  40. package/dist/index.js.map +1 -1
  41. package/dist/persistence/index.cjs +191 -0
  42. package/dist/persistence/index.cjs.map +1 -0
  43. package/dist/persistence/index.d.cts +77 -0
  44. package/dist/persistence/index.d.ts +77 -0
  45. package/dist/persistence/index.js +9 -0
  46. package/dist/persistence/index.js.map +1 -0
  47. package/dist/spreadsheet/index.cjs +17 -10
  48. package/dist/spreadsheet/index.cjs.map +1 -1
  49. package/dist/spreadsheet/index.d.cts +9 -7
  50. package/dist/spreadsheet/index.d.ts +9 -7
  51. package/dist/spreadsheet/index.js +1 -1
  52. package/package.json +26 -2
  53. package/dist/chunk-25S5EHH4.js.map +0 -1
  54. package/dist/chunk-TL27COKM.js.map +0 -1
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/commands/index.ts
31
+ var commands_exports = {};
32
+ __export(commands_exports, {
33
+ CommandPalette: () => CommandPalette,
34
+ useCommandPalette: () => useCommandPalette,
35
+ useCommandShortcuts: () => useCommandShortcuts,
36
+ useRegisterCommands: () => useRegisterCommands
37
+ });
38
+ module.exports = __toCommonJS(commands_exports);
39
+
40
+ // src/commands/useCommandPalette.ts
41
+ var import_react = require("react");
42
+ var import_commands = require("@pixerate/editor/commands");
43
+ function useCommandPalette(registry, options = {}) {
44
+ const optionsRef = (0, import_react.useRef)(options);
45
+ optionsRef.current = options;
46
+ const controller = (0, import_react.useMemo)(
47
+ () => (0, import_commands.createCommandPaletteController)(registry, {
48
+ context: () => {
49
+ const c = optionsRef.current.context;
50
+ if (c === void 0) return registry.context;
51
+ return typeof c === "function" ? c() : c;
52
+ },
53
+ scope: () => {
54
+ const s = optionsRef.current.scope;
55
+ return typeof s === "function" ? s() : s;
56
+ },
57
+ recents: options.recents,
58
+ recentLimit: options.recentLimit,
59
+ limit: options.limit,
60
+ platform: options.platform,
61
+ onRecentsChange: (recents) => optionsRef.current.onRecentsChange?.(recents),
62
+ onRun: (result) => optionsRef.current.onRun?.(result)
63
+ }),
64
+ // eslint-disable-next-line react-hooks/exhaustive-deps
65
+ [registry]
66
+ );
67
+ const state = (0, import_react.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
68
+ const { hotkey, hotkeyTarget } = options;
69
+ (0, import_react.useEffect)(() => {
70
+ if (!hotkey) return;
71
+ const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
72
+ if (!target) return;
73
+ const onKeyDown = (event) => {
74
+ const e = event;
75
+ if (e.defaultPrevented || !(0, import_commands.matchPaletteHotkey)(e, hotkey, optionsRef.current.platform)) return;
76
+ e.preventDefault();
77
+ controller.toggle();
78
+ };
79
+ target.addEventListener("keydown", onKeyDown);
80
+ return () => target.removeEventListener("keydown", onKeyDown);
81
+ }, [controller, hotkey, hotkeyTarget]);
82
+ return {
83
+ ...state,
84
+ controller,
85
+ setOpen: controller.setOpen,
86
+ toggle: controller.toggle,
87
+ setQuery: controller.setQuery,
88
+ setActiveIndex: controller.setActiveIndex,
89
+ move: controller.move,
90
+ run: controller.run,
91
+ runActive: controller.runActive,
92
+ handleKeyDown: controller.handleKeyDown
93
+ };
94
+ }
95
+
96
+ // src/commands/CommandPalette.tsx
97
+ var import_react2 = __toESM(require("react"), 1);
98
+ var import_jsx_runtime = require("react/jsx-runtime");
99
+ function HighlightedLabel({ item }) {
100
+ if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: item.label });
101
+ const marked = new Set(item.labelIndices);
102
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: Array.from(item.label).map(
103
+ (ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.default.Fragment, { children: ch }, i)
104
+ ) });
105
+ }
106
+ var CommandPalette = ({
107
+ palette,
108
+ placeholder = "Type a command\u2026",
109
+ emptyMessage = "No matching commands",
110
+ className = ""
111
+ }) => {
112
+ const inputRef = (0, import_react2.useRef)(null);
113
+ const listRef = (0, import_react2.useRef)(null);
114
+ const baseId = (0, import_react2.useId)();
115
+ const listId = `${baseId}-list`;
116
+ const optionId = (index) => `${baseId}-option-${index}`;
117
+ const { open, query, items, activeIndex } = palette;
118
+ (0, import_react2.useEffect)(() => {
119
+ if (open) inputRef.current?.focus();
120
+ }, [open]);
121
+ (0, import_react2.useEffect)(() => {
122
+ if (!open) return;
123
+ const active = listRef.current?.querySelector('[aria-selected="true"]');
124
+ active?.scrollIntoView?.({ block: "nearest" });
125
+ }, [open, activeIndex]);
126
+ if (!open) return null;
127
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
128
+ "div",
129
+ {
130
+ className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
131
+ "data-command-palette-backdrop": "",
132
+ onMouseDown: (e) => {
133
+ if (e.target === e.currentTarget) palette.setOpen(false);
134
+ },
135
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
136
+ "div",
137
+ {
138
+ role: "dialog",
139
+ "aria-modal": "true",
140
+ "aria-label": "Command palette",
141
+ className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
142
+ style: { background: "var(--popover, var(--background, #fff))" },
143
+ children: [
144
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
145
+ "input",
146
+ {
147
+ ref: inputRef,
148
+ type: "text",
149
+ role: "combobox",
150
+ "aria-expanded": "true",
151
+ "aria-controls": listId,
152
+ "aria-autocomplete": "list",
153
+ "aria-activedescendant": items.length ? optionId(activeIndex) : void 0,
154
+ "aria-label": "Search commands",
155
+ placeholder,
156
+ value: query,
157
+ onChange: (e) => palette.setQuery(e.target.value),
158
+ onKeyDown: (e) => {
159
+ if (palette.handleKeyDown(e.nativeEvent)) e.stopPropagation();
160
+ },
161
+ className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
162
+ }
163
+ ),
164
+ items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { ref: listRef, id: listId, role: "listbox", "aria-label": "Commands", className: "max-h-80 overflow-y-auto py-1", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
165
+ "li",
166
+ {
167
+ id: optionId(index),
168
+ role: "option",
169
+ "aria-selected": index === activeIndex,
170
+ "aria-disabled": !item.enabled || void 0,
171
+ "data-command-id": item.id,
172
+ "data-recent": item.recent ? "" : void 0,
173
+ title: item.disabledReason,
174
+ onMouseMove: () => index !== activeIndex && palette.setActiveIndex(index),
175
+ onMouseDown: (e) => e.preventDefault(),
176
+ onClick: () => palette.run(item.id),
177
+ className: `flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm ${index === activeIndex ? "bg-muted" : ""} ${item.enabled ? "" : "cursor-default opacity-50"}`,
178
+ children: [
179
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HighlightedLabel, { item }),
181
+ item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
182
+ ] }),
183
+ item.group && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
184
+ item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
185
+ ]
186
+ },
187
+ item.id
188
+ )) })
189
+ ]
190
+ }
191
+ )
192
+ }
193
+ );
194
+ };
195
+
196
+ // src/commands/useCommandShortcuts.ts
197
+ var import_react3 = require("react");
198
+ function useCommandShortcuts(registry, options = {}) {
199
+ const optionsRef = (0, import_react3.useRef)(options);
200
+ optionsRef.current = options;
201
+ const { enabled = true, target } = options;
202
+ (0, import_react3.useEffect)(() => {
203
+ if (!registry || !enabled) return;
204
+ const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
205
+ if (!eventTarget) return;
206
+ const onKeyDown = (event) => {
207
+ const { scopes, context, allowInEditable, onRun } = optionsRef.current;
208
+ const result = registry.handleKeyDown(event, {
209
+ scopes,
210
+ ...allowInEditable !== void 0 ? { allowInEditable } : {},
211
+ ...context !== void 0 ? { context } : {}
212
+ });
213
+ if (result) onRun?.(result);
214
+ };
215
+ eventTarget.addEventListener("keydown", onKeyDown);
216
+ return () => eventTarget.removeEventListener("keydown", onKeyDown);
217
+ }, [registry, enabled, target]);
218
+ }
219
+ function useRegisterCommands(registry, specs) {
220
+ (0, import_react3.useEffect)(() => {
221
+ if (!registry || !specs || specs.length === 0) return;
222
+ return registry.register(specs);
223
+ }, [registry, specs]);
224
+ }
225
+ // Annotate the CommonJS export names for ESM import in node:
226
+ 0 && (module.exports = {
227
+ CommandPalette,
228
+ useCommandPalette,
229
+ useCommandShortcuts,
230
+ useRegisterCommands
231
+ });
232
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/index.ts","../../src/commands/useCommandPalette.ts","../../src/commands/CommandPalette.tsx","../../src/commands/useCommandShortcuts.ts"],"sourcesContent":["export * from './useCommandPalette';\nexport * from './CommandPalette';\nexport * from './useCommandShortcuts';\n","import { useEffect, useMemo, useRef, useSyncExternalStore } from 'react';\nimport {\n createCommandPaletteController,\n matchPaletteHotkey,\n type CommandPaletteController,\n type CommandPaletteOptions,\n type CommandPaletteState,\n type CommandRegistry,\n} from '@pixerate/editor/commands';\n\nexport interface UseCommandPaletteOptions<TContext = any> extends CommandPaletteOptions<TContext> {\n /** Chord that toggles the palette from anywhere, also while typing (e.g. `Mod+K`). */\n hotkey?: string;\n /** Element or window the hotkey listens on (default: `window`). */\n hotkeyTarget?: Window | HTMLElement | null;\n}\n\nexport interface UseCommandPaletteResult extends CommandPaletteState {\n controller: CommandPaletteController;\n setOpen: (open: boolean) => void;\n toggle: () => void;\n setQuery: (query: string) => void;\n setActiveIndex: (index: number) => void;\n move: (delta: number) => void;\n run: CommandPaletteController['run'];\n runActive: CommandPaletteController['runActive'];\n handleKeyDown: CommandPaletteController['handleKeyDown'];\n}\n\n/**\n * Command palette state over a `CommandRegistry` (ranked rows with shortcuts and\n * disabled reasons, active row, recents). Render it with `<CommandPalette palette={…} />`\n * or your own UI. Options are read live; the registry identity is the dependency.\n */\nexport function useCommandPalette<TContext = any>(\n registry: CommandRegistry<TContext>,\n options: UseCommandPaletteOptions<TContext> = {},\n): UseCommandPaletteResult {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const controller = useMemo(\n () =>\n createCommandPaletteController(registry, {\n context: () => {\n const c = optionsRef.current.context;\n if (c === undefined) return registry.context;\n return (typeof c === 'function' ? (c as () => TContext)() : c) as TContext;\n },\n scope: () => {\n const s = optionsRef.current.scope;\n return typeof s === 'function' ? s() : s;\n },\n recents: options.recents,\n recentLimit: options.recentLimit,\n limit: options.limit,\n platform: options.platform,\n onRecentsChange: (recents) => optionsRef.current.onRecentsChange?.(recents),\n onRun: (result) => optionsRef.current.onRun?.(result),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [registry],\n );\n\n const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);\n\n const { hotkey, hotkeyTarget } = options;\n useEffect(() => {\n if (!hotkey) return;\n const target = hotkeyTarget ?? (typeof window !== 'undefined' ? window : null);\n if (!target) return;\n const onKeyDown = (event: Event) => {\n const e = event as KeyboardEvent;\n if (e.defaultPrevented || !matchPaletteHotkey(e, hotkey, optionsRef.current.platform)) return;\n e.preventDefault();\n controller.toggle();\n };\n target.addEventListener('keydown', onKeyDown);\n return () => target.removeEventListener('keydown', onKeyDown);\n }, [controller, hotkey, hotkeyTarget]);\n\n return {\n ...state,\n controller,\n setOpen: controller.setOpen,\n toggle: controller.toggle,\n setQuery: controller.setQuery,\n setActiveIndex: controller.setActiveIndex,\n move: controller.move,\n run: controller.run,\n runActive: controller.runActive,\n handleKeyDown: controller.handleKeyDown,\n };\n}\n","import React, { useEffect, useId, useRef } from 'react';\nimport type { CommandPaletteItem } from '@pixerate/editor/commands';\nimport type { UseCommandPaletteResult } from './useCommandPalette';\n\nexport interface CommandPaletteProps {\n /** State from `useCommandPalette`. */\n palette: UseCommandPaletteResult;\n placeholder?: string;\n emptyMessage?: string;\n /** Extra classes for the dialog panel. */\n className?: string;\n}\n\n/** Label with the fuzzy-matched characters emphasised. */\nfunction HighlightedLabel({ item }: { item: CommandPaletteItem }) {\n if (item.labelIndices.length === 0) return <>{item.label}</>;\n const marked = new Set(item.labelIndices);\n return (\n <>\n {Array.from(item.label).map((ch, i) =>\n marked.has(i) ? (\n <span key={i} className=\"font-semibold text-foreground\" data-match=\"\">\n {ch}\n </span>\n ) : (\n <React.Fragment key={i}>{ch}</React.Fragment>\n ),\n )}\n </>\n );\n}\n\n/**\n * Headless-styled command palette (Tailwind + theme tokens): a search box over the\n * registry's commands showing each command's group, shortcut and, for disabled\n * commands, the reason. Arrow keys move, Enter runs, Escape or a backdrop click closes.\n */\nexport const CommandPalette: React.FC<CommandPaletteProps> = ({\n palette,\n placeholder = 'Type a command…',\n emptyMessage = 'No matching commands',\n className = '',\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const baseId = useId();\n const listId = `${baseId}-list`;\n const optionId = (index: number) => `${baseId}-option-${index}`;\n const { open, query, items, activeIndex } = palette;\n\n useEffect(() => {\n if (open) inputRef.current?.focus();\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n const active = listRef.current?.querySelector<HTMLElement>('[aria-selected=\"true\"]');\n active?.scrollIntoView?.({ block: 'nearest' });\n }, [open, activeIndex]);\n\n if (!open) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]\"\n data-command-palette-backdrop=\"\"\n onMouseDown={(e) => {\n if (e.target === e.currentTarget) palette.setOpen(false);\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n className={`w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`}\n style={{ background: 'var(--popover, var(--background, #fff))' }}\n >\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={items.length ? optionId(activeIndex) : undefined}\n aria-label=\"Search commands\"\n placeholder={placeholder}\n value={query}\n onChange={(e) => palette.setQuery(e.target.value)}\n onKeyDown={(e) => {\n if (palette.handleKeyDown(e.nativeEvent)) e.stopPropagation();\n }}\n className=\"w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground\"\n />\n {items.length === 0 ? (\n <div className=\"px-3 py-6 text-center text-sm text-muted-foreground\">{emptyMessage}</div>\n ) : (\n <ul ref={listRef} id={listId} role=\"listbox\" aria-label=\"Commands\" className=\"max-h-80 overflow-y-auto py-1\">\n {items.map((item, index) => (\n <li\n key={item.id}\n id={optionId(index)}\n role=\"option\"\n aria-selected={index === activeIndex}\n aria-disabled={!item.enabled || undefined}\n data-command-id={item.id}\n data-recent={item.recent ? '' : undefined}\n title={item.disabledReason}\n onMouseMove={() => index !== activeIndex && palette.setActiveIndex(index)}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => palette.run(item.id)}\n className={`flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm ${\n index === activeIndex ? 'bg-muted' : ''\n } ${item.enabled ? '' : 'cursor-default opacity-50'}`}\n >\n <span className=\"min-w-0 flex-1 truncate\">\n <HighlightedLabel item={item} />\n {item.disabledReason && (\n <span className=\"ml-2 text-xs text-muted-foreground\" data-disabled-reason=\"\">\n {item.disabledReason}\n </span>\n )}\n </span>\n {item.group && <span className=\"shrink-0 text-xs text-muted-foreground\">{item.group}</span>}\n {item.shortcut && (\n <kbd className=\"shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground\">\n {item.shortcut}\n </kbd>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { CommandRegistry, CommandResult, CommandSpec } from '@pixerate/editor/commands';\n\nexport interface UseCommandShortcutsOptions<TContext = any> {\n /** Default `true`. */\n enabled?: boolean;\n /** Element or window to listen on (default: `window`). */\n target?: Window | HTMLElement | null;\n /** Active scopes, most specific first (e.g. `'canvas'` while the canvas has focus). */\n scopes?: string | readonly string[];\n /** Context for the commands (default: the registry's). */\n context?: TContext;\n /** Fire even while typing in inputs / contenteditable (default: per binding). */\n allowInEditable?: boolean;\n /** Called after a shortcut ran a command. */\n onRun?: (result: CommandResult) => void;\n}\n\n/**\n * Runs the registry's commands from their keyboard shortcuts (`registry.handleKeyDown`).\n * Typing in inputs and editors is never hijacked, and disabled commands leave the\n * event alone. Options are read live.\n */\nexport function useCommandShortcuts<TContext = any>(\n registry: CommandRegistry<TContext> | null | undefined,\n options: UseCommandShortcutsOptions<TContext> = {},\n): void {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const { enabled = true, target } = options;\n\n useEffect(() => {\n if (!registry || !enabled) return;\n const eventTarget = target ?? (typeof window !== 'undefined' ? window : null);\n if (!eventTarget) return;\n const onKeyDown = (event: Event) => {\n const { scopes, context, allowInEditable, onRun } = optionsRef.current;\n const result = registry.handleKeyDown(event as KeyboardEvent, {\n scopes,\n ...(allowInEditable !== undefined ? { allowInEditable } : {}),\n ...(context !== undefined ? { context } : {}),\n });\n if (result) onRun?.(result);\n };\n eventTarget.addEventListener('keydown', onKeyDown);\n return () => eventTarget.removeEventListener('keydown', onKeyDown);\n }, [registry, enabled, target]);\n}\n\n/**\n * Registers commands while the component is mounted. Memoize `specs` (e.g. with\n * `useMemo(() => createHistoryCommands(manager), [manager])`): a new array re-registers.\n */\nexport function useRegisterCommands<TContext = any>(\n registry: CommandRegistry<TContext> | null | undefined,\n specs: readonly CommandSpec<TContext>[] | null | undefined,\n): void {\n useEffect(() => {\n if (!registry || !specs || specs.length === 0) return;\n return registry.register(specs);\n }, [registry, specs]);\n}\n"],"mappings":"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","names":["import_react","React","import_react"]}
@@ -0,0 +1,69 @@
1
+ import { CommandPaletteState, CommandPaletteController, CommandPaletteOptions, CommandRegistry, CommandResult, CommandSpec } from '@pixerate/editor/commands';
2
+ import React__default from 'react';
3
+
4
+ interface UseCommandPaletteOptions<TContext = any> extends CommandPaletteOptions<TContext> {
5
+ /** Chord that toggles the palette from anywhere, also while typing (e.g. `Mod+K`). */
6
+ hotkey?: string;
7
+ /** Element or window the hotkey listens on (default: `window`). */
8
+ hotkeyTarget?: Window | HTMLElement | null;
9
+ }
10
+ interface UseCommandPaletteResult extends CommandPaletteState {
11
+ controller: CommandPaletteController;
12
+ setOpen: (open: boolean) => void;
13
+ toggle: () => void;
14
+ setQuery: (query: string) => void;
15
+ setActiveIndex: (index: number) => void;
16
+ move: (delta: number) => void;
17
+ run: CommandPaletteController['run'];
18
+ runActive: CommandPaletteController['runActive'];
19
+ handleKeyDown: CommandPaletteController['handleKeyDown'];
20
+ }
21
+ /**
22
+ * Command palette state over a `CommandRegistry` (ranked rows with shortcuts and
23
+ * disabled reasons, active row, recents). Render it with `<CommandPalette palette={…} />`
24
+ * or your own UI. Options are read live; the registry identity is the dependency.
25
+ */
26
+ declare function useCommandPalette<TContext = any>(registry: CommandRegistry<TContext>, options?: UseCommandPaletteOptions<TContext>): UseCommandPaletteResult;
27
+
28
+ interface CommandPaletteProps {
29
+ /** State from `useCommandPalette`. */
30
+ palette: UseCommandPaletteResult;
31
+ placeholder?: string;
32
+ emptyMessage?: string;
33
+ /** Extra classes for the dialog panel. */
34
+ className?: string;
35
+ }
36
+ /**
37
+ * Headless-styled command palette (Tailwind + theme tokens): a search box over the
38
+ * registry's commands showing each command's group, shortcut and, for disabled
39
+ * commands, the reason. Arrow keys move, Enter runs, Escape or a backdrop click closes.
40
+ */
41
+ declare const CommandPalette: React__default.FC<CommandPaletteProps>;
42
+
43
+ interface UseCommandShortcutsOptions<TContext = any> {
44
+ /** Default `true`. */
45
+ enabled?: boolean;
46
+ /** Element or window to listen on (default: `window`). */
47
+ target?: Window | HTMLElement | null;
48
+ /** Active scopes, most specific first (e.g. `'canvas'` while the canvas has focus). */
49
+ scopes?: string | readonly string[];
50
+ /** Context for the commands (default: the registry's). */
51
+ context?: TContext;
52
+ /** Fire even while typing in inputs / contenteditable (default: per binding). */
53
+ allowInEditable?: boolean;
54
+ /** Called after a shortcut ran a command. */
55
+ onRun?: (result: CommandResult) => void;
56
+ }
57
+ /**
58
+ * Runs the registry's commands from their keyboard shortcuts (`registry.handleKeyDown`).
59
+ * Typing in inputs and editors is never hijacked, and disabled commands leave the
60
+ * event alone. Options are read live.
61
+ */
62
+ declare function useCommandShortcuts<TContext = any>(registry: CommandRegistry<TContext> | null | undefined, options?: UseCommandShortcutsOptions<TContext>): void;
63
+ /**
64
+ * Registers commands while the component is mounted. Memoize `specs` (e.g. with
65
+ * `useMemo(() => createHistoryCommands(manager), [manager])`): a new array re-registers.
66
+ */
67
+ declare function useRegisterCommands<TContext = any>(registry: CommandRegistry<TContext> | null | undefined, specs: readonly CommandSpec<TContext>[] | null | undefined): void;
68
+
69
+ export { CommandPalette, type CommandPaletteProps, type UseCommandPaletteOptions, type UseCommandPaletteResult, type UseCommandShortcutsOptions, useCommandPalette, useCommandShortcuts, useRegisterCommands };
@@ -0,0 +1,69 @@
1
+ import { CommandPaletteState, CommandPaletteController, CommandPaletteOptions, CommandRegistry, CommandResult, CommandSpec } from '@pixerate/editor/commands';
2
+ import React__default from 'react';
3
+
4
+ interface UseCommandPaletteOptions<TContext = any> extends CommandPaletteOptions<TContext> {
5
+ /** Chord that toggles the palette from anywhere, also while typing (e.g. `Mod+K`). */
6
+ hotkey?: string;
7
+ /** Element or window the hotkey listens on (default: `window`). */
8
+ hotkeyTarget?: Window | HTMLElement | null;
9
+ }
10
+ interface UseCommandPaletteResult extends CommandPaletteState {
11
+ controller: CommandPaletteController;
12
+ setOpen: (open: boolean) => void;
13
+ toggle: () => void;
14
+ setQuery: (query: string) => void;
15
+ setActiveIndex: (index: number) => void;
16
+ move: (delta: number) => void;
17
+ run: CommandPaletteController['run'];
18
+ runActive: CommandPaletteController['runActive'];
19
+ handleKeyDown: CommandPaletteController['handleKeyDown'];
20
+ }
21
+ /**
22
+ * Command palette state over a `CommandRegistry` (ranked rows with shortcuts and
23
+ * disabled reasons, active row, recents). Render it with `<CommandPalette palette={…} />`
24
+ * or your own UI. Options are read live; the registry identity is the dependency.
25
+ */
26
+ declare function useCommandPalette<TContext = any>(registry: CommandRegistry<TContext>, options?: UseCommandPaletteOptions<TContext>): UseCommandPaletteResult;
27
+
28
+ interface CommandPaletteProps {
29
+ /** State from `useCommandPalette`. */
30
+ palette: UseCommandPaletteResult;
31
+ placeholder?: string;
32
+ emptyMessage?: string;
33
+ /** Extra classes for the dialog panel. */
34
+ className?: string;
35
+ }
36
+ /**
37
+ * Headless-styled command palette (Tailwind + theme tokens): a search box over the
38
+ * registry's commands showing each command's group, shortcut and, for disabled
39
+ * commands, the reason. Arrow keys move, Enter runs, Escape or a backdrop click closes.
40
+ */
41
+ declare const CommandPalette: React__default.FC<CommandPaletteProps>;
42
+
43
+ interface UseCommandShortcutsOptions<TContext = any> {
44
+ /** Default `true`. */
45
+ enabled?: boolean;
46
+ /** Element or window to listen on (default: `window`). */
47
+ target?: Window | HTMLElement | null;
48
+ /** Active scopes, most specific first (e.g. `'canvas'` while the canvas has focus). */
49
+ scopes?: string | readonly string[];
50
+ /** Context for the commands (default: the registry's). */
51
+ context?: TContext;
52
+ /** Fire even while typing in inputs / contenteditable (default: per binding). */
53
+ allowInEditable?: boolean;
54
+ /** Called after a shortcut ran a command. */
55
+ onRun?: (result: CommandResult) => void;
56
+ }
57
+ /**
58
+ * Runs the registry's commands from their keyboard shortcuts (`registry.handleKeyDown`).
59
+ * Typing in inputs and editors is never hijacked, and disabled commands leave the
60
+ * event alone. Options are read live.
61
+ */
62
+ declare function useCommandShortcuts<TContext = any>(registry: CommandRegistry<TContext> | null | undefined, options?: UseCommandShortcutsOptions<TContext>): void;
63
+ /**
64
+ * Registers commands while the component is mounted. Memoize `specs` (e.g. with
65
+ * `useMemo(() => createHistoryCommands(manager), [manager])`): a new array re-registers.
66
+ */
67
+ declare function useRegisterCommands<TContext = any>(registry: CommandRegistry<TContext> | null | undefined, specs: readonly CommandSpec<TContext>[] | null | undefined): void;
68
+
69
+ export { CommandPalette, type CommandPaletteProps, type UseCommandPaletteOptions, type UseCommandPaletteResult, type UseCommandShortcutsOptions, useCommandPalette, useCommandShortcuts, useRegisterCommands };
@@ -0,0 +1,13 @@
1
+ import {
2
+ CommandPalette,
3
+ useCommandPalette,
4
+ useCommandShortcuts,
5
+ useRegisterCommands
6
+ } from "../chunk-4ZC2WCUO.js";
7
+ export {
8
+ CommandPalette,
9
+ useCommandPalette,
10
+ useCommandShortcuts,
11
+ useRegisterCommands
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/generation/index.ts
21
+ var generation_exports = {};
22
+ __export(generation_exports, {
23
+ GenerationSettings: () => GenerationSettings,
24
+ JobProgress: () => JobProgress,
25
+ useGenerationPlan: () => useGenerationPlan,
26
+ useJobProgress: () => useJobProgress
27
+ });
28
+ module.exports = __toCommonJS(generation_exports);
29
+
30
+ // src/generation/useGenerationPlan.ts
31
+ var import_react = require("react");
32
+ var import_generation = require("@pixerate/editor/generation");
33
+ function useGenerationPlan(request, capabilities, options = {}) {
34
+ const key = JSON.stringify([request, capabilities, options]);
35
+ return (0, import_react.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
36
+ }
37
+ function useJobProgress(options) {
38
+ const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
39
+ const [tick, setTick] = (0, import_react.useState)(() => Date.now());
40
+ const ticking = !done && now === void 0;
41
+ (0, import_react.useEffect)(() => {
42
+ if (!ticking) return;
43
+ setTick(Date.now());
44
+ const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
45
+ return () => clearInterval(id);
46
+ }, [ticking, intervalMs]);
47
+ return (0, import_generation.estimateJobProgress)({ startedAt, expectedMs, done, now: now ?? tick });
48
+ }
49
+
50
+ // src/generation/GenerationSettings.tsx
51
+ var import_react2 = require("react");
52
+ var import_generation2 = require("@pixerate/editor/generation");
53
+ var import_jsx_runtime = require("react/jsx-runtime");
54
+ var inputClass = "w-full rounded-md border border-border bg-background px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring";
55
+ function Control({
56
+ control,
57
+ value,
58
+ id,
59
+ onValue
60
+ }) {
61
+ const shown = value ?? control.defaultValue;
62
+ if (control.kind === "checkbox") {
63
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
64
+ "input",
65
+ {
66
+ id,
67
+ type: "checkbox",
68
+ "data-field": control.key,
69
+ checked: Boolean(shown),
70
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.checked))
71
+ }
72
+ );
73
+ }
74
+ if (control.kind === "select") {
75
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
76
+ "select",
77
+ {
78
+ id,
79
+ "data-field": control.key,
80
+ className: inputClass,
81
+ value: shown === void 0 ? "" : String(shown),
82
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
83
+ children: [
84
+ shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "Default" }),
85
+ control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
86
+ ]
87
+ }
88
+ );
89
+ }
90
+ if (control.kind === "textarea") {
91
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
92
+ "textarea",
93
+ {
94
+ id,
95
+ "data-field": control.key,
96
+ className: inputClass,
97
+ rows: 2,
98
+ maxLength: control.maxLength,
99
+ value: typeof value === "string" ? value : "",
100
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
101
+ }
102
+ );
103
+ }
104
+ const numeric = typeof shown === "number" ? shown : void 0;
105
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
106
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
107
+ "input",
108
+ {
109
+ id,
110
+ type: control.kind === "range" ? "range" : "number",
111
+ "data-field": control.key,
112
+ className: control.kind === "range" ? "flex-1" : inputClass,
113
+ min: control.min,
114
+ max: control.max,
115
+ step: control.step ?? "any",
116
+ value: numeric ?? (control.kind === "range" ? control.min ?? 0 : ""),
117
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
118
+ }
119
+ ),
120
+ control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
121
+ ] });
122
+ }
123
+ var GenerationSettings = ({
124
+ capabilities,
125
+ value,
126
+ onChange,
127
+ plan: planProp,
128
+ strategy,
129
+ showAdjustments = true,
130
+ onAddReference,
131
+ renderReference,
132
+ className = ""
133
+ }) => {
134
+ const baseId = (0, import_react2.useId)();
135
+ const controls = (0, import_react2.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
136
+ const computed = useGenerationPlan(value, capabilities, { strategy });
137
+ const plan = planProp ?? computed;
138
+ const slots = (0, import_generation2.getReferenceSlots)(capabilities, value);
139
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
140
+ controls.map((control) => {
141
+ const id = `${baseId}-${control.key}`;
142
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
143
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
144
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
145
+ Control,
146
+ {
147
+ control,
148
+ id,
149
+ value: (0, import_generation2.getRequestValue)(value, control.key),
150
+ onValue: (next) => onChange((0, import_generation2.setRequestValue)(value, control.key, next))
151
+ }
152
+ )
153
+ ] }, control.key);
154
+ }),
155
+ slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
157
+ slot.label,
158
+ " ",
159
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
160
+ "(",
161
+ slot.references.length,
162
+ "/",
163
+ slot.max,
164
+ ")"
165
+ ] }),
166
+ slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-destructive", children: " *" })
167
+ ] }),
168
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
169
+ slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
170
+ renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
171
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
172
+ "button",
173
+ {
174
+ type: "button",
175
+ "aria-label": `Remove ${slot.label} ${ref.id}`,
176
+ className: "text-muted-foreground hover:text-foreground",
177
+ onClick: () => onChange((0, import_generation2.removeReference)(value, slot.role, ref.id)),
178
+ children: "\xD7"
179
+ }
180
+ )
181
+ ] }, ref.id)),
182
+ onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
183
+ "button",
184
+ {
185
+ type: "button",
186
+ className: "rounded border border-dashed border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground",
187
+ onClick: () => onAddReference(slot.role),
188
+ children: "Add"
189
+ }
190
+ ) })
191
+ ] })
192
+ ] }, slot.role)),
193
+ showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { role: "status", className: "flex flex-col gap-0.5 text-xs text-muted-foreground", "data-generation-adjustments": "", children: plan.adjustments.map((adjustment, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
194
+ showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { role: "alert", className: "flex flex-col gap-0.5 text-xs text-destructive", "data-generation-errors": "", children: plan.errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
195
+ ] });
196
+ };
197
+
198
+ // src/generation/JobProgress.tsx
199
+ var import_jsx_runtime2 = require("react/jsx-runtime");
200
+ var JobProgress = ({ title, className = "", ...options }) => {
201
+ const progress = useJobProgress(options);
202
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
203
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
204
+ title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate text-foreground", children: title }),
205
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
206
+ ] }),
207
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
208
+ "div",
209
+ {
210
+ role: "progressbar",
211
+ "aria-label": title ?? "Generation progress",
212
+ "aria-valuemin": 0,
213
+ "aria-valuemax": 100,
214
+ "aria-valuenow": progress.percent,
215
+ "aria-valuetext": `${progress.percent}%, ${progress.label}`,
216
+ className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
217
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
218
+ "div",
219
+ {
220
+ className: "h-full rounded-full bg-primary transition-[width] duration-500",
221
+ style: { width: `${progress.percent}%`, background: "var(--primary, currentColor)" }
222
+ }
223
+ )
224
+ }
225
+ )
226
+ ] });
227
+ };
228
+ // Annotate the CommonJS export names for ESM import in node:
229
+ 0 && (module.exports = {
230
+ GenerationSettings,
231
+ JobProgress,
232
+ useGenerationPlan,
233
+ useJobProgress
234
+ });
235
+ //# sourceMappingURL=index.cjs.map