@hilum/designer 2.0.2 → 2.0.4

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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Dispatch, SetStateAction, ReactNode, ComponentType } from 'react';
2
+ import { Dispatch, SetStateAction, ReactNode, ComponentType, ComponentPropsWithoutRef } from 'react';
3
3
 
4
4
  /**
5
5
  * The minimal contract a designer shell needs from the engine beneath it.
@@ -153,6 +153,30 @@ declare function DesignerPane({ showFor, collapsible, defaultOpen, className, ch
153
153
  declare function DesignerPaneTitle({ className, children, action }: DesignerPaneTitleProps): react_jsx_runtime.JSX.Element;
154
154
  declare function DesignerPaneContent({ className, children }: DesignerPaneContentProps): react_jsx_runtime.JSX.Element | null;
155
155
 
156
+ interface DesignerPropertyRowProps extends ComponentPropsWithoutRef<"div"> {
157
+ /** Optional label for direct row usage. Compound usage can use DesignerPropertyLabel. */
158
+ label?: ReactNode;
159
+ /** htmlFor forwarded to the generated label when label is provided. */
160
+ labelFor?: string;
161
+ /** Class name for the generated controls container when label is provided. */
162
+ controlsClassName?: string;
163
+ children: ReactNode;
164
+ }
165
+ interface DesignerPropertyLabelProps extends ComponentPropsWithoutRef<"label"> {
166
+ children: ReactNode;
167
+ }
168
+ interface DesignerPropertyControlsProps extends ComponentPropsWithoutRef<"div"> {
169
+ children: ReactNode;
170
+ }
171
+ interface DesignerPropertyGroupProps extends Omit<ComponentPropsWithoutRef<"div">, "title"> {
172
+ title?: ReactNode;
173
+ children: ReactNode;
174
+ }
175
+ declare function DesignerPropertyRow({ label, labelFor, controlsClassName, className, children, ...rest }: DesignerPropertyRowProps): react_jsx_runtime.JSX.Element;
176
+ declare function DesignerPropertyLabel({ className, children, ...rest }: DesignerPropertyLabelProps): react_jsx_runtime.JSX.Element;
177
+ declare function DesignerPropertyControls({ className, children, ...rest }: DesignerPropertyControlsProps): react_jsx_runtime.JSX.Element;
178
+ declare function DesignerPropertyGroup({ title, className, children, ...rest }: DesignerPropertyGroupProps): react_jsx_runtime.JSX.Element;
179
+
156
180
  interface DesignerToolbarProps {
157
181
  className?: string;
158
182
  /** Position. Default: 'floating' (centered, floating above content). */
@@ -250,4 +274,4 @@ interface UseKeybindingsOptions {
250
274
  */
251
275
  declare function useKeybindings(bindings: KeybindingConfig[], { disabled, target }?: UseKeybindingsOptions): void;
252
276
 
253
- export { DesignerHeader, type DesignerHeaderProps, DesignerPane, DesignerPaneContent, type DesignerPaneContentProps, type DesignerPaneProps, DesignerPaneTitle, type DesignerPaneTitleProps, DesignerPanel, type DesignerPanelProps, DesignerShell, type DesignerShellProps, DesignerSidebar, type DesignerSidebarProps, DesignerToolbar, DesignerToolbarButton, type DesignerToolbarButtonProps, DesignerToolbarGroup, type DesignerToolbarGroupProps, type DesignerToolbarProps, DesignerToolbarSeparator, type DesignerToolbarSeparatorProps, type KeybindingConfig, type ShellContextValue, ShellProvider, type SidebarItem, useHistory, useKeybindings, useShellContext };
277
+ export { DesignerHeader, type DesignerHeaderProps, DesignerPane, DesignerPaneContent, type DesignerPaneContentProps, type DesignerPaneProps, DesignerPaneTitle, type DesignerPaneTitleProps, DesignerPanel, type DesignerPanelProps, DesignerPropertyControls, type DesignerPropertyControlsProps, DesignerPropertyGroup, type DesignerPropertyGroupProps, DesignerPropertyLabel, type DesignerPropertyLabelProps, DesignerPropertyRow, type DesignerPropertyRowProps, DesignerShell, type DesignerShellProps, DesignerSidebar, type DesignerSidebarProps, DesignerToolbar, DesignerToolbarButton, type DesignerToolbarButtonProps, DesignerToolbarGroup, type DesignerToolbarGroupProps, type DesignerToolbarProps, DesignerToolbarSeparator, type DesignerToolbarSeparatorProps, type KeybindingConfig, type ShellContextValue, ShellProvider, type SidebarItem, useHistory, useKeybindings, useShellContext };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createContext, useContext, useState, useMemo, useCallback, useEffect } from 'react';
2
- import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { cn, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '@hilum/ui';
4
4
  import { ChevronDown } from 'lucide-react';
5
5
 
@@ -163,7 +163,16 @@ function DesignerPane({
163
163
  }
164
164
  }
165
165
  if (!visible) return null;
166
- return /* @__PURE__ */ jsx(PaneContext.Provider, { value: { open, toggle: () => setOpen((v) => !v), collapsible }, children: /* @__PURE__ */ jsx("section", { className: cn("flex flex-col border-b border-border last:border-b-0", className), children }) });
166
+ return /* @__PURE__ */ jsx(PaneContext.Provider, { value: { open, toggle: () => setOpen((v) => !v), collapsible }, children: /* @__PURE__ */ jsx(
167
+ "section",
168
+ {
169
+ className: cn(
170
+ "flex min-w-0 max-w-full flex-col overflow-x-hidden border-b border-border last:border-b-0",
171
+ className
172
+ ),
173
+ children
174
+ }
175
+ ) });
167
176
  }
168
177
  function DesignerPaneTitle({ className, children, action }) {
169
178
  const { open, toggle, collapsible } = usePaneContext();
@@ -198,13 +207,97 @@ function DesignerPaneTitle({ className, children, action }) {
198
207
  function DesignerPaneContent({ className, children }) {
199
208
  const { open } = usePaneContext();
200
209
  if (!open) return null;
201
- return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-2 px-3 pb-3", className), children });
210
+ return /* @__PURE__ */ jsx(
211
+ "div",
212
+ {
213
+ className: cn(
214
+ "flex min-w-0 max-w-full flex-col gap-2 overflow-x-hidden px-3 pb-3",
215
+ className
216
+ ),
217
+ children
218
+ }
219
+ );
202
220
  }
203
221
  var PaneContext = createContext({ open: true, toggle: () => {
204
222
  }, collapsible: false });
205
223
  function usePaneContext() {
206
224
  return useContext(PaneContext);
207
225
  }
226
+ function DesignerPropertyRow({
227
+ label,
228
+ labelFor,
229
+ controlsClassName,
230
+ className,
231
+ children,
232
+ ...rest
233
+ }) {
234
+ return /* @__PURE__ */ jsx(
235
+ "div",
236
+ {
237
+ className: cn(
238
+ "flex w-full min-w-0 max-w-full flex-col items-stretch gap-1.5 py-1.5",
239
+ className
240
+ ),
241
+ ...rest,
242
+ children: label === void 0 ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
243
+ /* @__PURE__ */ jsx(DesignerPropertyLabel, { htmlFor: labelFor, children: label }),
244
+ /* @__PURE__ */ jsx(DesignerPropertyControls, { className: controlsClassName, children })
245
+ ] })
246
+ }
247
+ );
248
+ }
249
+ function DesignerPropertyLabel({
250
+ className,
251
+ children,
252
+ ...rest
253
+ }) {
254
+ return /* @__PURE__ */ jsx(
255
+ "label",
256
+ {
257
+ className: cn(
258
+ "caption w-full min-w-0 max-w-full select-none text-muted-foreground",
259
+ className
260
+ ),
261
+ ...rest,
262
+ children
263
+ }
264
+ );
265
+ }
266
+ function DesignerPropertyControls({
267
+ className,
268
+ children,
269
+ ...rest
270
+ }) {
271
+ return /* @__PURE__ */ jsx(
272
+ "div",
273
+ {
274
+ className: cn(
275
+ "flex w-full min-w-0 max-w-full flex-1 items-center gap-2 overflow-visible",
276
+ className
277
+ ),
278
+ ...rest,
279
+ children
280
+ }
281
+ );
282
+ }
283
+ function DesignerPropertyGroup({
284
+ title,
285
+ className,
286
+ children,
287
+ ...rest
288
+ }) {
289
+ return /* @__PURE__ */ jsxs(
290
+ "div",
291
+ {
292
+ className: cn("flex min-w-0 max-w-full flex-col gap-3", className),
293
+ ...rest,
294
+ children: [
295
+ title && /* @__PURE__ */ jsx("div", { className: "caption-xs min-w-0 max-w-full select-none overflow-hidden text-ellipsis uppercase tracking-wider text-muted-foreground", children: title }),
296
+ children
297
+ ]
298
+ }
299
+ );
300
+ }
208
301
  function DesignerToolbar({ className, variant = "floating", children }) {
209
302
  return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(
210
303
  "div",
@@ -355,6 +448,6 @@ function useKeybindings(bindings, { disabled, target } = {}) {
355
448
  }, [bindings, disabled, target]);
356
449
  }
