@zvk/composite 0.1.2 → 0.1.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +158 -1
  3. package/dist/domains/activity.d.ts +2 -0
  4. package/dist/domains/activity.js +1 -0
  5. package/dist/domains/ai.d.ts +6 -0
  6. package/dist/domains/ai.js +3 -0
  7. package/dist/domains/data.d.ts +10 -0
  8. package/dist/domains/data.js +5 -0
  9. package/dist/domains/detail.d.ts +2 -0
  10. package/dist/domains/detail.js +1 -0
  11. package/dist/domains/forms.d.ts +4 -0
  12. package/dist/domains/forms.js +2 -0
  13. package/dist/domains/navigation.d.ts +16 -0
  14. package/dist/domains/navigation.js +8 -0
  15. package/dist/domains/settings.d.ts +6 -0
  16. package/dist/domains/settings.js +3 -0
  17. package/dist/domains/shell.d.ts +6 -0
  18. package/dist/domains/shell.js +3 -0
  19. package/dist/domains/state.d.ts +4 -0
  20. package/dist/domains/state.js +2 -0
  21. package/dist/domains/workflow.d.ts +8 -0
  22. package/dist/domains/workflow.js +4 -0
  23. package/dist/index.d.ts +10 -56
  24. package/dist/index.js +10 -28
  25. package/dist/layout/page-scaffold.js +17 -9
  26. package/dist/navigation/command-palette-shell.d.ts +2 -1
  27. package/dist/navigation/command-palette-shell.js +3 -13
  28. package/dist/navigation/entity-switcher-menu.js +1 -11
  29. package/dist/navigation/resource-explorer-shell.d.ts +31 -0
  30. package/dist/navigation/resource-explorer-shell.js +30 -0
  31. package/dist/navigation/sectioned-workspace-shell.js +13 -6
  32. package/dist/navigation/shell-slot-rendering.d.ts +13 -0
  33. package/dist/navigation/shell-slot-rendering.js +25 -0
  34. package/dist/navigation/simple-workspace-shell.d.ts +16 -0
  35. package/dist/navigation/simple-workspace-shell.js +25 -0
  36. package/dist/navigation/split-workspace-shell.d.ts +24 -0
  37. package/dist/navigation/split-workspace-shell.js +32 -0
  38. package/dist/styles.css +272 -20
  39. package/dist/utils/use-controllable-value.d.ts +7 -0
  40. package/dist/utils/use-controllable-value.js +12 -0
  41. package/dist/workflows/wizard-shell.d.ts +24 -0
  42. package/dist/workflows/wizard-shell.js +32 -0
  43. package/package.json +22 -2
