@zvk/composite 0.1.1 → 0.1.3
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/CHANGELOG.md +14 -0
- package/README.md +450 -0
- package/dist/activity/activity-feed.d.ts +27 -0
- package/dist/activity/activity-feed.js +30 -0
- package/dist/ai/conversation-directory.d.ts +31 -0
- package/dist/ai/conversation-directory.js +44 -0
- package/dist/ai/provider-model-selector.d.ts +31 -0
- package/dist/ai/provider-model-selector.js +41 -0
- package/dist/ai/sticky-composer.d.ts +14 -0
- package/dist/ai/sticky-composer.js +13 -0
- package/dist/data/data-table-control-bar.d.ts +13 -0
- package/dist/data/data-table-control-bar.js +11 -0
- package/dist/detail/detail-inspector-panel.d.ts +21 -0
- package/dist/detail/detail-inspector-panel.js +18 -0
- package/dist/domains/activity.d.ts +2 -0
- package/dist/domains/activity.js +1 -0
- package/dist/domains/ai.d.ts +6 -0
- package/dist/domains/ai.js +3 -0
- package/dist/domains/data.d.ts +10 -0
- package/dist/domains/data.js +5 -0
- package/dist/domains/detail.d.ts +2 -0
- package/dist/domains/detail.js +1 -0
- package/dist/domains/forms.d.ts +4 -0
- package/dist/domains/forms.js +2 -0
- package/dist/domains/navigation.d.ts +10 -0
- package/dist/domains/navigation.js +5 -0
- package/dist/domains/settings.d.ts +6 -0
- package/dist/domains/settings.js +3 -0
- package/dist/domains/shell.d.ts +6 -0
- package/dist/domains/shell.js +3 -0
- package/dist/domains/state.d.ts +4 -0
- package/dist/domains/state.js +2 -0
- package/dist/domains/workflow.d.ts +6 -0
- package/dist/domains/workflow.js +3 -0
- package/dist/index.d.ts +10 -24
- package/dist/index.js +10 -12
- package/dist/integrations/integration-status-card.d.ts +20 -0
- package/dist/integrations/integration-status-card.js +15 -0
- package/dist/layout/feature-shell.d.ts +13 -0
- package/dist/layout/feature-shell.js +7 -0
- package/dist/navigation/command-palette-shell.d.ts +31 -0
- package/dist/navigation/command-palette-shell.js +45 -0
- package/dist/navigation/entity-switcher-menu.d.ts +38 -0
- package/dist/navigation/entity-switcher-menu.js +56 -0
- package/dist/navigation/link-action.d.ts +11 -0
- package/dist/navigation/link-action.js +41 -0
- package/dist/navigation/sectioned-workspace-shell.d.ts +2 -1
- package/dist/navigation/sectioned-workspace-shell.js +2 -2
- package/dist/settings/parameter-editor.d.ts +27 -0
- package/dist/settings/parameter-editor.js +12 -0
- package/dist/settings/settings-section-stack.d.ts +20 -0
- package/dist/settings/settings-section-stack.js +10 -0
- package/dist/state/route-state-frame.d.ts +10 -0
- package/dist/state/route-state-frame.js +31 -0
- package/dist/styles.css +2120 -81
- package/dist/workflows/process-list-panel.d.ts +26 -0
- package/dist/workflows/process-list-panel.js +24 -0
- package/dist/workflows/workflow-status-card.d.ts +20 -0
- package/dist/workflows/workflow-status-card.js +46 -0
- package/package.json +112 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @zvk/composite Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.3](https://github.com/brandon-schabel/zvk/compare/composite-v0.1.2...composite-v0.1.3) (2026-06-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* improve package release workflow and repo maintainability ([#22](https://github.com/brandon-schabel/zvk/issues/22)) ([a41cb66](https://github.com/brandon-schabel/zvk/commit/a41cb66554496f241c5a8e30b29a76c8b8ca92b3))
|
|
9
|
+
|
|
10
|
+
## [0.1.2](https://github.com/brandon-schabel/zvk/compare/composite-v0.1.1...composite-v0.1.2) (2026-06-19)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* add theme presets and package improvements ([#19](https://github.com/brandon-schabel/zvk/issues/19)) ([867f955](https://github.com/brandon-schabel/zvk/commit/867f9556f7a60144cad4e747f2c032f2d5ede353))
|
|
16
|
+
|
|
3
17
|
## [0.1.1](https://github.com/brandon-schabel/zvk/compare/composite-v0.1.0...composite-v0.1.1) (2026-06-16)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -10,3 +10,453 @@ import "@zvk/composite/styles.css";
|
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Components are UI-only and accept typed props, slots, and callbacks. They do not own routing, persistence, data fetching, authentication, billing, or business rules.
|
|
13
|
+
|
|
14
|
+
Composite typography inherits the shared `@zvk/ui` font-family slots: primary for body/control text, secondary for titles and navigation accents, and tertiary wherever composed UI primitives render code or technical values.
|
|
15
|
+
|
|
16
|
+
## Domain Ownership
|
|
17
|
+
|
|
18
|
+
The package is organized around product-surface domains so repeated shell structure stays readable without creating new public import groups. This map is for internal ownership and review; it does not add domain barrel imports to the public API.
|
|
19
|
+
|
|
20
|
+
- `shell`: `AppWorkspaceShell`, `PageScaffold`, `FeatureShell`
|
|
21
|
+
- `navigation`: `WorkspaceHeader`, `BreadcrumbPageHeader`, `SectionedWorkspaceShell`, `EntitySwitcherMenu`, `CommandPaletteShell`, `LinkAction`
|
|
22
|
+
- `state`: `StateSurface`, `RouteStateFrame`
|
|
23
|
+
- `forms`: `FormSurface`, `ConfirmActionDialog`
|
|
24
|
+
- `data`: `EntityCard`, `EntityListSection`, `SummaryMetricGrid`, `DataTablePageFrame`, `DataTableControlBar`
|
|
25
|
+
- `workflow`: `IntegrationStatusCard`, `WorkflowStatusCard`, `ProcessListPanel`
|
|
26
|
+
- `settings`: `SettingsHubList`, `ParameterEditor`, `SettingsSectionStack`
|
|
27
|
+
- `ai`: `ProviderModelSelector`, `ConversationDirectory`, `StickyComposer`
|
|
28
|
+
- `activity`: `ActivityFeed`
|
|
29
|
+
- `detail`: `DetailInspectorPanel`
|
|
30
|
+
|
|
31
|
+
## What Composite Does Not Own
|
|
32
|
+
|
|
33
|
+
`@zvk/composite` owns repeated product-surface structure, semantic markup, accessible labels for the UI it renders, token-backed spacing, density-aware layout, and typed slots. It deliberately does not own app policy or runtime orchestration.
|
|
34
|
+
|
|
35
|
+
Keep these in the consuming app or a more specific package:
|
|
36
|
+
|
|
37
|
+
- routing, link components, active route state, and query params;
|
|
38
|
+
- data fetching, caching, mutations, optimistic updates, polling, subscriptions, and streaming;
|
|
39
|
+
- auth, billing, entitlements, permission checks, and organization policy;
|
|
40
|
+
- form state, validation, dirty-state detection, persistence, and schema interpretation;
|
|
41
|
+
- table engines, sorting, filtering, pagination, row selection, saved-view state, and column visibility;
|
|
42
|
+
- AI provider catalogs, model compatibility, prompt state, tool execution, attachments, message history, and AI SDK integration;
|
|
43
|
+
- analytics, telemetry, business copy, domain transforms, date formatting, and error classification.
|
|
44
|
+
|
|
45
|
+
## Public Stability
|
|
46
|
+
|
|
47
|
+
- All current component subpaths and the root export are stable public API.
|
|
48
|
+
- Watched surfaces may evolve only through additive, UI-only props, callbacks, and tests; keep them app-agnostic and preserve the current import paths.
|
|
49
|
+
- `./styles.css` is a stable stylesheet export.
|
|
50
|
+
- `./package.json` is stable metadata and tooling export, not a component surface.
|
|
51
|
+
|
|
52
|
+
Watched surfaces: `EntitySwitcherMenu`, `CommandPaletteShell`, `ConfirmActionDialog`, `IntegrationStatusCard`, `WorkflowStatusCard`, `ProcessListPanel`, `ActivityFeed`, `ParameterEditor`, `ProviderModelSelector`, `ConversationDirectory`, `StickyComposer`, and `DataTableControlBar`.
|
|
53
|
+
|
|
54
|
+
## App Surface Exports
|
|
55
|
+
|
|
56
|
+
App surfaces are intentionally router-agnostic and UI-only:
|
|
57
|
+
|
|
58
|
+
| Surface | Import | Purpose |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| `AppWorkspaceShell` | `@zvk/composite/app-workspace-shell` | Product workspace chrome with brand, navigation, switcher, command, header, content, account, and footer slots. |
|
|
61
|
+
| `EntitySwitcherMenu` | `@zvk/composite/entity-switcher-menu` | Searchable context switcher for app-owned workspaces, projects, accounts, repositories, or environments. |
|
|
62
|
+
| `CommandPaletteShell` | `@zvk/composite/command-palette-shell` | Controlled command palette dialog with grouped commands and app-owned command execution. |
|
|
63
|
+
| `WorkspaceHeader` | `@zvk/composite/workspace-header` | Page header with title, description, status, metadata, and actions. |
|
|
64
|
+
| `BreadcrumbPageHeader` | `@zvk/composite/breadcrumb-page-header` | Breadcrumb-aware page header for nested workspace routes. |
|
|
65
|
+
| `SectionedWorkspaceShell` | `@zvk/composite/sectioned-workspace-shell` | Sectioned navigation shell for dense workspace panels. |
|
|
66
|
+
| `PageScaffold` | `@zvk/composite/page-scaffold` | Page layout with toolbar, aside, constrained width, and content slots. |
|
|
67
|
+
| `FeatureShell` | `@zvk/composite/feature-shell` | Reusable feature page layout with title, description, actions, metadata, and toolbar slots. |
|
|
68
|
+
| `StateSurface` | `@zvk/composite/state-surface` | Empty, loading, error, permission, success, and search-empty state panels. |
|
|
69
|
+
| `RouteStateFrame` | `@zvk/composite/route-state-frame` | Route-level view states for `loading`, `empty`, `error`, `not-found`, and `ready`. |
|
|
70
|
+
| `EntityCard` | `@zvk/composite/entity-card` | Selectable entity card with icon, title, description, badges, metadata, and actions. |
|
|
71
|
+
| `EntityListSection` | `@zvk/composite/entity-list-section` | List section wrapper with app-owned item rendering. |
|
|
72
|
+
| `SummaryMetricGrid` | `@zvk/composite/summary-metric-grid` | Metric cards for dashboards and operational summaries. |
|
|
73
|
+
| `SettingsHubList` | `@zvk/composite/settings-hub-list` | Settings index list with route-free items, badges, metadata, and disabled state. |
|
|
74
|
+
| `FormSurface` | `@zvk/composite/form-surface` | Native form shell for app-owned fields and submit handling. |
|
|
75
|
+
| `ConfirmActionDialog` | `@zvk/composite/confirm-action-dialog` | Confirmation dialog for destructive, primary, or neutral actions. |
|
|
76
|
+
| `IntegrationStatusCard` | `@zvk/composite/integration-status-card` | Provider/API/service connection status card with status, badges, metadata, metrics, actions, and errors. |
|
|
77
|
+
| `WorkflowStatusCard` | `@zvk/composite/workflow-status-card` | Workflow, run, import, queue, deploy, or parser status card with progress and current-step slots. |
|
|
78
|
+
| `ProcessListPanel` | `@zvk/composite/process-list-panel` | List panel for app-owned background work items, rendered by default through workflow status cards. |
|
|
79
|
+
| `ActivityFeed` | `@zvk/composite/activity-feed` | Ordered activity, audit, workflow, comment, or notification feed with app-owned ordering and timestamps. |
|
|
80
|
+
| `ParameterEditor` | `@zvk/composite/parameter-editor` | Grouped parameter/settings rows where controls, validation, persistence, and reset actions stay in the app. |
|
|
81
|
+
| `SettingsSectionStack` | `@zvk/composite/settings-section-stack` | Settings page section stack with controlled dirty/save presentation and app-owned forms. |
|
|
82
|
+
| `ProviderModelSelector` | `@zvk/composite/provider-model-selector` | Two-level provider/model, service/variant, or environment/resource selector where catalogs and constraints stay in the app. |
|
|
83
|
+
| `ConversationDirectory` | `@zvk/composite/conversation-directory` | Searchable/selectable conversation or record directory for app-owned AI workspaces. |
|
|
84
|
+
| `StickyComposer` | `@zvk/composite/sticky-composer` | Sticky prompt/input form shell with app-owned state, validation, tools, streaming, and submit effects. |
|
|
85
|
+
| `DetailInspectorPanel` | `@zvk/composite/detail-inspector-panel` | Right-side detail, metadata, review, or audit panel for selected app-owned entities. |
|
|
86
|
+
| `DataTableControlBar` | `@zvk/composite/data-table-control-bar` | Controller-free table toolbar for app-owned search, filters, views, density, columns, selection, and actions. |
|
|
87
|
+
| `DataTablePageFrame` | `@zvk/composite/data-table-page-frame` | Table page frame for app-owned search, filters, rows, pagination, loading, and empty state. |
|
|
88
|
+
| `LinkAction` | `@zvk/composite/link-action` | Anchor styled like a `@zvk/ui` button, with button variants and sizes. |
|
|
89
|
+
|
|
90
|
+
Use root imports when a file composes several surfaces together:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import {
|
|
94
|
+
AppWorkspaceShell,
|
|
95
|
+
PageScaffold,
|
|
96
|
+
RouteStateFrame,
|
|
97
|
+
WorkspaceHeader
|
|
98
|
+
} from "@zvk/composite";
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Use focused subpath imports when a file consumes one or two surfaces:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { FeatureShell } from "@zvk/composite/feature-shell";
|
|
105
|
+
import { RouteStateFrame } from "@zvk/composite/route-state-frame";
|
|
106
|
+
import { LinkAction } from "@zvk/composite/link-action";
|
|
107
|
+
|
|
108
|
+
<FeatureShell
|
|
109
|
+
title="Projects"
|
|
110
|
+
description="Use this workspace to review active work."
|
|
111
|
+
actions={<LinkAction href="/projects/new">New project</LinkAction>}
|
|
112
|
+
>
|
|
113
|
+
<RouteStateFrame status="ready">...</RouteStateFrame>
|
|
114
|
+
</FeatureShell>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
These components should stay focused on visual structure, semantics, and affordances; routing, domain mapping, and data orchestration remain in the consuming app.
|
|
118
|
+
|
|
119
|
+
## Future Feature Acceptance
|
|
120
|
+
|
|
121
|
+
Accept a new composite only when all of these are true:
|
|
122
|
+
|
|
123
|
+
- [ ] It replaces repeated product-surface structure, not a primitive control or wrapper `div`.
|
|
124
|
+
- [ ] Its name and props stay app-agnostic.
|
|
125
|
+
- [ ] It composes public `@zvk/ui` exports, existing public composites, or local presentational helpers only.
|
|
126
|
+
- [ ] Routing, persistence, data fetching, auth, billing, validation, table engines, AI SDKs, analytics, policy checks, and business rules stay in the app or a more specific package.
|
|
127
|
+
- [ ] It fits an existing domain owner or clearly justifies a new owner in this README and the composite skill.
|
|
128
|
+
- [ ] It can be covered by package export map, root export, internal domain barrel, CSS aggregate, type fixture, SSR import smoke, export validation, tarball inspection, README guidance, preview example, and skill update.
|
|
129
|
+
- [ ] It remains SSR-safe at module initialization and deterministic in initial render.
|
|
130
|
+
|
|
131
|
+
## Migration Guide
|
|
132
|
+
|
|
133
|
+
Migrate repeated app-owned shells into `@zvk/composite` only when the repeated part is visual structure and interaction affordance, not domain behavior.
|
|
134
|
+
|
|
135
|
+
| Repeated app surface | Composite target | Keep in the app |
|
|
136
|
+
| --- | --- | --- |
|
|
137
|
+
| Product workspace chrome with brand, account, nav, switcher, command, and content slots | `AppWorkspaceShell` | route tree, auth context, workspace persistence, account menu actions |
|
|
138
|
+
| Tab-with-sidebar or dense route workspace wrappers | `SectionedWorkspaceShell` | active route, URL updates, permission gating, tab persistence |
|
|
139
|
+
| Route/page loading, empty, permission, error, and ready wrappers | `RouteStateFrame` or `StateSurface` | loader state, retry mutations, fetch errors, domain-specific empty data |
|
|
140
|
+
| Page headers and breadcrumb headers | `WorkspaceHeader` or `BreadcrumbPageHeader` | router links, breadcrumb construction, page-level data policy |
|
|
141
|
+
| Settings index pages and settings detail pages | `SettingsHubList` or `SettingsSectionStack` | route anchors, dirty-state calculation, validation, persistence, permission decisions |
|
|
142
|
+
| Provider/API status cards, workflow cards, and process lists | `IntegrationStatusCard`, `WorkflowStatusCard`, or `ProcessListPanel` | health checks, polling, process control, retries, logs, provider credentials |
|
|
143
|
+
| Audit logs, run histories, review threads, and notification feeds | `ActivityFeed` | event fetching, ordering, timestamps, subscriptions, comment mutations, infinite scroll |
|
|
144
|
+
| AI model choices, conversation sidebars, and sticky prompt forms | `ProviderModelSelector`, `ConversationDirectory`, or `StickyComposer` | catalogs, compatibility rules, message fetching, prompt validation, streaming, tools, persistence |
|
|
145
|
+
| Table page wrappers and table control bars | `DataTablePageFrame` or `DataTableControlBar` | table engine adapters, query state, sorting, filters, pagination, row selection, saved views |
|
|
146
|
+
| Selected-row or selected-record inspectors | `DetailInspectorPanel` | selected entity state, fetching, route params, drawer/sheet state, audit queries |
|
|
147
|
+
|
|
148
|
+
## Sectioned Workspace Shells
|
|
149
|
+
|
|
150
|
+
`SectionedWorkspaceShell` is the migration target for repeated tab-with-sidebar or dense workspace wrappers. Use it when an app already owns the active tab, routes, permissions, and data loading, but repeats the same sidebar/header/content frame.
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
import { SectionedWorkspaceShell } from "@zvk/composite/sectioned-workspace-shell";
|
|
154
|
+
|
|
155
|
+
<SectionedWorkspaceShell
|
|
156
|
+
activeItemId="runs"
|
|
157
|
+
navLabel="Automation workspace navigation"
|
|
158
|
+
onItemSelect={(itemId) => {
|
|
159
|
+
// Route, persist, or guard in the app.
|
|
160
|
+
}}
|
|
161
|
+
sections={[
|
|
162
|
+
{
|
|
163
|
+
id: "operations",
|
|
164
|
+
label: "Operations",
|
|
165
|
+
items: [
|
|
166
|
+
{ id: "runs", label: "Runs", description: "Recent automation history" },
|
|
167
|
+
{ id: "logs", label: "Logs", href: "/automation/logs" },
|
|
168
|
+
{ id: "limits", label: "Limits", disabled: true }
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
]}
|
|
172
|
+
sidebarFooter="Route state, permissions, and tab persistence stay in the app."
|
|
173
|
+
title="Automation workspace"
|
|
174
|
+
toolbar="Filters"
|
|
175
|
+
>
|
|
176
|
+
...
|
|
177
|
+
</SectionedWorkspaceShell>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
When replacing an app-owned `*-tab-with-sidebar.tsx` wrapper, map repeated shell pieces directly: wrapper title to `title`, tab/sidebar groups to `sections`, active route key to `activeItemId`, app navigation labels to `navLabel`, and local helper text to `sidebarFooter` or `footer`. Keep route objects, loaders, permission checks, query params, and product-specific empty states in the app.
|
|
181
|
+
|
|
182
|
+
## Navigation Accelerators
|
|
183
|
+
|
|
184
|
+
`EntitySwitcherMenu` and `CommandPaletteShell` provide reusable command/navigation shells while leaving persistence, routing, recent-item storage, shortcuts, and side effects in the app:
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
import { CommandPaletteShell } from "@zvk/composite/command-palette-shell";
|
|
188
|
+
import { EntitySwitcherMenu } from "@zvk/composite/entity-switcher-menu";
|
|
189
|
+
|
|
190
|
+
<EntitySwitcherMenu
|
|
191
|
+
current={{ id: "northline", label: "Northline" }}
|
|
192
|
+
groups={[{ id: "recent", items: [{ id: "northline", label: "Northline" }] }]}
|
|
193
|
+
label="Workspace"
|
|
194
|
+
onSelect={(item) => {
|
|
195
|
+
// Route or persist in the app.
|
|
196
|
+
}}
|
|
197
|
+
/>;
|
|
198
|
+
|
|
199
|
+
<CommandPaletteShell
|
|
200
|
+
groups={[{ id: "navigation", commands: [{ id: "runs", label: "Open runs" }] }]}
|
|
201
|
+
onCommandSelect={(command) => {
|
|
202
|
+
// Execute in the app.
|
|
203
|
+
}}
|
|
204
|
+
onOpenChange={setOpen}
|
|
205
|
+
open={open}
|
|
206
|
+
/>;
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Status Accelerators
|
|
210
|
+
|
|
211
|
+
`IntegrationStatusCard` and `WorkflowStatusCard` cover repeated provider/API and run/progress panels without owning health checks, polling, queues, retries, logs, or process control:
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
import { IntegrationStatusCard } from "@zvk/composite/integration-status-card";
|
|
215
|
+
import { WorkflowStatusCard } from "@zvk/composite/workflow-status-card";
|
|
216
|
+
|
|
217
|
+
<IntegrationStatusCard
|
|
218
|
+
actions={<button type="button">Test</button>}
|
|
219
|
+
metadata="Checked 1 minute ago"
|
|
220
|
+
status="Connected"
|
|
221
|
+
statusTone="success"
|
|
222
|
+
title="OpenAI"
|
|
223
|
+
/>;
|
|
224
|
+
|
|
225
|
+
<WorkflowStatusCard
|
|
226
|
+
currentStep="Extracting line items"
|
|
227
|
+
progressLabel="42%"
|
|
228
|
+
progressValue={42}
|
|
229
|
+
status="Running"
|
|
230
|
+
title="Proposal parse"
|
|
231
|
+
tone="running"
|
|
232
|
+
/>;
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`ProcessListPanel` turns repeated background-work lists into a reusable shell while keeping grouping, actions, logs, and lifecycle state in the app:
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
import { ProcessListPanel } from "@zvk/composite/process-list-panel";
|
|
239
|
+
|
|
240
|
+
<ProcessListPanel
|
|
241
|
+
items={[
|
|
242
|
+
{
|
|
243
|
+
id: "parse-run",
|
|
244
|
+
title: "Proposal parse",
|
|
245
|
+
status: "Running",
|
|
246
|
+
tone: "running",
|
|
247
|
+
progressValue: 42,
|
|
248
|
+
progressLabel: "42%"
|
|
249
|
+
}
|
|
250
|
+
]}
|
|
251
|
+
title="Background work"
|
|
252
|
+
/>;
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`ActivityFeed` provides ordered activity, audit, run history, review, and notification markup without owning event fetching, ordering, date formatting, real-time subscriptions, virtualization, comment mutation, or audit schemas.
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
import { ActivityFeed } from "@zvk/composite/activity-feed";
|
|
259
|
+
|
|
260
|
+
<ActivityFeed
|
|
261
|
+
groups={[
|
|
262
|
+
{
|
|
263
|
+
id: "today",
|
|
264
|
+
label: "Today",
|
|
265
|
+
items: [
|
|
266
|
+
{
|
|
267
|
+
id: "run-started",
|
|
268
|
+
title: "Parser run started",
|
|
269
|
+
description: "LandingAI accepted the uploaded plan.",
|
|
270
|
+
meta: "10:30 AM",
|
|
271
|
+
tone: "info"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
id: "review",
|
|
275
|
+
title: "Reviewer commented",
|
|
276
|
+
body: "Confirm the normalized line item group.",
|
|
277
|
+
tone: "warning"
|
|
278
|
+
}
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
]}
|
|
282
|
+
title="Activity"
|
|
283
|
+
/>;
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Settings Accelerators
|
|
287
|
+
|
|
288
|
+
`ParameterEditor` provides grouped settings rows for numeric, boolean, text, and choice controls passed in as app-owned slots. It does not generate controls from schemas, validate values, persist changes, or encode provider/model-specific parameters.
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
import { ParameterEditor } from "@zvk/composite/parameter-editor";
|
|
292
|
+
|
|
293
|
+
<ParameterEditor
|
|
294
|
+
groups={[
|
|
295
|
+
{
|
|
296
|
+
id: "model",
|
|
297
|
+
title: "Model settings",
|
|
298
|
+
rows: [
|
|
299
|
+
{
|
|
300
|
+
id: "temperature",
|
|
301
|
+
label: "Temperature",
|
|
302
|
+
value: "0.7",
|
|
303
|
+
control: <input aria-label="Temperature" type="range" />
|
|
304
|
+
}
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
]}
|
|
308
|
+
/>;
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`ProviderModelSelector` provides the repeated two-level chooser shell for AI provider/model settings, service/variant selection, environment/resource selection, and similar grouped option workflows. The component owns layout, selected presentation, empty/loading states, and disabled styling; the app owns the catalog, filtering, pricing, validation, persistence, and provider checks.
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
import { ProviderModelSelector } from "@zvk/composite/provider-model-selector";
|
|
315
|
+
|
|
316
|
+
<ProviderModelSelector
|
|
317
|
+
groups={[
|
|
318
|
+
{
|
|
319
|
+
id: "openai",
|
|
320
|
+
label: "OpenAI",
|
|
321
|
+
description: "Text and reasoning models",
|
|
322
|
+
badge: "Connected",
|
|
323
|
+
items: [{ id: "gpt-5.4", label: "GPT-5.4", metadata: "128k context" }]
|
|
324
|
+
}
|
|
325
|
+
]}
|
|
326
|
+
selectedGroupId="openai"
|
|
327
|
+
selectedItemId="gpt-5.4"
|
|
328
|
+
selectedSummary="OpenAI / GPT-5.4"
|
|
329
|
+
onItemSelect={(item, group) => {
|
|
330
|
+
// Persist and validate in the app.
|
|
331
|
+
}}
|
|
332
|
+
/>;
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
`ConversationDirectory` provides the repeated conversation/sidebar directory shell for AI workspaces, activity workbenches, and other record-selection panels. It owns grouped list layout, selected/disabled/pinned/unread/archived presentation, empty/loading states, and item selection callbacks. The app owns persistence, search/filter logic, routes, unread-count calculation, archive/delete actions, message fetching, streaming, and AI SDK integration.
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
import { ConversationDirectory } from "@zvk/composite/conversation-directory";
|
|
339
|
+
|
|
340
|
+
<ConversationDirectory
|
|
341
|
+
actions={<button type="button">New</button>}
|
|
342
|
+
groups={[
|
|
343
|
+
{
|
|
344
|
+
id: "today",
|
|
345
|
+
label: "Today",
|
|
346
|
+
items: [
|
|
347
|
+
{
|
|
348
|
+
id: "release-plan",
|
|
349
|
+
title: "Release planning",
|
|
350
|
+
description: "Package rollout notes",
|
|
351
|
+
meta: "12 messages",
|
|
352
|
+
selected: true,
|
|
353
|
+
unread: true
|
|
354
|
+
}
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
]}
|
|
358
|
+
label="Conversation history"
|
|
359
|
+
onItemSelect={(item) => {
|
|
360
|
+
// Route, persist, and fetch messages in the app.
|
|
361
|
+
}}
|
|
362
|
+
/>;
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
`StickyComposer` provides the repeated sticky composer frame for chat, AI prompt, command, and workbench input areas. It owns the native form container, sticky layout, tool slots, submit slot, status/error/footer placement, and loading/disabled presentation. The app owns input state, validation, files, tools, streaming, submit side effects, keyboard shortcuts beyond native form behavior, and persistence.
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
import { StickyComposer } from "@zvk/composite/sticky-composer";
|
|
369
|
+
import { Conversation } from "@zvk/ui/conversation";
|
|
370
|
+
|
|
371
|
+
<StickyComposer
|
|
372
|
+
aria-label="Message composer"
|
|
373
|
+
footer="State, validation, streaming, and persistence stay in the app."
|
|
374
|
+
input={<Conversation.PromptInputTextarea aria-label="Message" />}
|
|
375
|
+
leadingTools={<button type="button">Attach</button>}
|
|
376
|
+
onSubmit={(event) => {
|
|
377
|
+
event.preventDefault();
|
|
378
|
+
// Submit in the app.
|
|
379
|
+
}}
|
|
380
|
+
status="Ready"
|
|
381
|
+
submit={<Conversation.PromptInputSubmit>Send</Conversation.PromptInputSubmit>}
|
|
382
|
+
/>;
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
`SettingsSectionStack` groups settings-page sections, alerts, actions, disabled presentation, and a controlled save bar. It does not detect dirty state, validate values, persist changes, manage route anchors, or own form field state.
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
import { SettingsSectionStack } from "@zvk/composite/settings-section-stack";
|
|
389
|
+
|
|
390
|
+
<SettingsSectionStack
|
|
391
|
+
dirty
|
|
392
|
+
saveBar="Unsaved changes"
|
|
393
|
+
sections={[
|
|
394
|
+
{
|
|
395
|
+
id: "profile",
|
|
396
|
+
title: "Profile",
|
|
397
|
+
description: "App-owned controls passed as content.",
|
|
398
|
+
content: "Profile fields",
|
|
399
|
+
actions: "Reset"
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
id: "billing",
|
|
403
|
+
title: "Billing",
|
|
404
|
+
content: "Billing controls",
|
|
405
|
+
disabled: true
|
|
406
|
+
}
|
|
407
|
+
]}
|
|
408
|
+
title="Workspace settings"
|
|
409
|
+
/>;
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Detail Panels
|
|
413
|
+
|
|
414
|
+
`DetailInspectorPanel` gives `PageScaffold` aside slots and split views a reusable selected-item inspector. It owns header, status, metadata, section layout, empty/loading presentation, and footer placement. The app owns selected item state, fetching, route params, audit queries, and any drawer or sheet wrapper.
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
import { DetailInspectorPanel } from "@zvk/composite/detail-inspector-panel";
|
|
418
|
+
|
|
419
|
+
<DetailInspectorPanel
|
|
420
|
+
actions={<button type="button">Open full page</button>}
|
|
421
|
+
description="Selected workflow run"
|
|
422
|
+
footer="Drawer state and data loading stay in the app."
|
|
423
|
+
metadata="Updated 1 minute ago"
|
|
424
|
+
sections={[
|
|
425
|
+
{
|
|
426
|
+
id: "summary",
|
|
427
|
+
title: "Summary",
|
|
428
|
+
content: "Parser is extracting line items."
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
id: "audit",
|
|
432
|
+
title: "Audit",
|
|
433
|
+
content: "Queued by Codex"
|
|
434
|
+
}
|
|
435
|
+
]}
|
|
436
|
+
status="Running"
|
|
437
|
+
title="Run details"
|
|
438
|
+
/>;
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Data Table Controls
|
|
442
|
+
|
|
443
|
+
`DataTableControlBar` complements `DataTablePageFrame` when a table page repeats search, filters, saved views, density, column, selection, bulk-action, and action placement. It does not own search state, filter schemas, saved-view persistence, column visibility, row selection, sorting, pagination, data fetching, or table engine adapters.
|
|
444
|
+
|
|
445
|
+
```tsx
|
|
446
|
+
import { DataTableControlBar } from "@zvk/composite/data-table-control-bar";
|
|
447
|
+
|
|
448
|
+
<DataTableControlBar
|
|
449
|
+
actions={<button type="button">Refresh</button>}
|
|
450
|
+
bulkActions={<button type="button">Archive selected</button>}
|
|
451
|
+
columnControl={<button type="button">Columns</button>}
|
|
452
|
+
densityControl={<button type="button">Compact</button>}
|
|
453
|
+
filters={<button type="button">Status</button>}
|
|
454
|
+
savedView={<button type="button">Saved view</button>}
|
|
455
|
+
search={<input aria-label="Search rows" />}
|
|
456
|
+
selectionSummary="3 selected"
|
|
457
|
+
/>;
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Repo Skill
|
|
461
|
+
|
|
462
|
+
Use `.codex/skills/use-zvk-composite/SKILL.md` when maintaining this package.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type ActivityFeedTone = "neutral" | "info" | "success" | "warning" | "danger";
|
|
3
|
+
export interface ActivityFeedItem {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly title: React.ReactNode;
|
|
6
|
+
readonly description?: React.ReactNode;
|
|
7
|
+
readonly meta?: React.ReactNode;
|
|
8
|
+
readonly body?: React.ReactNode;
|
|
9
|
+
readonly icon?: React.ReactNode;
|
|
10
|
+
readonly actions?: React.ReactNode;
|
|
11
|
+
readonly tone?: ActivityFeedTone;
|
|
12
|
+
}
|
|
13
|
+
export interface ActivityFeedGroup {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly label?: React.ReactNode;
|
|
16
|
+
readonly items: readonly ActivityFeedItem[];
|
|
17
|
+
}
|
|
18
|
+
export interface ActivityFeedProps extends Omit<React.ComponentPropsWithoutRef<"section">, "title" | "children"> {
|
|
19
|
+
readonly title?: React.ReactNode;
|
|
20
|
+
readonly description?: React.ReactNode;
|
|
21
|
+
readonly groups: readonly ActivityFeedGroup[];
|
|
22
|
+
readonly empty?: React.ReactNode;
|
|
23
|
+
readonly loading?: boolean;
|
|
24
|
+
readonly footer?: React.ReactNode;
|
|
25
|
+
readonly ref?: React.Ref<HTMLElement>;
|
|
26
|
+
}
|
|
27
|
+
export declare function ActivityFeed({ className, description, empty, footer, groups, loading, ref, title, ...props }: ActivityFeedProps): React.JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Spinner } from "@zvk/ui/spinner";
|
|
4
|
+
import { cn } from "../utils/cn.js";
|
|
5
|
+
function hasValue(value) {
|
|
6
|
+
return value !== null && value !== undefined && value !== false;
|
|
7
|
+
}
|
|
8
|
+
function hasItems(groups) {
|
|
9
|
+
return groups.some((group) => group.items.length > 0);
|
|
10
|
+
}
|
|
11
|
+
function renderActivityItem(item) {
|
|
12
|
+
const tone = item.tone ?? "neutral";
|
|
13
|
+
const showAside = hasValue(item.actions);
|
|
14
|
+
const showDescription = hasValue(item.description);
|
|
15
|
+
const showMeta = hasValue(item.meta);
|
|
16
|
+
const showBody = hasValue(item.body);
|
|
17
|
+
const showIcon = hasValue(item.icon);
|
|
18
|
+
return (_jsx("article", { className: "zvk-composite-activity-feed__entry", "data-tone": tone, children: _jsxs("div", { className: "zvk-composite-activity-feed__shell", children: [showIcon ? _jsx("div", { className: "zvk-composite-activity-feed__icon", children: item.icon }) : null, _jsxs("div", { className: "zvk-composite-activity-feed__content", children: [_jsxs("div", { className: "zvk-composite-activity-feed__header", children: [_jsxs("div", { className: "zvk-composite-activity-feed__copy", children: [_jsx("h4", { className: "zvk-composite-activity-feed__title", children: item.title }), showDescription ? (_jsx("p", { className: "zvk-composite-activity-feed__description", children: item.description })) : null] }), showAside ? _jsx("div", { className: "zvk-composite-activity-feed__actions", children: item.actions }) : null] }), showMeta ? _jsx("div", { className: "zvk-composite-activity-feed__meta", children: item.meta }) : null, showBody ? _jsx("div", { className: "zvk-composite-activity-feed__body", children: item.body }) : null] })] }) }));
|
|
19
|
+
}
|
|
20
|
+
export function ActivityFeed({ className, description, empty = "No activity yet.", footer, groups, loading = false, ref, title, ...props }) {
|
|
21
|
+
const showHeader = hasValue(title) || hasValue(description);
|
|
22
|
+
const showItems = !loading && hasItems(groups);
|
|
23
|
+
const showEmptyState = !loading && !showItems;
|
|
24
|
+
return (_jsxs("section", { ...props, ref: ref, "aria-busy": loading ? true : props["aria-busy"], className: cn("zvk-composite-activity-feed", className), "data-loading": loading ? "" : undefined, children: [showHeader ? (_jsx("div", { className: "zvk-composite-activity-feed__header", children: _jsxs("div", { className: "zvk-composite-activity-feed__copy", children: [hasValue(title) ? _jsx("h3", { className: "zvk-composite-activity-feed__title", children: title }) : null, hasValue(description) ? (_jsx("p", { className: "zvk-composite-activity-feed__description", children: description })) : null] }) })) : null, _jsxs("div", { className: "zvk-composite-activity-feed__sections", children: [loading ? (_jsxs("div", { className: "zvk-composite-activity-feed__state", "data-state": "loading", children: [_jsx(Spinner, { label: "Loading activity feed", size: "sm", tone: "muted" }), _jsx("span", { children: "Loading activity feed..." })] })) : null, showEmptyState ? (_jsx("div", { className: "zvk-composite-activity-feed__state", "data-state": "empty", children: empty })) : null, showItems ? (_jsx("div", { className: "zvk-composite-activity-feed__groups", children: groups.map((group) => {
|
|
25
|
+
if (group.items.length === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return (_jsxs("section", { className: "zvk-composite-activity-feed__group", children: [hasValue(group.label) ? (_jsx("div", { className: "zvk-composite-activity-feed__group-label", children: group.label })) : null, _jsx("ul", { className: "zvk-composite-activity-feed__list", children: group.items.map((item) => (_jsx("li", { className: "zvk-composite-activity-feed__item", children: renderActivityItem(item) }, item.id))) })] }, group.id));
|
|
29
|
+
}) })) : null] }), hasValue(footer) ? _jsx("div", { className: "zvk-composite-activity-feed__footer", children: footer }) : null] }));
|
|
30
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ConversationDirectoryItem {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly title: React.ReactNode;
|
|
5
|
+
readonly description?: React.ReactNode;
|
|
6
|
+
readonly meta?: React.ReactNode;
|
|
7
|
+
readonly badge?: React.ReactNode;
|
|
8
|
+
readonly selected?: boolean;
|
|
9
|
+
readonly disabled?: boolean;
|
|
10
|
+
readonly pinned?: boolean;
|
|
11
|
+
readonly unread?: boolean;
|
|
12
|
+
readonly archived?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ConversationDirectoryGroup {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly label?: React.ReactNode;
|
|
17
|
+
readonly items: readonly ConversationDirectoryItem[];
|
|
18
|
+
}
|
|
19
|
+
export interface ConversationDirectoryProps extends Omit<React.ComponentPropsWithoutRef<"aside">, "children"> {
|
|
20
|
+
readonly label: string;
|
|
21
|
+
readonly groups: readonly ConversationDirectoryGroup[];
|
|
22
|
+
readonly search?: React.ReactNode;
|
|
23
|
+
readonly actions?: React.ReactNode;
|
|
24
|
+
readonly empty?: React.ReactNode;
|
|
25
|
+
readonly loading?: boolean;
|
|
26
|
+
readonly onItemSelect?: (item: ConversationDirectoryItem) => void;
|
|
27
|
+
readonly renderItem?: (item: ConversationDirectoryItem) => React.ReactNode;
|
|
28
|
+
readonly footer?: React.ReactNode;
|
|
29
|
+
readonly ref?: React.Ref<HTMLElement>;
|
|
30
|
+
}
|
|
31
|
+
export declare function ConversationDirectory({ actions, className, empty, footer, groups, label, loading, onItemSelect, ref, renderItem, search, ...props }: ConversationDirectoryProps): React.JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Spinner } from "@zvk/ui/spinner";
|
|
5
|
+
import { cn } from "../utils/cn.js";
|
|
6
|
+
function hasValue(value) {
|
|
7
|
+
return value !== null && value !== undefined && value !== false;
|
|
8
|
+
}
|
|
9
|
+
function renderNode(value) {
|
|
10
|
+
return hasValue(value) ? value : null;
|
|
11
|
+
}
|
|
12
|
+
function renderItemFlags(item) {
|
|
13
|
+
const flags = [];
|
|
14
|
+
if (item.pinned === true) {
|
|
15
|
+
flags.push(_jsx("span", { className: "zvk-composite-conversation-directory__item-state", "data-kind": "pinned", children: "Pinned" }, "pinned"));
|
|
16
|
+
}
|
|
17
|
+
if (item.unread === true) {
|
|
18
|
+
flags.push(_jsx("span", { className: "zvk-composite-conversation-directory__item-state", "data-kind": "unread", children: "Unread" }, "unread"));
|
|
19
|
+
}
|
|
20
|
+
if (item.archived === true) {
|
|
21
|
+
flags.push(_jsx("span", { className: "zvk-composite-conversation-directory__item-state", "data-kind": "archived", children: "Archived" }, "archived"));
|
|
22
|
+
}
|
|
23
|
+
return flags.length > 0 ? _jsx(_Fragment, { children: flags }) : null;
|
|
24
|
+
}
|
|
25
|
+
function renderDefaultItemContent(item) {
|
|
26
|
+
const flags = renderItemFlags(item);
|
|
27
|
+
return (_jsxs("div", { className: "zvk-composite-conversation-directory__item-copy", children: [_jsxs("div", { className: "zvk-composite-conversation-directory__item-heading", children: [_jsx("span", { className: "zvk-composite-conversation-directory__item-title", children: item.title }), hasValue(item.badge) ? _jsx("span", { className: "zvk-composite-conversation-directory__item-badge", children: item.badge }) : null] }), hasValue(item.description) ? (_jsx("span", { className: "zvk-composite-conversation-directory__item-description", children: item.description })) : null, hasValue(item.meta) || item.pinned === true || item.unread === true || item.archived === true ? (_jsxs("span", { className: "zvk-composite-conversation-directory__item-meta-row", children: [hasValue(item.meta) ? _jsx("span", { className: "zvk-composite-conversation-directory__item-meta", children: item.meta }) : null, flags !== null ? _jsx("span", { className: "zvk-composite-conversation-directory__item-states", children: flags }) : null] })) : null] }));
|
|
28
|
+
}
|
|
29
|
+
export function ConversationDirectory({ actions, className, empty = "No conversations available.", footer, groups, label, loading = false, onItemSelect, ref, renderItem, search, ...props }) {
|
|
30
|
+
const visibleGroups = groups.filter((group) => group.items.length > 0);
|
|
31
|
+
const showEmptyState = !loading && visibleGroups.length === 0;
|
|
32
|
+
const showLoader = loading;
|
|
33
|
+
return (_jsxs("aside", { ...props, ref: ref, "aria-busy": loading ? true : props["aria-busy"], "aria-label": label, className: cn("zvk-composite-conversation-directory", className), "data-empty": showEmptyState ? "" : undefined, "data-loading": loading ? "" : undefined, children: [_jsxs("header", { className: "zvk-composite-conversation-directory__header", children: [_jsx("div", { className: "zvk-composite-conversation-directory__header-copy", children: _jsx("h2", { className: "zvk-composite-conversation-directory__title", children: label }) }), hasValue(search) || hasValue(actions) ? (_jsxs("div", { className: "zvk-composite-conversation-directory__header-actions", children: [hasValue(search) ? _jsx("div", { className: "zvk-composite-conversation-directory__search", children: search }) : null, hasValue(actions) ? _jsx("div", { className: "zvk-composite-conversation-directory__actions", children: actions }) : null] })) : null] }), showLoader ? (_jsxs("div", { className: "zvk-composite-conversation-directory__state", "data-state": "loading", children: [_jsx(Spinner, { label: "Loading conversations", size: "sm", tone: "muted" }), _jsx("span", { children: "Loading conversations..." })] })) : null, showEmptyState ? (_jsx("div", { className: "zvk-composite-conversation-directory__state", "data-state": "empty", children: renderNode(empty) })) : null, !showLoader && !showEmptyState ? (_jsx("div", { className: "zvk-composite-conversation-directory__groups", children: visibleGroups.map((group) => (_jsxs("section", { "aria-label": typeof group.label === "string" ? group.label : undefined, className: "zvk-composite-conversation-directory__group", children: [hasValue(group.label) ? (_jsx("div", { className: "zvk-composite-conversation-directory__group-header", children: _jsx("h3", { className: "zvk-composite-conversation-directory__group-title", children: group.label }) })) : null, _jsx("ul", { className: "zvk-composite-conversation-directory__list", children: group.items.map((item) => {
|
|
34
|
+
const isDisabled = item.disabled === true;
|
|
35
|
+
const isSelected = item.selected === true;
|
|
36
|
+
const itemBody = renderItem !== undefined ? renderItem(item) : renderDefaultItemContent(item);
|
|
37
|
+
return (_jsx("li", { className: "zvk-composite-conversation-directory__list-item", children: _jsx("button", { "aria-pressed": isSelected, className: "zvk-composite-conversation-directory__item", "data-archived": item.archived === true ? "" : undefined, "data-disabled": isDisabled ? "" : undefined, "data-pinned": item.pinned === true ? "" : undefined, "data-selected": isSelected ? "" : undefined, "data-unread": item.unread === true ? "" : undefined, disabled: isDisabled, type: "button", onClick: () => {
|
|
38
|
+
if (isDisabled) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
onItemSelect?.(item);
|
|
42
|
+
}, children: _jsx("div", { className: "zvk-composite-conversation-directory__item-content", children: itemBody }) }) }, item.id));
|
|
43
|
+
}) })] }, group.id))) })) : null, hasValue(footer) ? _jsx("div", { className: "zvk-composite-conversation-directory__footer", children: footer }) : null] }));
|
|
44
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ProviderModelItem {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly label: React.ReactNode;
|
|
5
|
+
readonly description?: React.ReactNode;
|
|
6
|
+
readonly badge?: React.ReactNode;
|
|
7
|
+
readonly metadata?: React.ReactNode;
|
|
8
|
+
readonly disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface ProviderModelGroup {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly label: React.ReactNode;
|
|
13
|
+
readonly description?: React.ReactNode;
|
|
14
|
+
readonly badge?: React.ReactNode;
|
|
15
|
+
readonly disabled?: boolean;
|
|
16
|
+
readonly items: readonly ProviderModelItem[];
|
|
17
|
+
}
|
|
18
|
+
export interface ProviderModelSelectorProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
19
|
+
readonly groups: readonly ProviderModelGroup[];
|
|
20
|
+
readonly selectedGroupId?: string;
|
|
21
|
+
readonly selectedItemId?: string;
|
|
22
|
+
readonly onGroupSelect?: (group: ProviderModelGroup) => void;
|
|
23
|
+
readonly onItemSelect?: (item: ProviderModelItem, group: ProviderModelGroup) => void;
|
|
24
|
+
readonly search?: React.ReactNode;
|
|
25
|
+
readonly selectedSummary?: React.ReactNode;
|
|
26
|
+
readonly advancedSettings?: React.ReactNode;
|
|
27
|
+
readonly empty?: React.ReactNode;
|
|
28
|
+
readonly loading?: boolean;
|
|
29
|
+
readonly ref?: React.Ref<HTMLDivElement>;
|
|
30
|
+
}
|
|
31
|
+
export declare function ProviderModelSelector({ advancedSettings, className, empty, groups, loading, onGroupSelect, onItemSelect, ref, search, selectedGroupId, selectedItemId, selectedSummary, ...props }: ProviderModelSelectorProps): React.JSX.Element;
|