357
450
 
358
- export { DesignerHeader, DesignerPane, DesignerPaneContent, DesignerPaneTitle, DesignerPanel, DesignerShell, DesignerSidebar, DesignerToolbar, DesignerToolbarButton, DesignerToolbarGroup, DesignerToolbarSeparator, ShellProvider, useHistory, useKeybindings, useShellContext };
451
+ export { DesignerHeader, DesignerPane, DesignerPaneContent, DesignerPaneTitle, DesignerPanel, DesignerPropertyControls, DesignerPropertyGroup, DesignerPropertyLabel, DesignerPropertyRow, DesignerShell, DesignerSidebar, DesignerToolbar, DesignerToolbarButton, DesignerToolbarGroup, DesignerToolbarSeparator, ShellProvider, useHistory, useKeybindings, useShellContext };
359
452
  //# sourceMappingURL=index.js.map
360
453
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/ShellContext.tsx","../src/components/DesignerShell.tsx","../src/components/DesignerHeader.tsx","../src/components/DesignerSidebar.tsx","../src/components/DesignerPanel.tsx","../src/components/DesignerPane.tsx","../src/components/DesignerToolbar.tsx","../src/hooks/useHistory.ts","../src/hooks/useKeybindings.ts"],"names":["jsx","cn","jsxs","useState","createContext","useContext","TooltipProvider","Tooltip","TooltipTrigger","TooltipContent"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext, useMemo, useState } from \"react\";\nimport type { Dispatch, ReactNode, SetStateAction } from \"react\";\n\n/**\n * The minimal contract a designer shell needs from the engine beneath it.\n *\n * The chrome (toolbar, panel, pane, sidebar) reads from this context.\n * It does NOT know what is being edited — selection IDs are opaque strings\n * (layer IDs, field IDs, node IDs — whatever the engine uses), and active\n * tool is an open string the app defines (`select`, `hand`, `text`, …).\n *\n * @hilum/designer-canvas wires this up for canvas apps. A form-builder app\n * could wire its own engine to ShellContext with the same primitives.\n */\nexport interface ShellContextValue {\n /** IDs of currently-selected items. Engine-defined meaning. */\n selectedIds: string[];\n setSelectedIds: Dispatch<SetStateAction<string[]>>;\n\n /** Active tool. App-defined enum (e.g. 'select' | 'hand' | 'text'). */\n activeTool: string;\n setActiveTool: Dispatch<SetStateAction<string>>;\n\n /** When true, mutating actions should no-op. Used for previews. */\n readOnly: boolean;\n\n /**\n * Optional resolver: given a `selectedId`, return its engine-defined \"kind\"\n * (e.g. 'text', 'image'). DesignerPane.showFor uses this to decide whether\n * to render. Apps that don't have typed selections can leave this undefined.\n */\n resolveKind?: (id: string) => string | undefined;\n}\n\nconst noop = () => {};\n\nconst DEFAULT: ShellContextValue = {\n selectedIds: [],\n setSelectedIds: noop as Dispatch<SetStateAction<string[]>>,\n activeTool: \"select\",\n setActiveTool: noop as Dispatch<SetStateAction<string>>,\n readOnly: false,\n};\n\nconst ShellContext = createContext<ShellContextValue>(DEFAULT);\n\nexport function useShellContext(): ShellContextValue {\n return useContext(ShellContext);\n}\n\ninterface ShellProviderProps {\n /** Initial selected IDs. Default: []. */\n initialSelectedIds?: string[];\n /** Initial active tool. Default: 'select'. */\n initialTool?: string;\n /** Read-only flag. */\n readOnly?: boolean;\n /** Kind resolver — see ShellContextValue.resolveKind. */\n resolveKind?: (id: string) => string | undefined;\n /** Controlled override — pass a value to lift state out of the provider. */\n value?: Partial<ShellContextValue>;\n children: ReactNode;\n}\n\nexport function ShellProvider({\n initialSelectedIds = [],\n initialTool = \"select\",\n readOnly = false,\n resolveKind,\n value: controlled,\n children,\n}: ShellProviderProps) {\n const [selectedIds, setSelectedIds] = useState<string[]>(initialSelectedIds);\n const [activeTool, setActiveTool] = useState<string>(initialTool);\n\n const resolvedKind = controlled?.resolveKind ?? resolveKind;\n\n const value = useMemo<ShellContextValue>(\n () => ({\n selectedIds: controlled?.selectedIds ?? selectedIds,\n setSelectedIds: controlled?.setSelectedIds ?? setSelectedIds,\n activeTool: controlled?.activeTool ?? activeTool,\n setActiveTool: controlled?.setActiveTool ?? setActiveTool,\n readOnly: controlled?.readOnly ?? readOnly,\n ...(resolvedKind !== undefined && { resolveKind: resolvedKind }),\n }),\n [selectedIds, activeTool, readOnly, resolvedKind, controlled],\n );\n\n return <ShellContext.Provider value={value}>{children}</ShellContext.Provider>;\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@hilum/ui\";\n\ninterface DesignerShellProps {\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Root layout for an editor app — full viewport, themed surface.\n * Place a <DesignerHeader>, <DesignerSidebar>, <DesignerPanel>, and the\n * canvas content as children.\n */\nfunction DesignerShell({ className, children }: DesignerShellProps) {\n return (\n <div\n className={cn(\n \"flex flex-col h-screen w-screen overflow-hidden bg-muted text-foreground\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nexport { DesignerShell };\nexport type { DesignerShellProps };\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@hilum/ui\";\n\ninterface DesignerHeaderProps {\n /** Left-aligned content — file name, breadcrumbs, project switcher. */\n left?: ReactNode;\n /** Center content — typically the active document title. */\n center?: ReactNode;\n /** Right-aligned content — share, export, presence, account. */\n right?: ReactNode;\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Top bar of an editor app. Slot-driven — the chrome doesn't know what\n * goes in each region. Use <DesignerHeader left={...} center={...} right={...} />.\n */\nfunction DesignerHeader({ left, center, right, className, children }: DesignerHeaderProps) {\n return (\n <header\n className={cn(\n \"flex h-12 items-center justify-between gap-3 border-b border-border bg-card px-3 shrink-0\",\n className,\n )}\n >\n <div className=\"flex items-center gap-2 min-w-0\">{left}</div>\n {center && <div className=\"flex items-center gap-2 min-w-0\">{center}</div>}\n <div className=\"flex items-center gap-2 min-w-0\">{right}</div>\n {children}\n </header>\n );\n}\n\nexport { DesignerHeader };\nexport type { DesignerHeaderProps };\n","import type { ComponentType, ReactNode } from \"react\";\nimport { cn, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@hilum/ui\";\n\ninterface SidebarItem {\n id: string;\n label: string;\n icon: ComponentType<{ size?: number; className?: string }>;\n onClick?: () => void;\n /** Caller-computed active flag. */\n active?: boolean;\n disabled?: boolean;\n badge?: ReactNode;\n}\n\ninterface DesignerSidebarProps {\n /** Top group of icon buttons. */\n items: SidebarItem[];\n /** Optional bottom group (settings, help, account). */\n bottomItems?: SidebarItem[];\n side?: \"left\" | \"right\";\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Vertical icon rail used as the primary tool / navigation column in an\n * editor. Driven by an `items` array — no engine coupling. Each item gets\n * a tooltip showing its label.\n */\nfunction DesignerSidebar({\n items,\n bottomItems,\n side = \"left\",\n className,\n children,\n}: DesignerSidebarProps) {\n return (\n <aside\n className={cn(\n \"flex flex-col w-12 bg-card shrink-0\",\n side === \"left\" ? \"border-r\" : \"border-l\",\n \"border-border\",\n className,\n )}\n >\n <TooltipProvider>\n <div className=\"flex flex-col items-center gap-0.5 p-1.5\">\n {items.map((item) => (\n <SidebarButton key={item.id} item={item} />\n ))}\n </div>\n\n {children}\n\n {bottomItems && bottomItems.length > 0 && (\n <div className=\"mt-auto flex flex-col items-center gap-0.5 p-1.5\">\n {bottomItems.map((item) => (\n <SidebarButton key={item.id} item={item} />\n ))}\n </div>\n )}\n </TooltipProvider>\n </aside>\n );\n}\n\nfunction SidebarButton({ item }: { item: SidebarItem }) {\n const Icon = item.icon;\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={item.onClick}\n disabled={item.disabled}\n aria-label={item.label}\n aria-pressed={item.active}\n className={cn(\n \"relative flex size-9 items-center justify-center rounded-md transition-colors\",\n item.active\n ? \"bg-foreground text-background\"\n : \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n item.disabled && \"opacity-50 cursor-not-allowed\",\n )}\n >\n <Icon size={16} />\n {item.badge != null && (\n <span className=\"absolute -top-0.5 -right-0.5 caption-xs\">{item.badge}</span>\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{item.label}</TooltipContent>\n </Tooltip>\n );\n}\n\nexport { DesignerSidebar };\nexport type { DesignerSidebarProps, SidebarItem };\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@hilum/ui\";\n\ninterface DesignerPanelProps {\n side: \"left\" | \"right\";\n /** Width in pixels. Default: 240. */\n width?: number;\n /** Add a separator border on the inner edge. Default: true. */\n bordered?: boolean;\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Left or right side panel of an editor — typically holds layer lists,\n * inspector / properties, history, comments, etc. Static-width for v1.\n * (Resize handles arrive in a later iteration if needed.)\n */\nfunction DesignerPanel({\n side,\n width = 240,\n bordered = true,\n className,\n children,\n}: DesignerPanelProps) {\n return (\n <aside\n className={cn(\n \"flex min-w-0 max-w-full shrink-0 flex-col overflow-hidden bg-card\",\n bordered && (side === \"left\" ? \"border-r\" : \"border-l\"),\n bordered && \"border-border\",\n className,\n )}\n style={{ width, maxWidth: \"100%\" }}\n >\n <div className=\"flex min-w-0 flex-1 flex-col overflow-x-hidden overflow-y-auto\">\n {children}\n </div>\n </aside>\n );\n}\n\nexport { DesignerPanel };\nexport type { DesignerPanelProps };\n","import { useState, type ReactNode } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { cn } from \"@hilum/ui\";\nimport { useShellContext } from \"../shell/ShellContext\";\n\ninterface DesignerPaneProps {\n /**\n * Predicate or list of allowed kinds. The pane renders only when matched.\n *\n * - `string[]`: render when at least one selected ID resolves to one of\n * these kinds (requires `ShellContext.resolveKind`).\n * - `(selectedIds: string[]) => boolean`: full predicate.\n * - omitted: always render.\n */\n showFor?: string[] | ((selectedIds: string[]) => boolean);\n collapsible?: boolean;\n defaultOpen?: boolean;\n className?: string;\n children: ReactNode;\n}\n\ninterface DesignerPaneTitleProps {\n className?: string;\n children: ReactNode;\n /** Right-aligned action / control. */\n action?: ReactNode;\n}\n\ninterface DesignerPaneContentProps {\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Collapsible inspector section. Use inside a <DesignerPanel>.\n *\n * <DesignerPane showFor={[\"text\"]} collapsible>\n * <DesignerPaneTitle>Typography</DesignerPaneTitle>\n * <DesignerPaneContent>...</DesignerPaneContent>\n * </DesignerPane>\n */\nfunction DesignerPane({\n showFor,\n collapsible = false,\n defaultOpen = true,\n className,\n children,\n}: DesignerPaneProps) {\n const { selectedIds, resolveKind } = useShellContext();\n const [open, setOpen] = useState(defaultOpen);\n\n // Visibility check.\n let visible = true;\n if (typeof showFor === \"function\") {\n visible = showFor(selectedIds);\n } else if (Array.isArray(showFor)) {\n if (!resolveKind) {\n // No resolver: best effort — show only if any IDs are selected.\n visible = selectedIds.length > 0;\n } else {\n visible = selectedIds.some((id) => {\n const kind = resolveKind(id);\n return kind != null && showFor.includes(kind);\n });\n }\n }\n if (!visible) return null;\n\n return (\n <PaneContext.Provider value={{ open, toggle: () => setOpen((v) => !v), collapsible }}>\n <section className={cn(\"flex flex-col border-b border-border last:border-b-0\", className)}>\n {children}\n </section>\n </PaneContext.Provider>\n );\n}\n\nfunction DesignerPaneTitle({ className, children, action }: DesignerPaneTitleProps) {\n const { open, toggle, collapsible } = usePaneContext();\n\n const Tag = collapsible ? \"button\" : \"div\";\n return (\n <Tag\n type={collapsible ? \"button\" : undefined}\n onClick={collapsible ? toggle : undefined}\n className={cn(\n \"flex w-full items-center justify-between gap-2 px-3 py-2 text-left\",\n \"caption-xs uppercase tracking-wider font-semibold text-muted-foreground\",\n collapsible && \"hover:text-foreground transition-colors\",\n className,\n )}\n >\n <span className=\"flex items-center gap-1.5\">\n {collapsible && (\n <ChevronDown\n size={12}\n className={cn(\"transition-transform duration-150\", !open && \"-rotate-90\")}\n />\n )}\n {children}\n </span>\n {action && <span className=\"ml-auto\">{action}</span>}\n </Tag>\n );\n}\n\nfunction DesignerPaneContent({ className, children }: DesignerPaneContentProps) {\n const { open } = usePaneContext();\n if (!open) return null;\n return <div className={cn(\"flex flex-col gap-2 px-3 pb-3\", className)}>{children}</div>;\n}\n\n// --- internal pane context (so title and content stay in sync) ---\n\nimport { createContext, useContext } from \"react\";\n\ninterface PaneCtx {\n open: boolean;\n toggle: () => void;\n collapsible: boolean;\n}\nconst PaneContext = createContext<PaneCtx>({ open: true, toggle: () => {}, collapsible: false });\nfunction usePaneContext() {\n return useContext(PaneContext);\n}\n\nexport { DesignerPane, DesignerPaneTitle, DesignerPaneContent };\nexport type { DesignerPaneProps, DesignerPaneTitleProps, DesignerPaneContentProps };\n","import type { ComponentType, ReactNode } from \"react\";\nimport { cn, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@hilum/ui\";\n\n/* ============================================================== *\n * Toolbar — outer container *\n * ============================================================== */\n\ninterface DesignerToolbarProps {\n className?: string;\n /** Position. Default: 'floating' (centered, floating above content). */\n variant?: \"floating\" | \"inline\";\n children: ReactNode;\n}\n\nfunction DesignerToolbar({ className, variant = \"floating\", children }: DesignerToolbarProps) {\n return (\n <TooltipProvider>\n <div\n role=\"toolbar\"\n className={cn(\n \"flex items-center gap-0.5 rounded-lg bg-card shadow-natural border border-border p-1\",\n variant === \"floating\" && \"fixed bottom-4 left-1/2 -translate-x-1/2 z-30\",\n className,\n )}\n >\n {children}\n </div>\n </TooltipProvider>\n );\n}\n\n/* ============================================================== *\n * ToolbarGroup — visual group of buttons *\n * ============================================================== */\n\ninterface DesignerToolbarGroupProps {\n className?: string;\n children: ReactNode;\n}\n\nfunction DesignerToolbarGroup({ className, children }: DesignerToolbarGroupProps) {\n return <div className={cn(\"flex items-center gap-0.5\", className)}>{children}</div>;\n}\n\n/* ============================================================== *\n * ToolbarSeparator *\n * ============================================================== */\n\ninterface DesignerToolbarSeparatorProps {\n className?: string;\n}\n\nfunction DesignerToolbarSeparator({ className }: DesignerToolbarSeparatorProps) {\n return <div className={cn(\"mx-1 h-5 w-px bg-muted\", className)} role=\"separator\" />;\n}\n\n/* ============================================================== *\n * ToolbarButton — single tool / action *\n * ============================================================== */\n\ninterface DesignerToolbarButtonProps {\n label: string;\n icon?: ComponentType<{ size?: number; className?: string }>;\n onClick?: () => void;\n active?: boolean;\n disabled?: boolean;\n /** Optional keyboard shortcut shown in the tooltip (e.g. 'V', 'Cmd+Z'). */\n shortcut?: string;\n className?: string;\n children?: ReactNode;\n}\n\nfunction DesignerToolbarButton({\n label,\n icon: Icon,\n onClick,\n active,\n disabled,\n shortcut,\n className,\n children,\n}: DesignerToolbarButtonProps) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n aria-label={label}\n aria-pressed={active}\n className={cn(\n \"flex h-8 min-w-8 items-center justify-center gap-1 rounded-md px-1.5 transition-colors caption\",\n active\n ? \"bg-foreground text-background\"\n : \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className,\n )}\n >\n {Icon && <Icon size={16} />}\n {children}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">\n <span>{label}</span>\n {shortcut && <span className=\"ml-2 caption-xs text-muted-foreground\">{shortcut}</span>}\n </TooltipContent>\n </Tooltip>\n );\n}\n\nexport { DesignerToolbar, DesignerToolbarGroup, DesignerToolbarSeparator, DesignerToolbarButton };\nexport type {\n DesignerToolbarProps,\n DesignerToolbarGroupProps,\n DesignerToolbarSeparatorProps,\n DesignerToolbarButtonProps,\n};\n","import { useCallback, useState } from \"react\";\n\ninterface HistoryState<T> {\n past: T[];\n present: T;\n future: T[];\n}\n\ninterface UseHistoryReturn<T> {\n state: T;\n /**\n * Record a new state. Use when the user makes a logical edit. Pushes the\n * current `state` into `past` and clears `future`. Pass `{ skipHistory: true }`\n * (via a separate setter) to overwrite without pushing — apps that need that\n * can set state directly via a wrapper.\n */\n setState: (next: T | ((prev: T) => T)) => void;\n /** Replace `state` without pushing onto the history stack. */\n replaceState: (next: T | ((prev: T) => T)) => void;\n undo: () => void;\n redo: () => void;\n reset: (next: T) => void;\n canUndo: boolean;\n canRedo: boolean;\n /** Number of past entries (undo depth). */\n pastSize: number;\n /** Number of future entries (redo depth). */\n futureSize: number;\n}\n\n/**\n * Generic, engine-agnostic undo/redo stack.\n *\n * @hilum/designer-canvas wires this with `useHistory<Layer[]>(layers)`.\n * A form-builder app could wire `useHistory<FormSchema>(schema)`.\n */\nexport function useHistory<T>(initial: T): UseHistoryReturn<T> {\n const [history, setHistory] = useState<HistoryState<T>>({\n past: [],\n present: initial,\n future: [],\n });\n\n const setState = useCallback((next: T | ((prev: T) => T)) => {\n setHistory((prev) => {\n const value = typeof next === \"function\" ? (next as (p: T) => T)(prev.present) : next;\n if (Object.is(value, prev.present)) return prev;\n return {\n past: [...prev.past, prev.present],\n present: value,\n future: [],\n };\n });\n }, []);\n\n const replaceState = useCallback((next: T | ((prev: T) => T)) => {\n setHistory((prev) => {\n const value = typeof next === \"function\" ? (next as (p: T) => T)(prev.present) : next;\n return { ...prev, present: value };\n });\n }, []);\n\n const undo = useCallback(() => {\n setHistory((prev) => {\n if (prev.past.length === 0) return prev;\n const past = prev.past.slice(0, -1);\n const previous = prev.past[prev.past.length - 1]!;\n return {\n past,\n present: previous,\n future: [prev.present, ...prev.future],\n };\n });\n }, []);\n\n const redo = useCallback(() => {\n setHistory((prev) => {\n if (prev.future.length === 0) return prev;\n const [next, ...rest] = prev.future;\n return {\n past: [...prev.past, prev.present],\n present: next!,\n future: rest,\n };\n });\n }, []);\n\n const reset = useCallback((next: T) => {\n setHistory({ past: [], present: next, future: [] });\n }, []);\n\n return {\n state: history.present,\n setState,\n replaceState,\n undo,\n redo,\n reset,\n canUndo: history.past.length > 0,\n canRedo: history.future.length > 0,\n pastSize: history.past.length,\n futureSize: history.future.length,\n };\n}\n","import { useEffect } from \"react\";\n\nexport interface KeybindingConfig {\n /** Lower-case key (e.g. 'z', 'arrowup', 'escape', '+', '-'). */\n key: string;\n ctrl?: boolean;\n /** Cmd on macOS. Use both `meta` and `ctrl: true` if you want both. */\n meta?: boolean;\n shift?: boolean;\n alt?: boolean;\n /**\n * Treat both ctrl and meta as the same modifier (for cross-platform\n * shortcuts like Cmd+Z / Ctrl+Z). Default: false. Set to true to match\n * either modifier.\n */\n mod?: boolean;\n action: (event: KeyboardEvent) => void;\n /** Don't run when target is an input / textarea / contenteditable. Default: true. */\n skipInputs?: boolean;\n /** Call event.preventDefault() before action. Default: true. */\n preventDefault?: boolean;\n}\n\ninterface UseKeybindingsOptions {\n /** Skip all bindings entirely. */\n disabled?: boolean;\n /** Element to attach the listener to. Default: window. */\n target?: Window | HTMLElement | null;\n}\n\n/**\n * Generic keyboard shortcut registry. Engine-agnostic — the package doesn't\n * know what an action does. Pass an array of bindings; the hook attaches\n * a single keydown listener and dispatches on match.\n *\n * @hilum/designer-canvas wires its standard editor shortcuts (Cmd+Z, V, T,\n * arrow nudge, etc.) on top of this hook.\n */\nexport function useKeybindings(\n bindings: KeybindingConfig[],\n { disabled, target }: UseKeybindingsOptions = {},\n) {\n useEffect(() => {\n if (disabled) return;\n const node = target ?? (typeof window !== \"undefined\" ? window : null);\n if (!node) return;\n\n const handler = (rawEvent: Event) => {\n const e = rawEvent as KeyboardEvent;\n\n const tgt = e.target as HTMLElement | null;\n const isInput =\n tgt instanceof HTMLInputElement ||\n tgt instanceof HTMLTextAreaElement ||\n tgt instanceof HTMLSelectElement ||\n tgt?.isContentEditable === true;\n\n const key = e.key.toLowerCase();\n\n for (const b of bindings) {\n if (b.key.toLowerCase() !== key) continue;\n if (b.skipInputs !== false && isInput) continue;\n\n const ctrlMatches = b.ctrl ? e.ctrlKey : !e.ctrlKey || b.mod;\n const metaMatches = b.meta ? e.metaKey : !e.metaKey || b.mod;\n const modMatches = b.mod ? e.ctrlKey || e.metaKey : true;\n const shiftMatches = b.shift ? e.shiftKey : !e.shiftKey;\n const altMatches = b.alt ? e.altKey : !e.altKey;\n\n if (!modMatches) continue;\n if (!b.mod && (!ctrlMatches || !metaMatches)) continue;\n if (!shiftMatches || !altMatches) continue;\n\n if (b.preventDefault !== false) e.preventDefault();\n b.action(e);\n return;\n }\n };\n\n (node as Window).addEventListener(\"keydown\", handler);\n return () => (node as Window).removeEventListener(\"keydown\", handler);\n }, [bindings, disabled, target]);\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/ShellContext.tsx","../src/components/DesignerShell.tsx","../src/components/DesignerHeader.tsx","../src/components/DesignerSidebar.tsx","../src/components/DesignerPanel.tsx","../src/components/DesignerPane.tsx","../src/components/DesignerPropertyRow.tsx","../src/components/DesignerToolbar.tsx","../src/hooks/useHistory.ts","../src/hooks/useKeybindings.ts"],"names":["jsx","cn","jsxs","useState","createContext","useContext","TooltipProvider","Tooltip","TooltipTrigger","TooltipContent"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext, useMemo, useState } from \"react\";\nimport type { Dispatch, ReactNode, SetStateAction } from \"react\";\n\n/**\n * The minimal contract a designer shell needs from the engine beneath it.\n *\n * The chrome (toolbar, panel, pane, sidebar) reads from this context.\n * It does NOT know what is being edited — selection IDs are opaque strings\n * (layer IDs, field IDs, node IDs — whatever the engine uses), and active\n * tool is an open string the app defines (`select`, `hand`, `text`, …).\n *\n * @hilum/designer-canvas wires this up for canvas apps. A form-builder app\n * could wire its own engine to ShellContext with the same primitives.\n */\nexport interface ShellContextValue {\n /** IDs of currently-selected items. Engine-defined meaning. */\n selectedIds: string[];\n setSelectedIds: Dispatch<SetStateAction<string[]>>;\n\n /** Active tool. App-defined enum (e.g. 'select' | 'hand' | 'text'). */\n activeTool: string;\n setActiveTool: Dispatch<SetStateAction<string>>;\n\n /** When true, mutating actions should no-op. Used for previews. */\n readOnly: boolean;\n\n /**\n * Optional resolver: given a `selectedId`, return its engine-defined \"kind\"\n * (e.g. 'text', 'image'). DesignerPane.showFor uses this to decide whether\n * to render. Apps that don't have typed selections can leave this undefined.\n */\n resolveKind?: (id: string) => string | undefined;\n}\n\nconst noop = () => {};\n\nconst DEFAULT: ShellContextValue = {\n selectedIds: [],\n setSelectedIds: noop as Dispatch<SetStateAction<string[]>>,\n activeTool: \"select\",\n setActiveTool: noop as Dispatch<SetStateAction<string>>,\n readOnly: false,\n};\n\nconst ShellContext = createContext<ShellContextValue>(DEFAULT);\n\nexport function useShellContext(): ShellContextValue {\n return useContext(ShellContext);\n}\n\ninterface ShellProviderProps {\n /** Initial selected IDs. Default: []. */\n initialSelectedIds?: string[];\n /** Initial active tool. Default: 'select'. */\n initialTool?: string;\n /** Read-only flag. */\n readOnly?: boolean;\n /** Kind resolver — see ShellContextValue.resolveKind. */\n resolveKind?: (id: string) => string | undefined;\n /** Controlled override — pass a value to lift state out of the provider. */\n value?: Partial<ShellContextValue>;\n children: ReactNode;\n}\n\nexport function ShellProvider({\n initialSelectedIds = [],\n initialTool = \"select\",\n readOnly = false,\n resolveKind,\n value: controlled,\n children,\n}: ShellProviderProps) {\n const [selectedIds, setSelectedIds] = useState<string[]>(initialSelectedIds);\n const [activeTool, setActiveTool] = useState<string>(initialTool);\n\n const resolvedKind = controlled?.resolveKind ?? resolveKind;\n\n const value = useMemo<ShellContextValue>(\n () => ({\n selectedIds: controlled?.selectedIds ?? selectedIds,\n setSelectedIds: controlled?.setSelectedIds ?? setSelectedIds,\n activeTool: controlled?.activeTool ?? activeTool,\n setActiveTool: controlled?.setActiveTool ?? setActiveTool,\n readOnly: controlled?.readOnly ?? readOnly,\n ...(resolvedKind !== undefined && { resolveKind: resolvedKind }),\n }),\n [selectedIds, activeTool, readOnly, resolvedKind, controlled],\n );\n\n return <ShellContext.Provider value={value}>{children}</ShellContext.Provider>;\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@hilum/ui\";\n\ninterface DesignerShellProps {\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Root layout for an editor app — full viewport, themed surface.\n * Place a <DesignerHeader>, <DesignerSidebar>, <DesignerPanel>, and the\n * canvas content as children.\n */\nfunction DesignerShell({ className, children }: DesignerShellProps) {\n return (\n <div\n className={cn(\n \"flex flex-col h-screen w-screen overflow-hidden bg-muted text-foreground\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nexport { DesignerShell };\nexport type { DesignerShellProps };\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@hilum/ui\";\n\ninterface DesignerHeaderProps {\n /** Left-aligned content — file name, breadcrumbs, project switcher. */\n left?: ReactNode;\n /** Center content — typically the active document title. */\n center?: ReactNode;\n /** Right-aligned content — share, export, presence, account. */\n right?: ReactNode;\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Top bar of an editor app. Slot-driven — the chrome doesn't know what\n * goes in each region. Use <DesignerHeader left={...} center={...} right={...} />.\n */\nfunction DesignerHeader({ left, center, right, className, children }: DesignerHeaderProps) {\n return (\n <header\n className={cn(\n \"flex h-12 items-center justify-between gap-3 border-b border-border bg-card px-3 shrink-0\",\n className,\n )}\n >\n <div className=\"flex items-center gap-2 min-w-0\">{left}</div>\n {center && <div className=\"flex items-center gap-2 min-w-0\">{center}</div>}\n <div className=\"flex items-center gap-2 min-w-0\">{right}</div>\n {children}\n </header>\n );\n}\n\nexport { DesignerHeader };\nexport type { DesignerHeaderProps };\n","import type { ComponentType, ReactNode } from \"react\";\nimport { cn, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@hilum/ui\";\n\ninterface SidebarItem {\n id: string;\n label: string;\n icon: ComponentType<{ size?: number; className?: string }>;\n onClick?: () => void;\n /** Caller-computed active flag. */\n active?: boolean;\n disabled?: boolean;\n badge?: ReactNode;\n}\n\ninterface DesignerSidebarProps {\n /** Top group of icon buttons. */\n items: SidebarItem[];\n /** Optional bottom group (settings, help, account). */\n bottomItems?: SidebarItem[];\n side?: \"left\" | \"right\";\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Vertical icon rail used as the primary tool / navigation column in an\n * editor. Driven by an `items` array — no engine coupling. Each item gets\n * a tooltip showing its label.\n */\nfunction DesignerSidebar({\n items,\n bottomItems,\n side = \"left\",\n className,\n children,\n}: DesignerSidebarProps) {\n return (\n <aside\n className={cn(\n \"flex flex-col w-12 bg-card shrink-0\",\n side === \"left\" ? \"border-r\" : \"border-l\",\n \"border-border\",\n className,\n )}\n >\n <TooltipProvider>\n <div className=\"flex flex-col items-center gap-0.5 p-1.5\">\n {items.map((item) => (\n <SidebarButton key={item.id} item={item} />\n ))}\n </div>\n\n {children}\n\n {bottomItems && bottomItems.length > 0 && (\n <div className=\"mt-auto flex flex-col items-center gap-0.5 p-1.5\">\n {bottomItems.map((item) => (\n <SidebarButton key={item.id} item={item} />\n ))}\n </div>\n )}\n </TooltipProvider>\n </aside>\n );\n}\n\nfunction SidebarButton({ item }: { item: SidebarItem }) {\n const Icon = item.icon;\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={item.onClick}\n disabled={item.disabled}\n aria-label={item.label}\n aria-pressed={item.active}\n className={cn(\n \"relative flex size-9 items-center justify-center rounded-md transition-colors\",\n item.active\n ? \"bg-foreground text-background\"\n : \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n item.disabled && \"opacity-50 cursor-not-allowed\",\n )}\n >\n <Icon size={16} />\n {item.badge != null && (\n <span className=\"absolute -top-0.5 -right-0.5 caption-xs\">{item.badge}</span>\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{item.label}</TooltipContent>\n </Tooltip>\n );\n}\n\nexport { DesignerSidebar };\nexport type { DesignerSidebarProps, SidebarItem };\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@hilum/ui\";\n\ninterface DesignerPanelProps {\n side: \"left\" | \"right\";\n /** Width in pixels. Default: 240. */\n width?: number;\n /** Add a separator border on the inner edge. Default: true. */\n bordered?: boolean;\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Left or right side panel of an editor — typically holds layer lists,\n * inspector / properties, history, comments, etc. Static-width for v1.\n * (Resize handles arrive in a later iteration if needed.)\n */\nfunction DesignerPanel({\n side,\n width = 240,\n bordered = true,\n className,\n children,\n}: DesignerPanelProps) {\n return (\n <aside\n className={cn(\n \"flex min-w-0 max-w-full shrink-0 flex-col overflow-hidden bg-card\",\n bordered && (side === \"left\" ? \"border-r\" : \"border-l\"),\n bordered && \"border-border\",\n className,\n )}\n style={{ width, maxWidth: \"100%\" }}\n >\n <div className=\"flex min-w-0 flex-1 flex-col overflow-x-hidden overflow-y-auto\">\n {children}\n </div>\n </aside>\n );\n}\n\nexport { DesignerPanel };\nexport type { DesignerPanelProps };\n","import { useState, type ReactNode } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { cn } from \"@hilum/ui\";\nimport { useShellContext } from \"../shell/ShellContext\";\n\ninterface DesignerPaneProps {\n /**\n * Predicate or list of allowed kinds. The pane renders only when matched.\n *\n * - `string[]`: render when at least one selected ID resolves to one of\n * these kinds (requires `ShellContext.resolveKind`).\n * - `(selectedIds: string[]) => boolean`: full predicate.\n * - omitted: always render.\n */\n showFor?: string[] | ((selectedIds: string[]) => boolean);\n collapsible?: boolean;\n defaultOpen?: boolean;\n className?: string;\n children: ReactNode;\n}\n\ninterface DesignerPaneTitleProps {\n className?: string;\n children: ReactNode;\n /** Right-aligned action / control. */\n action?: ReactNode;\n}\n\ninterface DesignerPaneContentProps {\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Collapsible inspector section. Use inside a <DesignerPanel>.\n *\n * <DesignerPane showFor={[\"text\"]} collapsible>\n * <DesignerPaneTitle>Typography</DesignerPaneTitle>\n * <DesignerPaneContent>...</DesignerPaneContent>\n * </DesignerPane>\n */\nfunction DesignerPane({\n showFor,\n collapsible = false,\n defaultOpen = true,\n className,\n children,\n}: DesignerPaneProps) {\n const { selectedIds, resolveKind } = useShellContext();\n const [open, setOpen] = useState(defaultOpen);\n\n // Visibility check.\n let visible = true;\n if (typeof showFor === \"function\") {\n visible = showFor(selectedIds);\n } else if (Array.isArray(showFor)) {\n if (!resolveKind) {\n // No resolver: best effort — show only if any IDs are selected.\n visible = selectedIds.length > 0;\n } else {\n visible = selectedIds.some((id) => {\n const kind = resolveKind(id);\n return kind != null && showFor.includes(kind);\n });\n }\n }\n if (!visible) return null;\n\n return (\n <PaneContext.Provider value={{ open, toggle: () => setOpen((v) => !v), collapsible }}>\n <section\n className={cn(\n \"flex min-w-0 max-w-full flex-col overflow-x-hidden border-b border-border last:border-b-0\",\n className,\n )}\n >\n {children}\n </section>\n </PaneContext.Provider>\n );\n}\n\nfunction DesignerPaneTitle({ className, children, action }: DesignerPaneTitleProps) {\n const { open, toggle, collapsible } = usePaneContext();\n\n const Tag = collapsible ? \"button\" : \"div\";\n return (\n <Tag\n type={collapsible ? \"button\" : undefined}\n onClick={collapsible ? toggle : undefined}\n className={cn(\n \"flex w-full items-center justify-between gap-2 px-3 py-2 text-left\",\n \"caption-xs uppercase tracking-wider font-semibold text-muted-foreground\",\n collapsible && \"hover:text-foreground transition-colors\",\n className,\n )}\n >\n <span className=\"flex items-center gap-1.5\">\n {collapsible && (\n <ChevronDown\n size={12}\n className={cn(\"transition-transform duration-150\", !open && \"-rotate-90\")}\n />\n )}\n {children}\n </span>\n {action && <span className=\"ml-auto\">{action}</span>}\n </Tag>\n );\n}\n\nfunction DesignerPaneContent({ className, children }: DesignerPaneContentProps) {\n const { open } = usePaneContext();\n if (!open) return null;\n return (\n <div\n className={cn(\n \"flex min-w-0 max-w-full flex-col gap-2 overflow-x-hidden px-3 pb-3\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n// --- internal pane context (so title and content stay in sync) ---\n\nimport { createContext, useContext } from \"react\";\n\ninterface PaneCtx {\n open: boolean;\n toggle: () => void;\n collapsible: boolean;\n}\nconst PaneContext = createContext<PaneCtx>({ open: true, toggle: () => {}, collapsible: false });\nfunction usePaneContext() {\n return useContext(PaneContext);\n}\n\nexport { DesignerPane, DesignerPaneTitle, DesignerPaneContent };\nexport type { DesignerPaneProps, DesignerPaneTitleProps, DesignerPaneContentProps };\n","import type { ComponentPropsWithoutRef, ReactNode } from \"react\";\nimport { cn } from \"@hilum/ui\";\n\ninterface DesignerPropertyRowProps extends ComponentPropsWithoutRef<\"div\"> {\n /** Optional label for direct row usage. Compound usage can use DesignerPropertyLabel. */\n label?: ReactNode;\n /** htmlFor forwarded to the generated label when label is provided. */\n labelFor?: string;\n /** Class name for the generated controls container when label is provided. */\n controlsClassName?: string;\n children: ReactNode;\n}\n\ninterface DesignerPropertyLabelProps extends ComponentPropsWithoutRef<\"label\"> {\n children: ReactNode;\n}\n\ninterface DesignerPropertyControlsProps extends ComponentPropsWithoutRef<\"div\"> {\n children: ReactNode;\n}\n\ninterface DesignerPropertyGroupProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"title\"> {\n title?: ReactNode;\n children: ReactNode;\n}\n\nfunction DesignerPropertyRow({\n label,\n labelFor,\n controlsClassName,\n className,\n children,\n ...rest\n}: DesignerPropertyRowProps) {\n return (\n <div\n className={cn(\n \"flex w-full min-w-0 max-w-full flex-col items-stretch gap-1.5 py-1.5\",\n className,\n )}\n {...rest}\n >\n {label === undefined ? (\n children\n ) : (\n <>\n <DesignerPropertyLabel htmlFor={labelFor}>{label}</DesignerPropertyLabel>\n <DesignerPropertyControls className={controlsClassName}>{children}</DesignerPropertyControls>\n </>\n )}\n </div>\n );\n}\n\nfunction DesignerPropertyLabel({\n className,\n children,\n ...rest\n}: DesignerPropertyLabelProps) {\n return (\n <label\n className={cn(\n \"caption w-full min-w-0 max-w-full select-none text-muted-foreground\",\n className,\n )}\n {...rest}\n >\n {children}\n </label>\n );\n}\n\nfunction DesignerPropertyControls({\n className,\n children,\n ...rest\n}: DesignerPropertyControlsProps) {\n return (\n <div\n className={cn(\n \"flex w-full min-w-0 max-w-full flex-1 items-center gap-2 overflow-visible\",\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n );\n}\n\nfunction DesignerPropertyGroup({\n title,\n className,\n children,\n ...rest\n}: DesignerPropertyGroupProps) {\n return (\n <div\n className={cn(\"flex min-w-0 max-w-full flex-col gap-3\", className)}\n {...rest}\n >\n {title && (\n <div className=\"caption-xs min-w-0 max-w-full select-none overflow-hidden text-ellipsis uppercase tracking-wider text-muted-foreground\">\n {title}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nexport {\n DesignerPropertyRow,\n DesignerPropertyLabel,\n DesignerPropertyControls,\n DesignerPropertyGroup,\n};\nexport type {\n DesignerPropertyRowProps,\n DesignerPropertyLabelProps,\n DesignerPropertyControlsProps,\n DesignerPropertyGroupProps,\n};\n","import type { ComponentType, ReactNode } from \"react\";\nimport { cn, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@hilum/ui\";\n\n/* ============================================================== *\n * Toolbar — outer container *\n * ============================================================== */\n\ninterface DesignerToolbarProps {\n className?: string;\n /** Position. Default: 'floating' (centered, floating above content). */\n variant?: \"floating\" | \"inline\";\n children: ReactNode;\n}\n\nfunction DesignerToolbar({ className, variant = \"floating\", children }: DesignerToolbarProps) {\n return (\n <TooltipProvider>\n <div\n role=\"toolbar\"\n className={cn(\n \"flex items-center gap-0.5 rounded-lg bg-card shadow-natural border border-border p-1\",\n variant === \"floating\" && \"fixed bottom-4 left-1/2 -translate-x-1/2 z-30\",\n className,\n )}\n >\n {children}\n </div>\n </TooltipProvider>\n );\n}\n\n/* ============================================================== *\n * ToolbarGroup — visual group of buttons *\n * ============================================================== */\n\ninterface DesignerToolbarGroupProps {\n className?: string;\n children: ReactNode;\n}\n\nfunction DesignerToolbarGroup({ className, children }: DesignerToolbarGroupProps) {\n return <div className={cn(\"flex items-center gap-0.5\", className)}>{children}</div>;\n}\n\n/* ============================================================== *\n * ToolbarSeparator *\n * ============================================================== */\n\ninterface DesignerToolbarSeparatorProps {\n className?: string;\n}\n\nfunction DesignerToolbarSeparator({ className }: DesignerToolbarSeparatorProps) {\n return <div className={cn(\"mx-1 h-5 w-px bg-muted\", className)} role=\"separator\" />;\n}\n\n/* ============================================================== *\n * ToolbarButton — single tool / action *\n * ============================================================== */\n\ninterface DesignerToolbarButtonProps {\n label: string;\n icon?: ComponentType<{ size?: number; className?: string }>;\n onClick?: () => void;\n active?: boolean;\n disabled?: boolean;\n /** Optional keyboard shortcut shown in the tooltip (e.g. 'V', 'Cmd+Z'). */\n shortcut?: string;\n className?: string;\n children?: ReactNode;\n}\n\nfunction DesignerToolbarButton({\n label,\n icon: Icon,\n onClick,\n active,\n disabled,\n shortcut,\n className,\n children,\n}: DesignerToolbarButtonProps) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n aria-label={label}\n aria-pressed={active}\n className={cn(\n \"flex h-8 min-w-8 items-center justify-center gap-1 rounded-md px-1.5 transition-colors caption\",\n active\n ? \"bg-foreground text-background\"\n : \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className,\n )}\n >\n {Icon && <Icon size={16} />}\n {children}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">\n <span>{label}</span>\n {shortcut && <span className=\"ml-2 caption-xs text-muted-foreground\">{shortcut}</span>}\n </TooltipContent>\n </Tooltip>\n );\n}\n\nexport { DesignerToolbar, DesignerToolbarGroup, DesignerToolbarSeparator, DesignerToolbarButton };\nexport type {\n DesignerToolbarProps,\n DesignerToolbarGroupProps,\n DesignerToolbarSeparatorProps,\n DesignerToolbarButtonProps,\n};\n","import { useCallback, useState } from \"react\";\n\ninterface HistoryState<T> {\n past: T[];\n present: T;\n future: T[];\n}\n\ninterface UseHistoryReturn<T> {\n state: T;\n /**\n * Record a new state. Use when the user makes a logical edit. Pushes the\n * current `state` into `past` and clears `future`. Pass `{ skipHistory: true }`\n * (via a separate setter) to overwrite without pushing — apps that need that\n * can set state directly via a wrapper.\n */\n setState: (next: T | ((prev: T) => T)) => void;\n /** Replace `state` without pushing onto the history stack. */\n replaceState: (next: T | ((prev: T) => T)) => void;\n undo: () => void;\n redo: () => void;\n reset: (next: T) => void;\n canUndo: boolean;\n canRedo: boolean;\n /** Number of past entries (undo depth). */\n pastSize: number;\n /** Number of future entries (redo depth). */\n futureSize: number;\n}\n\n/**\n * Generic, engine-agnostic undo/redo stack.\n *\n * @hilum/designer-canvas wires this with `useHistory<Layer[]>(layers)`.\n * A form-builder app could wire `useHistory<FormSchema>(schema)`.\n */\nexport function useHistory<T>(initial: T): UseHistoryReturn<T> {\n const [history, setHistory] = useState<HistoryState<T>>({\n past: [],\n present: initial,\n future: [],\n });\n\n const setState = useCallback((next: T | ((prev: T) => T)) => {\n setHistory((prev) => {\n const value = typeof next === \"function\" ? (next as (p: T) => T)(prev.present) : next;\n if (Object.is(value, prev.present)) return prev;\n return {\n past: [...prev.past, prev.present],\n present: value,\n future: [],\n };\n });\n }, []);\n\n const replaceState = useCallback((next: T | ((prev: T) => T)) => {\n setHistory((prev) => {\n const value = typeof next === \"function\" ? (next as (p: T) => T)(prev.present) : next;\n return { ...prev, present: value };\n });\n }, []);\n\n const undo = useCallback(() => {\n setHistory((prev) => {\n if (prev.past.length === 0) return prev;\n const past = prev.past.slice(0, -1);\n const previous = prev.past[prev.past.length - 1]!;\n return {\n past,\n present: previous,\n future: [prev.present, ...prev.future],\n };\n });\n }, []);\n\n const redo = useCallback(() => {\n setHistory((prev) => {\n if (prev.future.length === 0) return prev;\n const [next, ...rest] = prev.future;\n return {\n past: [...prev.past, prev.present],\n present: next!,\n future: rest,\n };\n });\n }, []);\n\n const reset = useCallback((next: T) => {\n setHistory({ past: [], present: next, future: [] });\n }, []);\n\n return {\n state: history.present,\n setState,\n replaceState,\n undo,\n redo,\n reset,\n canUndo: history.past.length > 0,\n canRedo: history.future.length > 0,\n pastSize: history.past.length,\n futureSize: history.future.length,\n };\n}\n","import { useEffect } from \"react\";\n\nexport interface KeybindingConfig {\n /** Lower-case key (e.g. 'z', 'arrowup', 'escape', '+', '-'). */\n key: string;\n ctrl?: boolean;\n /** Cmd on macOS. Use both `meta` and `ctrl: true` if you want both. */\n meta?: boolean;\n shift?: boolean;\n alt?: boolean;\n /**\n * Treat both ctrl and meta as the same modifier (for cross-platform\n * shortcuts like Cmd+Z / Ctrl+Z). Default: false. Set to true to match\n * either modifier.\n */\n mod?: boolean;\n action: (event: KeyboardEvent) => void;\n /** Don't run when target is an input / textarea / contenteditable. Default: true. */\n skipInputs?: boolean;\n /** Call event.preventDefault() before action. Default: true. */\n preventDefault?: boolean;\n}\n\ninterface UseKeybindingsOptions {\n /** Skip all bindings entirely. */\n disabled?: boolean;\n /** Element to attach the listener to. Default: window. */\n target?: Window | HTMLElement | null;\n}\n\n/**\n * Generic keyboard shortcut registry. Engine-agnostic — the package doesn't\n * know what an action does. Pass an array of bindings; the hook attaches\n * a single keydown listener and dispatches on match.\n *\n * @hilum/designer-canvas wires its standard editor shortcuts (Cmd+Z, V, T,\n * arrow nudge, etc.) on top of this hook.\n */\nexport function useKeybindings(\n bindings: KeybindingConfig[],\n { disabled, target }: UseKeybindingsOptions = {},\n) {\n useEffect(() => {\n if (disabled) return;\n const node = target ?? (typeof window !== \"undefined\" ? window : null);\n if (!node) return;\n\n const handler = (rawEvent: Event) => {\n const e = rawEvent as KeyboardEvent;\n\n const tgt = e.target as HTMLElement | null;\n const isInput =\n tgt instanceof HTMLInputElement ||\n tgt instanceof HTMLTextAreaElement ||\n tgt instanceof HTMLSelectElement ||\n tgt?.isContentEditable === true;\n\n const key = e.key.toLowerCase();\n\n for (const b of bindings) {\n if (b.key.toLowerCase() !== key) continue;\n if (b.skipInputs !== false && isInput) continue;\n\n const ctrlMatches = b.ctrl ? e.ctrlKey : !e.ctrlKey || b.mod;\n const metaMatches = b.meta ? e.metaKey : !e.metaKey || b.mod;\n const modMatches = b.mod ? e.ctrlKey || e.metaKey : true;\n const shiftMatches = b.shift ? e.shiftKey : !e.shiftKey;\n const altMatches = b.alt ? e.altKey : !e.altKey;\n\n if (!modMatches) continue;\n if (!b.mod && (!ctrlMatches || !metaMatches)) continue;\n if (!shiftMatches || !altMatches) continue;\n\n if (b.preventDefault !== false) e.preventDefault();\n b.action(e);\n return;\n }\n };\n\n (node as Window).addEventListener(\"keydown\", handler);\n return () => (node as Window).removeEventListener(\"keydown\", handler);\n }, [bindings, disabled, target]);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hilum/designer",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "private": false,
5
5
  "description": "Engine-agnostic canvas-editor chrome — DesignerShell, Toolbar, Panel, Pane + generic useHistory and useKeybindings hooks",
6
6
  "license": "MIT",
@@ -28,7 +28,7 @@
28
28
  "peerDependencies": {
29
29
  "react": "^19.0.0",
30
30
  "react-dom": "^19.0.0",
31
- "@hilum/ui": "2.0.2"
31
+ "@hilum/ui": "2.0.4"
32
32
  },
33
33
  "dependencies": {
34
34
  "lucide-react": "^0.511.0"
@@ -39,7 +39,7 @@
39
39
  "tailwindcss": "^4.2.0",
40
40
  "tsup": "^8.3.0",
41
41
  "typescript": "^5.7.0",
42
- "@hilum/ui": "2.0.2"
42
+ "@hilum/ui": "2.0.4"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "tsup",