@@ -0,0 +1,31 @@
1
+ import * as React from "react";
2
+ export interface ResourceExplorerShellResource {
3
+ badge?: React.ReactNode | undefined;
4
+ children?: readonly ResourceExplorerShellResource[] | undefined;
5
+ description?: React.ReactNode | undefined;
6
+ disabled?: boolean | undefined;
7
+ icon?: React.ReactNode | undefined;
8
+ id: string;
9
+ label: React.ReactNode;
10
+ meta?: React.ReactNode | undefined;
11
+ textValue: string;
12
+ }
13
+ export interface ResourceExplorerShellProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSelect"> {
14
+ activeKey?: string | undefined;
15
+ empty?: React.ReactNode | undefined;
16
+ expandedKeys?: readonly string[] | undefined;
17
+ footer?: React.ReactNode | undefined;
18
+ label: string;
19
+ loading?: boolean | undefined;
20
+ onExpandedKeysChange?: ((keys: string[]) => void) | undefined;
21
+ onItemAction?: ((id: string, item: ResourceExplorerShellResource) => void) | undefined;
22
+ onSelectedKeysChange?: ((keys: string[]) => void) | undefined;
23
+ preview?: React.ReactNode | undefined;
24
+ ref?: React.Ref<HTMLDivElement> | undefined;
25
+ resultItems?: readonly ResourceExplorerShellResource[] | undefined;
26
+ search?: React.ReactNode | undefined;
27
+ selectedKeys?: readonly string[] | undefined;
28
+ toolbar?: React.ReactNode | undefined;
29
+ treeItems: readonly ResourceExplorerShellResource[];
30
+ }
31
+ export declare function ResourceExplorerShell({ activeKey, className, empty, expandedKeys, footer, label, loading, onExpandedKeysChange, onItemAction, onSelectedKeysChange, preview, ref, resultItems, search, selectedKeys, toolbar, treeItems, ...props }: ResourceExplorerShellProps): React.JSX.Element;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { GridList } from "@zvk/ui/grid-list";
5
+ import { ListRow } from "@zvk/ui/list-row";
6
+ import { TreeView } from "@zvk/ui/tree-view";
7
+ import { cn } from "../utils/cn.js";
8
+ function renderResourceRow(item, selected) {
9
+ return (_jsxs(ListRow, { selected: selected, variant: "plain", children: [item.icon ? _jsx(ListRow.Leading, { children: item.icon }) : null, _jsxs(ListRow.Content, { children: [_jsx(ListRow.Title, { children: item.label }), item.description ? _jsx(ListRow.Description, { children: item.description }) : null] }), item.meta ? _jsx(ListRow.Meta, { children: item.meta }) : null, item.badge ? _jsx(ListRow.Trailing, { children: item.badge }) : null] }));
10
+ }
11
+ export function ResourceExplorerShell({ activeKey, className, empty = "No resources found.", expandedKeys, footer, label, loading = false, onExpandedKeysChange, onItemAction, onSelectedKeysChange, preview, ref, resultItems, search, selectedKeys, toolbar, treeItems, ...props }) {
12
+ const records = resultItems ?? treeItems;
13
+ const selectedProps = {
14
+ ...(selectedKeys === undefined ? {} : { selectedKeys }),
15
+ ...(onSelectedKeysChange === undefined ? {} : { onSelectedKeysChange })
16
+ };
17
+ const treeProps = {
18
+ ...(activeKey === undefined ? {} : { activeKey }),
19
+ ...(expandedKeys === undefined ? { defaultExpandedKeys: treeItems.slice(0, 1).map((item) => item.id) } : {}),
20
+ ...(expandedKeys === undefined ? {} : { expandedKeys }),
21
+ ...(onExpandedKeysChange === undefined ? {} : { onExpandedKeysChange }),
22
+ ...(onItemAction === undefined ? {} : { onItemAction }),
23
+ ...selectedProps
24
+ };
25
+ const gridProps = {
26
+ ...(onItemAction === undefined ? {} : { onAction: onItemAction }),
27
+ ...selectedProps
28
+ };
29
+ return (_jsxs("div", { ...props, ref: ref, className: cn("zvk-composite-resource-explorer-shell", className), "data-with-preview": preview ? "true" : undefined, children: [_jsxs("aside", { className: "zvk-composite-resource-explorer-shell__tree", children: [_jsx("div", { className: "zvk-composite-resource-explorer-shell__tree-header", children: _jsx("strong", { children: label }) }), search ? _jsx("div", { className: "zvk-composite-resource-explorer-shell__search", children: search }) : null, _jsx(TreeView, { ...treeProps, "aria-label": `${label} tree`, getItemChildren: (item) => item.children, getItemId: (item) => item.id, getItemLabel: (item) => item.textValue, isItemDisabled: (item) => item.disabled === true, items: treeItems, renderItem: (item) => (_jsxs("span", { className: "zvk-composite-resource-explorer-shell__tree-item", children: [item.icon ? _jsx("span", { className: "zvk-composite-resource-explorer-shell__tree-item-icon", children: item.icon }) : null, _jsx("span", { children: item.label })] })), selectionMode: "single" }), footer ? _jsx("div", { className: "zvk-composite-resource-explorer-shell__footer", children: footer }) : null] }), _jsxs("section", { className: "zvk-composite-resource-explorer-shell__results", "aria-label": `${label} results`, children: [toolbar ? _jsx("div", { className: "zvk-composite-resource-explorer-shell__toolbar", children: toolbar }) : null, _jsx(GridList, { ...gridProps, "aria-label": `${label} resources`, emptyState: empty, getItemId: (item) => item.id, getItemTextValue: (item) => item.textValue, isItemDisabled: (item) => item.disabled === true, items: records, loading: loading, loadingState: "Loading resources...", renderItem: (item, state) => renderResourceRow(item, state.selected), selectionMode: "single" })] }), preview ? _jsx("aside", { className: "zvk-composite-resource-explorer-shell__preview", children: preview }) : null] }));
30
+ }
@@ -2,26 +2,33 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { SectionedSidebarNav } from "@zvk/ui/sectioned-sidebar-nav";
4
4
  import { cn } from "../utils/cn.js";
5
+ import { hasRenderableShellSlot, ShellHeaderChrome } from "./shell-slot-rendering.js";
5
6
  import { WorkspaceHeader } from "./workspace-header.js";
6
7
  export function SectionedWorkspaceShell({ actions, activeItemId, children, className, description, footer, headingLevel, navLabel = "Workspace navigation", onItemSelect, ref, sections, sidebarFooter, title, toolbar, ...props }) {
7
- const hasHeader = Boolean(title || description || actions || toolbar);
8
+ const hasActions = hasRenderableShellSlot(actions);
9
+ const hasDescription = hasRenderableShellSlot(description);
10
+ const hasFooter = hasRenderableShellSlot(footer);
11
+ const hasSidebarFooter = hasRenderableShellSlot(sidebarFooter);
12
+ const hasTitle = hasRenderableShellSlot(title);
13
+ const hasToolbar = hasRenderableShellSlot(toolbar);
14
+ const hasHeader = hasTitle || hasDescription || hasActions || hasToolbar;
8
15
  const navigationProps = {
9
16
  ...(activeItemId === undefined ? {} : { activeItemId }),
10
17
  ...(onItemSelect === undefined ? {} : { onItemSelect })
11
18
  };
12
19
  const headerProps = {
13
- ...(actions === undefined ? {} : { actions }),
14
- ...(description === undefined ? {} : { description }),
20
+ ...(hasActions ? { actions } : {}),
21
+ ...(hasDescription ? { description } : {}),
15
22
  ...(headingLevel === undefined ? {} : { headingLevel }),
16
- ...(toolbar === undefined ? {} : { toolbar })
23
+ ...(hasToolbar ? { toolbar } : {})
17
24
  };
18
- return (_jsxs("div", { ...props, ref: ref, className: cn("zvk-composite-sectioned-workspace-shell", className), children: [_jsxs("aside", { className: "zvk-composite-sectioned-workspace-shell__sidebar", children: [_jsx(SectionedWorkspaceNavigation, { ...navigationProps, navLabel: navLabel, sections: sections }), sidebarFooter ? (_jsx("div", { className: "zvk-composite-sectioned-workspace-shell__sidebar-footer", children: sidebarFooter })) : null] }), _jsxs("div", { className: "zvk-composite-sectioned-workspace-shell__body", children: [hasHeader ? (_jsx(WorkspaceHeader, { ...headerProps, className: "zvk-composite-sectioned-workspace-shell__header", title: title ?? "" })) : null, _jsx("main", { className: "zvk-composite-sectioned-workspace-shell__content", children: children }), footer ? _jsx("footer", { className: "zvk-composite-sectioned-workspace-shell__footer", children: footer }) : null] })] }));
25
+ return (_jsxs("div", { ...props, ref: ref, className: cn("zvk-composite-sectioned-workspace-shell", className), children: [_jsxs("aside", { className: "zvk-composite-sectioned-workspace-shell__sidebar", children: [_jsx(SectionedWorkspaceNavigation, { ...navigationProps, navLabel: navLabel, sections: sections }), hasSidebarFooter ? (_jsx("div", { className: "zvk-composite-sectioned-workspace-shell__sidebar-footer", children: sidebarFooter })) : null] }), _jsxs("div", { className: "zvk-composite-sectioned-workspace-shell__body", children: [hasHeader && hasTitle ? (_jsx(WorkspaceHeader, { ...headerProps, className: "zvk-composite-sectioned-workspace-shell__header", title: title })) : hasHeader ? (_jsx(ShellHeaderChrome, { actions: actions, className: "zvk-composite-sectioned-workspace-shell__header", description: description, toolbar: toolbar })) : null, _jsx("main", { className: "zvk-composite-sectioned-workspace-shell__content", children: children }), hasFooter ? _jsx("footer", { className: "zvk-composite-sectioned-workspace-shell__footer", children: footer }) : null] })] }));
19
26
  }
20
27
  function SectionedWorkspaceNavigation({ activeItemId, navLabel, onItemSelect, sections }) {
21
28
  return (_jsx(SectionedSidebarNav, { className: "zvk-composite-sectioned-workspace-shell__nav", label: navLabel, children: sections.map((section) => (_jsxs(SectionedSidebarNav.Section, { children: [_jsx(SectionedSidebarNav.SectionTitle, { children: section.label }), _jsx(SectionedSidebarNav.List, { children: section.items.map((item) => (_jsx(SectionedWorkspaceNavigationItem, { active: item.id === activeItemId, item: item, onItemSelect: onItemSelect }, item.id))) })] }, section.id))) }));
22
29
  }
23
30
  function SectionedWorkspaceNavigationItem({ active, item, onItemSelect }) {
24
- const content = (_jsxs("span", { className: "zvk-composite-sectioned-workspace-shell__nav-item-content", children: [_jsx("span", { className: "zvk-composite-sectioned-workspace-shell__nav-item-label", children: item.label }), item.description ? (_jsx("span", { className: "zvk-composite-sectioned-workspace-shell__nav-item-description", children: item.description })) : null] }));
31
+ const content = (_jsxs("span", { className: "zvk-composite-sectioned-workspace-shell__nav-item-content", children: [_jsx("span", { className: "zvk-composite-sectioned-workspace-shell__nav-item-label", children: item.label }), hasRenderableShellSlot(item.description) ? (_jsx("span", { className: "zvk-composite-sectioned-workspace-shell__nav-item-description", children: item.description })) : null] }));
25
32
  const handleSelect = () => onItemSelect?.(item.id);
26
33
  const itemProps = {
27
34
  ...(item.badge === undefined ? {} : { badge: item.badge }),
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ import type { WorkspaceHeaderAlign } from "./workspace-header.js";
3
+ export declare function hasRenderableShellSlot(value: React.ReactNode): boolean;
4
+ export interface ShellHeaderChromeProps {
5
+ actions?: React.ReactNode | undefined;
6
+ align?: WorkspaceHeaderAlign | undefined;
7
+ className?: string | undefined;
8
+ description?: React.ReactNode | undefined;
9
+ eyebrow?: React.ReactNode | undefined;
10
+ status?: React.ReactNode | undefined;
11
+ toolbar?: React.ReactNode | undefined;
12
+ }
13
+ export declare function ShellHeaderChrome({ actions, align, className, description, eyebrow, status, toolbar }: ShellHeaderChromeProps): React.JSX.Element | null;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../utils/cn.js";
4
+ export function hasRenderableShellSlot(value) {
5
+ if (value === undefined || value === null || typeof value === "boolean") {
6
+ return false;
7
+ }
8
+ if (typeof value === "string") {
9
+ return value.trim().length > 0;
10
+ }
11
+ return true;
12
+ }
13
+ export function ShellHeaderChrome({ actions, align = "start", className, description, eyebrow, status, toolbar }) {
14
+ const hasActions = hasRenderableShellSlot(actions);
15
+ const hasDescription = hasRenderableShellSlot(description);
16
+ const hasEyebrow = hasRenderableShellSlot(eyebrow);
17
+ const hasStatus = hasRenderableShellSlot(status);
18
+ const hasToolbar = hasRenderableShellSlot(toolbar);
19
+ const hasContent = hasEyebrow || hasStatus || hasDescription;
20
+ const hasControls = hasToolbar || hasActions;
21
+ if (!hasContent && !hasControls) {
22
+ return null;
23
+ }
24
+ return (_jsxs("div", { className: cn("zvk-composite-workspace-header", className), "data-align": align, children: [hasContent ? (_jsxs("div", { className: "zvk-composite-workspace-header__content", children: [hasEyebrow || hasStatus ? (_jsxs("div", { className: "zvk-composite-workspace-header__kicker", children: [hasEyebrow ? _jsx("span", { className: "zvk-composite-workspace-header__eyebrow", children: eyebrow }) : null, hasStatus ? _jsx("span", { className: "zvk-composite-workspace-header__status", children: status }) : null] })) : null, hasDescription ? (_jsx("div", { className: "zvk-composite-workspace-header__body", children: _jsx("p", { className: "zvk-composite-workspace-header__description", children: description }) })) : null] })) : (_jsx("div", { className: "zvk-composite-workspace-header__content", "aria-hidden": "true" })), hasControls ? (_jsxs("div", { className: "zvk-composite-workspace-header__controls", children: [hasToolbar ? _jsx("div", { className: "zvk-composite-workspace-header__toolbar", children: toolbar }) : null, hasActions ? _jsx("div", { className: "zvk-composite-workspace-header__actions", children: actions }) : null] })) : null] }));
25
+ }
@@ -0,0 +1,16 @@
1
+ import * as React from "react";
2
+ import type { WorkspaceHeaderHeadingLevel } from "./workspace-header.js";
3
+ export interface SimpleWorkspaceShellProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
4
+ actions?: React.ReactNode | undefined;
5
+ aside?: React.ReactNode | undefined;
6
+ children?: React.ReactNode | undefined;
7
+ description?: React.ReactNode | undefined;
8
+ footer?: React.ReactNode | undefined;
9
+ headingLevel?: WorkspaceHeaderHeadingLevel | undefined;
10
+ navigation?: React.ReactNode | undefined;
11
+ ref?: React.Ref<HTMLDivElement> | undefined;
12
+ status?: React.ReactNode | undefined;
13
+ title?: React.ReactNode | undefined;
14
+ toolbar?: React.ReactNode | undefined;
15
+ }
16
+ export declare function SimpleWorkspaceShell({ actions, aside, children, className, description, footer, headingLevel, navigation, ref, status, title, toolbar, ...props }: SimpleWorkspaceShellProps): React.JSX.Element;
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../utils/cn.js";
5
+ import { hasRenderableShellSlot, ShellHeaderChrome } from "./shell-slot-rendering.js";
6
+ import { WorkspaceHeader } from "./workspace-header.js";
7
+ export function SimpleWorkspaceShell({ actions, aside, children, className, description, footer, headingLevel, navigation, ref, status, title, toolbar, ...props }) {
8
+ const hasActions = hasRenderableShellSlot(actions);
9
+ const hasAside = hasRenderableShellSlot(aside);
10
+ const hasDescription = hasRenderableShellSlot(description);
11
+ const hasFooter = hasRenderableShellSlot(footer);
12
+ const hasNavigation = hasRenderableShellSlot(navigation);
13
+ const hasStatus = hasRenderableShellSlot(status);
14
+ const hasTitle = hasRenderableShellSlot(title);
15
+ const hasToolbar = hasRenderableShellSlot(toolbar);
16
+ const hasHeader = hasTitle || hasDescription || hasStatus || hasToolbar || hasActions;
17
+ const headerProps = {
18
+ ...(hasActions ? { actions } : {}),
19
+ ...(hasDescription ? { description } : {}),
20
+ ...(headingLevel === undefined ? {} : { headingLevel }),
21
+ ...(hasStatus ? { status } : {}),
22
+ ...(hasToolbar ? { toolbar } : {})
23
+ };
24
+ return (_jsxs("div", { ...props, ref: ref, className: cn("zvk-composite-simple-workspace-shell", className), "data-with-aside": hasAside ? "true" : undefined, "data-with-navigation": hasNavigation ? "true" : undefined, children: [hasNavigation ? (_jsx("nav", { className: "zvk-composite-simple-workspace-shell__navigation", "aria-label": "Workspace navigation", children: navigation })) : null, _jsxs("div", { className: "zvk-composite-simple-workspace-shell__body", children: [hasHeader && hasTitle ? (_jsx(WorkspaceHeader, { ...headerProps, className: "zvk-composite-simple-workspace-shell__header", title: title })) : hasHeader ? (_jsx(ShellHeaderChrome, { actions: actions, className: "zvk-composite-simple-workspace-shell__header", description: description, status: status, toolbar: toolbar })) : null, _jsxs("div", { className: "zvk-composite-simple-workspace-shell__grid", children: [_jsx("main", { className: "zvk-composite-simple-workspace-shell__main", children: children }), hasAside ? _jsx("aside", { className: "zvk-composite-simple-workspace-shell__aside", children: aside }) : null] }), hasFooter ? (_jsx("footer", { className: "zvk-composite-simple-workspace-shell__footer", children: footer })) : null] })] }));
25
+ }
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ import type { SplitterValue } from "@zvk/ui/splitter";
3
+ import type { WorkspaceHeaderHeadingLevel } from "./workspace-header.js";
4
+ export interface SplitWorkspaceShellProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "defaultValue" | "title"> {
5
+ actions?: React.ReactNode | undefined;
6
+ collapsiblePrimary?: boolean | undefined;
7
+ defaultValue?: SplitterValue | undefined;
8
+ description?: React.ReactNode | undefined;
9
+ footer?: React.ReactNode | undefined;
10
+ headingLevel?: WorkspaceHeaderHeadingLevel | undefined;
11
+ maxPrimarySize?: number | undefined;
12
+ minPrimarySize?: number | undefined;
13
+ onResizeEnd?: ((value: SplitterValue) => void) | undefined;
14
+ onValueChange?: ((value: SplitterValue) => void) | undefined;
15
+ primary: React.ReactNode;
16
+ primaryLabel?: string | undefined;
17
+ ref?: React.Ref<HTMLDivElement> | undefined;
18
+ secondary: React.ReactNode;
19
+ secondaryLabel?: string | undefined;
20
+ title?: React.ReactNode | undefined;
21
+ toolbar?: React.ReactNode | undefined;
22
+ value?: SplitterValue | undefined;
23
+ }
24
+ export declare function SplitWorkspaceShell({ actions, className, collapsiblePrimary, defaultValue, description, footer, headingLevel, maxPrimarySize, minPrimarySize, onResizeEnd, onValueChange, primary, primaryLabel, ref, secondary, secondaryLabel, title, toolbar, value, ...props }: SplitWorkspaceShellProps): React.JSX.Element;
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Splitter } from "@zvk/ui/splitter";
5
+ import { cn } from "../utils/cn.js";
6
+ import { hasRenderableShellSlot, ShellHeaderChrome } from "./shell-slot-rendering.js";
7
+ import { WorkspaceHeader } from "./workspace-header.js";
8
+ export function SplitWorkspaceShell({ actions, className, collapsiblePrimary = false, defaultValue = [32, 68], description, footer, headingLevel, maxPrimarySize, minPrimarySize = 18, onResizeEnd, onValueChange, primary, primaryLabel = "Primary workspace pane", ref, secondary, secondaryLabel = "Secondary workspace pane", title, toolbar, value, ...props }) {
9
+ const hasActions = hasRenderableShellSlot(actions);
10
+ const hasDescription = hasRenderableShellSlot(description);
11
+ const hasFooter = hasRenderableShellSlot(footer);
12
+ const hasTitle = hasRenderableShellSlot(title);
13
+ const hasToolbar = hasRenderableShellSlot(toolbar);
14
+ const hasHeader = hasTitle || hasDescription || hasToolbar || hasActions;
15
+ const splitterProps = {
16
+ defaultValue,
17
+ ...(onResizeEnd === undefined ? {} : { onResizeEnd }),
18
+ ...(onValueChange === undefined ? {} : { onValueChange }),
19
+ ...(value === undefined ? {} : { value })
20
+ };
21
+ const primaryPanelProps = {
22
+ ...(maxPrimarySize === undefined ? {} : { maxSize: maxPrimarySize }),
23
+ minSize: minPrimarySize
24
+ };
25
+ const headerProps = {
26
+ ...(hasActions ? { actions } : {}),
27
+ ...(hasDescription ? { description } : {}),
28
+ ...(headingLevel === undefined ? {} : { headingLevel }),
29
+ ...(hasToolbar ? { toolbar } : {})
30
+ };
31
+ return (_jsxs("div", { ...props, ref: ref, className: cn("zvk-composite-split-workspace-shell", className), children: [hasHeader && hasTitle ? (_jsx(WorkspaceHeader, { ...headerProps, className: "zvk-composite-split-workspace-shell__header", title: title })) : hasHeader ? (_jsx(ShellHeaderChrome, { actions: actions, className: "zvk-composite-split-workspace-shell__header", description: description, toolbar: toolbar })) : null, _jsxs(Splitter, { ...splitterProps, className: "zvk-composite-split-workspace-shell__splitter", children: [_jsx(Splitter.Panel, { ...primaryPanelProps, "aria-label": primaryLabel, className: "zvk-composite-split-workspace-shell__pane", collapsible: collapsiblePrimary, children: primary }), _jsx(Splitter.Handle, { "aria-label": `Resize ${primaryLabel}` }), _jsx(Splitter.Panel, { "aria-label": secondaryLabel, className: "zvk-composite-split-workspace-shell__pane zvk-composite-split-workspace-shell__pane--secondary", children: secondary })] }), hasFooter ? (_jsx("footer", { className: "zvk-composite-split-workspace-shell__footer", children: footer })) : null] }));
32
+ }
package/dist/styles.css CHANGED
@@ -251,26 +251,6 @@
251
251
  }
252
252
 
253
253
 
254
- /* src/layout/feature-shell.css */
255
- @layer zvk-composite-components {
256
- :where(.zvk-composite-feature-shell) {
257
- container-type: inline-size;
258
- min-inline-size: 0;
259
- width: 100%;
260
- }
261
-
262
- @container (max-width: 36rem) {
263
- :where(.zvk-composite-feature-shell .zvk-composite-workspace-header) {
264
- grid-template-columns: minmax(0, 1fr);
265
- }
266
-
267
- :where(.zvk-composite-feature-shell .zvk-composite-workspace-header__controls) {
268
- justify-content: start;
269
- }
270
- }
271
- }
272
-
273
-
274
254
  /* src/navigation/app-workspace-shell.css */
275
255
  @layer zvk-composite-components {
276
256
  :where(.zvk-composite-app-workspace-shell) {
@@ -686,6 +666,95 @@
686
666
  }
687
667
 
688
668
 
669
+ /* src/navigation/resource-explorer-shell.css */
670
+ @layer zvk-composite-components {
671
+ :where(.zvk-composite-resource-explorer-shell) {
672
+ color: var(--zvk-ui-color-foreground);
673
+ container: zvk-composite-resource-explorer-shell / inline-size;
674
+ display: grid;
675
+ font-family: var(--zvk-ui-font-family-primary);
676
+ gap: var(--zvk-ui-space-4);
677
+ grid-template-columns: minmax(14rem, 18rem) minmax(0, 1fr) minmax(16rem, 22rem);
678
+ min-block-size: 0;
679
+ min-inline-size: 0;
680
+ }
681
+
682
+ :where(.zvk-composite-resource-explorer-shell:not([data-with-preview="true"])) {
683
+ grid-template-columns: minmax(14rem, 18rem) minmax(0, 1fr);
684
+ }
685
+
686
+ :where(.zvk-composite-resource-explorer-shell__tree),
687
+ :where(.zvk-composite-resource-explorer-shell__results),
688
+ :where(.zvk-composite-resource-explorer-shell__preview) {
689
+ background: var(--zvk-ui-color-surface);
690
+ border: 1px solid var(--zvk-ui-color-border);
691
+ border-radius: var(--zvk-ui-radius-md);
692
+ box-shadow: var(--zvk-ui-shadow-xs);
693
+ display: grid;
694
+ gap: var(--zvk-ui-space-3);
695
+ min-block-size: 0;
696
+ min-inline-size: 0;
697
+ padding: var(--zvk-ui-space-3);
698
+ }
699
+
700
+ :where(.zvk-composite-resource-explorer-shell__tree-header),
701
+ :where(.zvk-composite-resource-explorer-shell__toolbar),
702
+ :where(.zvk-composite-resource-explorer-shell__footer) {
703
+ color: var(--zvk-ui-color-muted-foreground);
704
+ font-size: var(--zvk-ui-font-size-sm);
705
+ }
706
+
707
+ :where(.zvk-composite-resource-explorer-shell__tree-header) {
708
+ color: var(--zvk-ui-color-foreground);
709
+ font-family: var(--zvk-ui-font-family-secondary);
710
+ }
711
+
712
+ :where(.zvk-composite-resource-explorer-shell__search) {
713
+ align-items: center;
714
+ display: flex;
715
+ flex-wrap: wrap;
716
+ gap: var(--zvk-ui-space-2);
717
+ min-inline-size: min(100%, 12rem);
718
+ }
719
+
720
+ :where(.zvk-composite-resource-explorer-shell__search > *) {
721
+ flex: 1 1 12rem;
722
+ min-inline-size: 0;
723
+ }
724
+
725
+ :where(.zvk-composite-resource-explorer-shell__search :is(input, select, textarea, .zvk-ui-input, .zvk-ui-select__trigger)) {
726
+ inline-size: 100%;
727
+ max-inline-size: 100%;
728
+ }
729
+
730
+ :where(.zvk-composite-resource-explorer-shell__tree-item) {
731
+ align-items: center;
732
+ display: inline-flex;
733
+ gap: var(--zvk-ui-space-2);
734
+ min-inline-size: 0;
735
+ }
736
+
737
+ :where(.zvk-composite-resource-explorer-shell__tree-item-icon) {
738
+ color: var(--zvk-ui-color-muted-foreground);
739
+ display: inline-flex;
740
+ }
741
+
742
+ @container zvk-composite-resource-explorer-shell (max-width: 72rem) {
743
+ :where(.zvk-composite-resource-explorer-shell),
744
+ :where(.zvk-composite-resource-explorer-shell:not([data-with-preview="true"])) {
745
+ grid-template-columns: 1fr;
746
+ }
747
+ }
748
+
749
+ @media (max-width: 72rem) {
750
+ :where(.zvk-composite-resource-explorer-shell),
751
+ :where(.zvk-composite-resource-explorer-shell:not([data-with-preview="true"])) {
752
+ grid-template-columns: 1fr;
753
+ }
754
+ }
755
+ }
756
+
757
+
689
758
  /* src/navigation/sectioned-workspace-shell.css */
690
759
  @layer zvk-composite-components {
691
760
  :where(.zvk-composite-sectioned-workspace-shell) {
@@ -806,6 +875,130 @@
806
875
  }
807
876
 
808
877
 
878
+ /* src/navigation/simple-workspace-shell.css */
879
+ @layer zvk-composite-components {
880
+ :where(.zvk-composite-simple-workspace-shell) {
881
+ color: var(--zvk-ui-color-foreground);
882
+ container: zvk-composite-simple-workspace-shell / inline-size;
883
+ display: grid;
884
+ font-family: var(--zvk-ui-font-family-primary);
885
+ gap: var(--zvk-ui-space-5);
886
+ grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr);
887
+ min-inline-size: 0;
888
+ }
889
+
890
+ :where(.zvk-composite-simple-workspace-shell:not([data-with-navigation="true"])) {
891
+ grid-template-columns: minmax(0, 1fr);
892
+ }
893
+
894
+ :where(.zvk-composite-simple-workspace-shell__navigation),
895
+ :where(.zvk-composite-simple-workspace-shell__aside) {
896
+ background: var(--zvk-ui-color-surface);
897
+ border: 1px solid var(--zvk-ui-color-border);
898
+ border-radius: var(--zvk-ui-radius-md);
899
+ box-shadow: var(--zvk-ui-shadow-xs);
900
+ min-inline-size: 0;
901
+ padding: var(--zvk-ui-space-3);
902
+ }
903
+
904
+ :where(.zvk-composite-simple-workspace-shell__body) {
905
+ display: grid;
906
+ gap: var(--zvk-ui-space-5);
907
+ min-inline-size: 0;
908
+ }
909
+
910
+ :where(.zvk-composite-simple-workspace-shell__header) {
911
+ border-block-end: 1px solid var(--zvk-ui-color-border);
912
+ padding-block-end: var(--zvk-ui-space-4);
913
+ }
914
+
915
+ :where(.zvk-composite-simple-workspace-shell__grid) {
916
+ align-items: start;
917
+ display: grid;
918
+ gap: var(--zvk-ui-space-5);
919
+ grid-template-columns: minmax(0, 1fr);
920
+ min-inline-size: 0;
921
+ }
922
+
923
+ :where(.zvk-composite-simple-workspace-shell[data-with-aside="true"] .zvk-composite-simple-workspace-shell__grid) {
924
+ grid-template-columns: minmax(0, 1fr) minmax(15rem, 22rem);
925
+ }
926
+
927
+ :where(.zvk-composite-simple-workspace-shell__main) {
928
+ display: grid;
929
+ gap: var(--zvk-ui-space-4);
930
+ min-inline-size: 0;
931
+ }
932
+
933
+ :where(.zvk-composite-simple-workspace-shell__footer) {
934
+ border-block-start: 1px solid var(--zvk-ui-color-border);
935
+ color: var(--zvk-ui-color-muted-foreground);
936
+ font-size: var(--zvk-ui-font-size-sm);
937
+ padding-block-start: var(--zvk-ui-space-4);
938
+ }
939
+
940
+ @container zvk-composite-simple-workspace-shell (max-width: 64rem) {
941
+ :where(.zvk-composite-simple-workspace-shell),
942
+ :where(.zvk-composite-simple-workspace-shell[data-with-aside="true"] .zvk-composite-simple-workspace-shell__grid) {
943
+ grid-template-columns: 1fr;
944
+ }
945
+ }
946
+
947
+ @media (max-width: 64rem) {
948
+ :where(.zvk-composite-simple-workspace-shell),
949
+ :where(.zvk-composite-simple-workspace-shell[data-with-aside="true"] .zvk-composite-simple-workspace-shell__grid) {
950
+ grid-template-columns: 1fr;
951
+ }
952
+ }
953
+ }
954
+
955
+
956
+ /* src/navigation/split-workspace-shell.css */
957
+ @layer zvk-composite-components {
958
+ :where(.zvk-composite-split-workspace-shell) {
959
+ color: var(--zvk-ui-color-foreground);
960
+ display: grid;
961
+ font-family: var(--zvk-ui-font-family-primary);
962
+ gap: var(--zvk-ui-space-5);
963
+ min-block-size: 0;
964
+ min-inline-size: 0;
965
+ }
966
+
967
+ :where(.zvk-composite-split-workspace-shell__header) {
968
+ border-block-end: 1px solid var(--zvk-ui-color-border);
969
+ padding-block-end: var(--zvk-ui-space-4);
970
+ }
971
+
972
+ :where(.zvk-composite-split-workspace-shell__splitter) {
973
+ min-block-size: 28rem;
974
+ }
975
+
976
+ :where(.zvk-composite-split-workspace-shell__pane) {
977
+ background: var(--zvk-ui-color-surface);
978
+ border: 1px solid var(--zvk-ui-color-border);
979
+ border-radius: var(--zvk-ui-radius-md);
980
+ box-shadow: var(--zvk-ui-shadow-xs);
981
+ min-block-size: 0;
982
+ min-inline-size: 0;
983
+ overflow: auto;
984
+ padding: var(--zvk-ui-space-4);
985
+ }
986
+
987
+ :where(.zvk-composite-split-workspace-shell__pane--secondary) {
988
+ background:
989
+ linear-gradient(180deg, color-mix(in srgb, var(--zvk-ui-color-primary) 5%, transparent), transparent 12rem),
990
+ var(--zvk-ui-color-surface);
991
+ }
992
+
993
+ :where(.zvk-composite-split-workspace-shell__footer) {
994
+ border-block-start: 1px solid var(--zvk-ui-color-border);
995
+ color: var(--zvk-ui-color-muted-foreground);
996
+ font-size: var(--zvk-ui-font-size-sm);
997
+ padding-block-start: var(--zvk-ui-space-4);
998
+ }
999
+ }
1000
+
1001
+
809
1002
  /* src/navigation/workspace-header.css */
810
1003
  @layer zvk-composite-components {
811
1004
  :where(.zvk-composite-workspace-header) {
@@ -923,6 +1116,26 @@
923
1116
  }
924
1117
 
925
1118
 
1119
+ /* src/layout/feature-shell.css */
1120
+ @layer zvk-composite-components {
1121
+ :where(.zvk-composite-feature-shell) {
1122
+ container-type: inline-size;
1123
+ min-inline-size: 0;
1124
+ width: 100%;
1125
+ }
1126
+
1127
+ @container (max-width: 36rem) {
1128
+ :where(.zvk-composite-feature-shell .zvk-composite-workspace-header) {
1129
+ grid-template-columns: minmax(0, 1fr);
1130
+ }
1131
+
1132
+ :where(.zvk-composite-feature-shell .zvk-composite-workspace-header__controls) {
1133
+ justify-content: start;
1134
+ }
1135
+ }
1136
+ }
1137
+
1138
+
926
1139
  /* src/navigation/link-action.css */
927
1140
  @layer zvk-composite-components {
928
1141
  :where(.zvk-composite-link-action) {
@@ -2009,6 +2222,45 @@
2009
2222
  }
2010
2223
 
2011
2224
 
2225
+ /* src/workflows/wizard-shell.css */
2226
+ @layer zvk-composite-components {
2227
+ :where(.zvk-composite-wizard-shell) {
2228
+ color: var(--zvk-ui-color-foreground);
2229
+ display: grid;
2230
+ font-family: var(--zvk-ui-font-family-primary);
2231
+ gap: var(--zvk-ui-space-5);
2232
+ min-inline-size: 0;
2233
+ }
2234
+
2235
+ :where(.zvk-composite-wizard-shell__header),
2236
+ :where(.zvk-composite-wizard-shell__progress),
2237
+ :where(.zvk-composite-wizard-shell__footer) {
2238
+ border-block-end: 1px solid var(--zvk-ui-color-border);
2239
+ padding-block-end: var(--zvk-ui-space-4);
2240
+ }
2241
+
2242
+ :where(.zvk-composite-wizard-shell__content) {
2243
+ background: var(--zvk-ui-color-surface);
2244
+ border: 1px solid var(--zvk-ui-color-border);
2245
+ border-radius: var(--zvk-ui-radius-md);
2246
+ box-shadow: var(--zvk-ui-shadow-xs);
2247
+ display: grid;
2248
+ gap: var(--zvk-ui-space-4);
2249
+ min-inline-size: 0;
2250
+ padding: var(--zvk-ui-space-5);
2251
+ }
2252
+
2253
+ :where(.zvk-composite-wizard-shell__footer) {
2254
+ border-block-end: 0;
2255
+ border-block-start: 1px solid var(--zvk-ui-color-border);
2256
+ color: var(--zvk-ui-color-muted-foreground);
2257
+ font-size: var(--zvk-ui-font-size-sm);
2258
+ padding-block-end: 0;
2259
+ padding-block-start: var(--zvk-ui-space-4);
2260
+ }
2261
+ }
2262
+
2263
+
2012
2264
  /* src/settings/parameter-editor.css */
2013
2265
  @layer zvk-composite-components {
2014
2266
  :where(.zvk-composite-parameter-editor) {
@@ -0,0 +1,7 @@
1
+ interface UseControllableValueOptions<Value> {
2
+ defaultValue: Value;
3
+ onChange?: ((value: Value) => void) | undefined;
4
+ value?: Value | undefined;
5
+ }
6
+ export declare function useControllableValue<Value>({ defaultValue, onChange, value }: UseControllableValueOptions<Value>): readonly [Value, (nextValue: Value) => void];
7
+ export {};
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ export function useControllableValue({ defaultValue, onChange, value }) {
3
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
4
+ const resolvedValue = value ?? uncontrolledValue;
5
+ const setValue = React.useCallback((nextValue) => {
6
+ if (value === undefined) {
7
+ setUncontrolledValue(nextValue);
8
+ }
9
+ onChange?.(nextValue);
10
+ }, [onChange, value]);
11
+ return [resolvedValue, setValue];
12
+ }
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ import type { WorkspaceHeaderHeadingLevel } from "../navigation/workspace-header.js";
3
+ export type WizardShellStepStatus = "idle" | "current" | "complete" | "error" | "disabled";
4
+ export interface WizardShellStep {
5
+ description?: React.ReactNode | undefined;
6
+ disabled?: boolean | undefined;
7
+ id: string;
8
+ label: React.ReactNode;
9
+ status?: WizardShellStepStatus | undefined;
10
+ }
11
+ export interface WizardShellProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSubmit" | "title"> {
12
+ actions?: React.ReactNode | undefined;
13
+ children: React.ReactNode;
14
+ currentStepId: string;
15
+ description?: React.ReactNode | undefined;
16
+ footer?: React.ReactNode | undefined;
17
+ headingLevel?: WorkspaceHeaderHeadingLevel | undefined;
18
+ onStepChange?: ((stepId: string) => void) | undefined;
19
+ progress?: React.ReactNode | undefined;
20
+ ref?: React.Ref<HTMLDivElement> | undefined;
21
+ steps: readonly WizardShellStep[];
22
+ title: React.ReactNode;
23
+ }
24
+ export declare function WizardShell({ actions, children, className, currentStepId, description, footer, headingLevel, onStepChange, progress, ref, steps, title, ...props }: WizardShellProps): React.JSX.Element;