@contractspec/bundle.library 3.9.8 → 3.9.9
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/.turbo/turbo-build.log +222 -214
- package/CHANGELOG.md +52 -0
- package/dist/components/docs/DocsIndexPage.js +2 -2
- package/dist/components/docs/docsManifest.js +1 -1
- package/dist/components/docs/getting-started/DataViewTutorialPage.js +81 -6
- package/dist/components/docs/getting-started/index.js +94 -19
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.d.ts +6 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.js +176 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.d.ts +1 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.js +176 -0
- package/dist/components/docs/guides/GuidesIndexPage.js +2 -2
- package/dist/components/docs/guides/index.d.ts +1 -0
- package/dist/components/docs/guides/index.js +220 -46
- package/dist/components/docs/index.js +1003 -309
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.content.d.ts +22 -5
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.content.js +125 -37
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.js +125 -37
- package/dist/components/docs/libraries/LibrariesDataViewsPage.js +120 -3
- package/dist/components/docs/libraries/LibrariesDesignSystemPage.js +101 -2
- package/dist/components/docs/libraries/LibrariesOverviewPage.js +1 -1
- package/dist/components/docs/libraries/LibrariesPersonalizationPage.js +58 -4
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.content.d.ts +10 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.content.js +43 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.d.ts +1 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.js +43 -0
- package/dist/components/docs/libraries/index.d.ts +1 -0
- package/dist/components/docs/libraries/index.js +496 -97
- package/dist/components/docs/specs/SpecsDataViewsPage.js +49 -3
- package/dist/components/docs/specs/index.js +60 -14
- package/dist/index.js +1014 -320
- package/dist/node/components/docs/DocsIndexPage.js +2 -2
- package/dist/node/components/docs/docsManifest.js +1 -1
- package/dist/node/components/docs/getting-started/DataViewTutorialPage.js +81 -6
- package/dist/node/components/docs/getting-started/index.js +94 -19
- package/dist/node/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.js +175 -0
- package/dist/node/components/docs/guides/GuideDataExchangeImportTemplatesPage.js +175 -0
- package/dist/node/components/docs/guides/GuidesIndexPage.js +2 -2
- package/dist/node/components/docs/guides/index.js +220 -46
- package/dist/node/components/docs/index.js +1003 -309
- package/dist/node/components/docs/libraries/LibrariesApplicationShellPage.content.js +125 -37
- package/dist/node/components/docs/libraries/LibrariesApplicationShellPage.js +125 -37
- package/dist/node/components/docs/libraries/LibrariesDataViewsPage.js +120 -3
- package/dist/node/components/docs/libraries/LibrariesDesignSystemPage.js +101 -2
- package/dist/node/components/docs/libraries/LibrariesOverviewPage.js +1 -1
- package/dist/node/components/docs/libraries/LibrariesPersonalizationPage.js +58 -4
- package/dist/node/components/docs/libraries/LibrariesTranslationRuntimePage.content.js +42 -0
- package/dist/node/components/docs/libraries/LibrariesTranslationRuntimePage.js +42 -0
- package/dist/node/components/docs/libraries/index.js +496 -97
- package/dist/node/components/docs/specs/SpecsDataViewsPage.js +49 -3
- package/dist/node/components/docs/specs/index.js +60 -14
- package/dist/node/index.js +1014 -320
- package/package.json +74 -26
- package/src/components/docs/docsManifest.test.ts +87 -0
- package/src/components/docs/docsManifest.ts +90 -3
- package/src/components/docs/generated/docs-index.notifications.json +7 -7
- package/src/components/docs/getting-started/DataViewTutorialPage.tsx +181 -50
- package/src/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.ts +185 -0
- package/src/components/docs/guides/GuideDataExchangeImportTemplatesPage.tsx +186 -0
- package/src/components/docs/guides/GuidesIndexPage.tsx +49 -42
- package/src/components/docs/guides/index.ts +1 -0
- package/src/components/docs/libraries/LibrariesApplicationShellPage.content.ts +148 -35
- package/src/components/docs/libraries/LibrariesApplicationShellPage.tsx +38 -5
- package/src/components/docs/libraries/LibrariesDataViewsPage.tsx +267 -64
- package/src/components/docs/libraries/LibrariesDesignSystemPage.tsx +235 -0
- package/src/components/docs/libraries/LibrariesOverviewPage.tsx +8 -2
- package/src/components/docs/libraries/LibrariesPersonalizationPage.tsx +141 -31
- package/src/components/docs/libraries/LibrariesTranslationRuntimePage.content.ts +78 -0
- package/src/components/docs/libraries/LibrariesTranslationRuntimePage.tsx +137 -0
- package/src/components/docs/libraries/index.ts +1 -0
- package/src/components/docs/specs/SpecsDataViewsPage.tsx +239 -113
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var w=Object.defineProperty;var k=(t)=>t;function N(t,n){this[t]=k.bind(null,n)}var O=(t,n)=>{for(var d in n)w(t,d,{get:n[d],enumerable:!0,configurable:!0,set:N.bind(n,d)})};var C=(t,n)=>()=>(t&&(n=t(t=0)),n);var p=`import {
|
|
3
3
|
AppShell,
|
|
4
|
-
|
|
5
|
-
type
|
|
4
|
+
type ShellCommandGroup,
|
|
5
|
+
type ShellNavSection,
|
|
6
|
+
type ShellNotificationCenter,
|
|
6
7
|
type PageOutlineItem,
|
|
7
8
|
} from "@contractspec/lib.design-system/shell";
|
|
8
9
|
|
|
9
|
-
const navigation:
|
|
10
|
+
const navigation: ShellNavSection[] = [
|
|
10
11
|
{
|
|
11
12
|
title: "Workspace",
|
|
12
13
|
items: [
|
|
@@ -23,6 +24,16 @@ const navigation: AppShellNavigationSection[] = [
|
|
|
23
24
|
},
|
|
24
25
|
];
|
|
25
26
|
|
|
27
|
+
const commands: ShellCommandGroup[] = [
|
|
28
|
+
{
|
|
29
|
+
heading: "Quick actions",
|
|
30
|
+
items: [
|
|
31
|
+
{ id: "new-contract", label: "New contract", shortcut: "N" },
|
|
32
|
+
{ id: "import", label: "Import existing app" },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
26
37
|
const outline: PageOutlineItem[] = [
|
|
27
38
|
{
|
|
28
39
|
id: "architecture",
|
|
@@ -35,41 +46,104 @@ const outline: PageOutlineItem[] = [
|
|
|
35
46
|
},
|
|
36
47
|
];
|
|
37
48
|
|
|
49
|
+
const notifications: ShellNotificationCenter = {
|
|
50
|
+
label: "Notifications",
|
|
51
|
+
loading: false,
|
|
52
|
+
unreadCount: 2,
|
|
53
|
+
items: [
|
|
54
|
+
{
|
|
55
|
+
id: "contract-approved",
|
|
56
|
+
title: "Contract approved",
|
|
57
|
+
body: "Billing.create is ready to publish.",
|
|
58
|
+
status: "unread",
|
|
59
|
+
createdAt: "2026-04-29T09:30:00Z",
|
|
60
|
+
actionUrl: "/contracts/billing.create",
|
|
61
|
+
category: "Review",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
onSelect: (item) => openNotificationTarget(item),
|
|
65
|
+
onMarkRead: (item) => markNotificationRead(item.id),
|
|
66
|
+
onMarkAllRead: () => markAllNotificationsRead(),
|
|
67
|
+
};
|
|
68
|
+
|
|
38
69
|
export function WorkspacePage() {
|
|
39
70
|
return (
|
|
40
71
|
<AppShell
|
|
41
|
-
|
|
72
|
+
title="ContractSpec"
|
|
73
|
+
homeHref="/dashboard"
|
|
42
74
|
navigation={navigation}
|
|
75
|
+
commands={commands}
|
|
43
76
|
breadcrumbs={[
|
|
44
77
|
{ label: "Workspace", href: "/dashboard" },
|
|
45
78
|
{ label: "Contracts" },
|
|
46
79
|
]}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
actions: [
|
|
53
|
-
{ id: "new-contract", label: "New contract" },
|
|
54
|
-
{ id: "import", label: "Import existing app" },
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
}}
|
|
59
|
-
user={{
|
|
60
|
-
name: "Ada Lovelace",
|
|
61
|
-
email: "ada@example.com",
|
|
62
|
-
actions: [{ label: "Sign out", onSelect: () => signOut() }],
|
|
63
|
-
}}
|
|
64
|
-
pageOutline={<PageOutline items={outline} activeId="desktop" />}
|
|
80
|
+
notifications={notifications}
|
|
81
|
+
pageOutline={outline}
|
|
82
|
+
activeHref="/contracts"
|
|
83
|
+
activeOutlineId="desktop"
|
|
84
|
+
userMenu={<UserMenu onSignOut={() => signOut()} />}
|
|
65
85
|
>
|
|
66
86
|
<main>{/* route content */}</main>
|
|
67
87
|
</AppShell>
|
|
68
88
|
);
|
|
69
|
-
}`,
|
|
89
|
+
}`,m=`import {
|
|
90
|
+
ListNotificationsOutputModel,
|
|
91
|
+
MarkNotificationReadInputModel,
|
|
92
|
+
} from "@contractspec/lib.contracts-spec/notifications";
|
|
93
|
+
import {
|
|
94
|
+
notificationsSchemaContribution,
|
|
95
|
+
renderNotificationTemplate,
|
|
96
|
+
} from "@contractspec/lib.notification";
|
|
97
|
+
import type { ShellNotificationCenter } from "@contractspec/lib.design-system/shell";
|
|
98
|
+
|
|
99
|
+
type NotificationListResult = {
|
|
100
|
+
unreadCount: number;
|
|
101
|
+
notifications: Array<{
|
|
102
|
+
id: string;
|
|
103
|
+
title: string;
|
|
104
|
+
body: string;
|
|
105
|
+
type: string;
|
|
106
|
+
status: string;
|
|
107
|
+
readAt?: string | Date | null;
|
|
108
|
+
createdAt: string | Date;
|
|
109
|
+
actionUrl?: string;
|
|
110
|
+
metadata?: Record<string, unknown>;
|
|
111
|
+
}>;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export function toShellNotifications(
|
|
115
|
+
data: NotificationListResult,
|
|
116
|
+
actions: {
|
|
117
|
+
open: (id: string) => void;
|
|
118
|
+
markRead: (input: { notificationId: string }) => void;
|
|
119
|
+
markAllRead: () => void;
|
|
120
|
+
}
|
|
121
|
+
): ShellNotificationCenter {
|
|
122
|
+
return {
|
|
123
|
+
unreadCount: data.unreadCount,
|
|
124
|
+
items: data.notifications.map((notification) => ({
|
|
125
|
+
id: notification.id,
|
|
126
|
+
title: notification.title,
|
|
127
|
+
body: notification.body,
|
|
128
|
+
status: notification.status,
|
|
129
|
+
createdAt: notification.createdAt,
|
|
130
|
+
actionUrl: notification.actionUrl,
|
|
131
|
+
category: notification.type,
|
|
132
|
+
metadata: notification.metadata,
|
|
133
|
+
})),
|
|
134
|
+
onSelect: (item) => actions.open(item.id),
|
|
135
|
+
onMarkRead: (item) => actions.markRead({ notificationId: item.id }),
|
|
136
|
+
onMarkAllRead: actions.markAllRead,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void ListNotificationsOutputModel;
|
|
141
|
+
void MarkNotificationReadInputModel;
|
|
142
|
+
void notificationsSchemaContribution;
|
|
143
|
+
void renderNotificationTemplate;`,u=`You are implementing a modern application shell from scratch.
|
|
70
144
|
|
|
71
145
|
Goal:
|
|
72
|
-
Build a reusable application shell for a React/Next.js web app and an Expo React Native app. The shell must provide a desktop sidebar, desktop topbar, command search, breadcrumbs, nested navigation, user/auth actions, and an in-page section navigator called PageOutline.
|
|
146
|
+
Build a reusable application shell for a React/Next.js web app and an Expo React Native app. The shell must provide a desktop sidebar, desktop topbar, command search, breadcrumbs, nested navigation, user/auth actions, in-app notifications, and an in-page section navigator called PageOutline.
|
|
73
147
|
|
|
74
148
|
Use this architecture:
|
|
75
149
|
- Keep route content independent from navigation chrome.
|
|
@@ -77,29 +151,37 @@ Use this architecture:
|
|
|
77
151
|
- Create a command model with search input, grouped suggestions, quick actions, keyboard shortcut labels, empty state, and loading state.
|
|
78
152
|
- Create a breadcrumb model for the topbar.
|
|
79
153
|
- Create a PageOutline model for right-side in-page navigation with exactly three supported levels. It should render anchors, support active section state, and degrade gracefully when no sections exist.
|
|
154
|
+
- Create a ShellNotificationCenter model with render-ready items, unread count, loading and empty states, onSelect, onMarkRead, onMarkAllRead, and optional custom item rendering.
|
|
80
155
|
- Expose the system from the design system or a dedicated shell module, not from a single app route.
|
|
81
156
|
|
|
157
|
+
Notification boundary:
|
|
158
|
+
- Use @contractspec/lib.contracts-spec/notifications as the canonical source for notification contracts, operation models, and feature metadata.
|
|
159
|
+
- Use @contractspec/lib.notification for reusable notification entities, schema contribution, channels, templates, and i18n helpers.
|
|
160
|
+
- Keep persistence, polling/subscriptions, delivery providers, and optimistic mutations in the host application or notification runtime layer.
|
|
161
|
+
- Pass only render-ready ShellNotificationCenter state into AppShell so the design system does not import or own notification runtime behavior.
|
|
162
|
+
|
|
82
163
|
Desktop behavior:
|
|
83
164
|
- Persistent left sidebar with app logo/title, command trigger, grouped navigation, nested submenus, and current user/auth/logout area.
|
|
84
165
|
- Topbar with breadcrumbs and an optional command trigger.
|
|
166
|
+
- Topbar notification trigger with unread badge, loading/empty states, mark-read actions, and item selection.
|
|
85
167
|
- Content area with optional right PageOutline.
|
|
86
168
|
- Keep dimensions stable. Navigation labels must not resize layout on hover or active state.
|
|
87
169
|
|
|
88
170
|
Mobile web behavior:
|
|
89
171
|
- Use bottom navigation for the primary destinations.
|
|
90
|
-
- Put deeper navigation, command search, auth actions, and secondary actions behind a menu or drawer.
|
|
172
|
+
- Put deeper navigation, command search, notifications, auth actions, and secondary actions behind a menu or drawer when the topbar cannot safely hold them.
|
|
91
173
|
- Keep route content first and make the shell controls reachable without covering important content.
|
|
92
174
|
|
|
93
175
|
Native behavior:
|
|
94
176
|
- Add .native.tsx entrypoints for Expo/React Native.
|
|
95
|
-
- Prefer bottom tabs for primary destinations and a menu/sheet for deeper navigation and account actions.
|
|
96
|
-
- Keep the same typed navigation, command, breadcrumb, and PageOutline data contracts across web and native.
|
|
177
|
+
- Prefer bottom tabs for primary destinations and a menu/sheet for deeper navigation, notifications, and account actions.
|
|
178
|
+
- Keep the same typed navigation, command, breadcrumb, notification, and PageOutline data contracts across web and native.
|
|
97
179
|
|
|
98
180
|
Implementation constraints:
|
|
99
181
|
- Reuse the existing design-system primitives, tokens, icons, and accessibility patterns.
|
|
100
182
|
- Do not hardcode app-specific routes in the shell component.
|
|
101
183
|
- Do not introduce a new dependency unless the repo already uses it for dialogs, menus, icons, or navigation.
|
|
102
|
-
- Include tests for navigation rendering, nested items, command filtering, breadcrumbs, PageOutline level handling, active section state, and mobile/native adaptation contracts.
|
|
184
|
+
- Include tests for navigation rendering, nested items, command filtering, breadcrumbs, notification unread badge/loading/empty/callback behavior, PageOutline level handling, active section state, and mobile/native adaptation contracts.
|
|
103
185
|
- Update docs and exports so developers can import the shell from a stable public API.
|
|
104
186
|
|
|
105
187
|
Deliverables:
|
|
@@ -107,15 +189,18 @@ Deliverables:
|
|
|
107
189
|
- Web shell components.
|
|
108
190
|
- Native shell components or adapters.
|
|
109
191
|
- PageOutline component with three-level support.
|
|
192
|
+
- ShellNotifications or equivalent notification center component for web and native shell placement.
|
|
110
193
|
- Usage example.
|
|
111
|
-
- Focused tests and typecheck/build evidence.`,
|
|
194
|
+
- Focused tests and typecheck/build evidence.`,h=`You are refactoring an existing application to use the shared application shell system.
|
|
112
195
|
|
|
113
196
|
Goal:
|
|
114
|
-
Replace app-specific sidebar, topbar, breadcrumb, command palette, account menu, mobile navigation, and in-page table-of-contents code with the shared AppShell and PageOutline system.
|
|
197
|
+
Replace app-specific sidebar, topbar, breadcrumb, command palette, notification badge/inbox, account menu, mobile navigation, and in-page table-of-contents code with the shared AppShell, ShellNotifications, and PageOutline system.
|
|
115
198
|
|
|
116
199
|
Start by auditing:
|
|
117
200
|
- Current layout wrappers and route groups.
|
|
118
201
|
- Sidebar, topbar, breadcrumb, command/search, auth menu, and mobile navigation implementations.
|
|
202
|
+
- Existing notification badges, inbox panels, toasts that represent durable in-app items, unread count queries, mark-read actions, and delivery modules.
|
|
203
|
+
- Imports from @contractspec/module.notifications that should migrate to @contractspec/lib.contracts-spec/notifications or @contractspec/lib.notification.
|
|
119
204
|
- Any duplicated navigation arrays, route labels, icon maps, access-control checks, and active-state logic.
|
|
120
205
|
- Any in-page summary/table-of-contents components that should become PageOutline data.
|
|
121
206
|
- Web-only assumptions that would block Expo/React Native adaptation.
|
|
@@ -124,25 +209,28 @@ Refactor plan:
|
|
|
124
209
|
1. Define a single typed navigation source for primary nav, grouped sidebar nav, nested children, labels, icons, badges, disabled states, and permissions.
|
|
125
210
|
2. Map existing command/search behavior into grouped command actions with search text and quick actions.
|
|
126
211
|
3. Map existing route metadata into breadcrumbs.
|
|
127
|
-
4.
|
|
128
|
-
5.
|
|
129
|
-
6.
|
|
130
|
-
7.
|
|
212
|
+
4. Move canonical notification contracts to @contractspec/lib.contracts-spec/notifications and reusable helpers to @contractspec/lib.notification; keep the old module shim only for compatibility imports that still need the legacy module id.
|
|
213
|
+
5. Convert notification query results into ShellNotificationCenter items with unreadCount, loading, empty state, onSelect, onMarkRead, and onMarkAllRead callbacks.
|
|
214
|
+
6. Convert page table-of-contents or section summary data into PageOutline items with a maximum of three levels.
|
|
215
|
+
7. Wrap app routes in AppShell while keeping page content components route-local.
|
|
216
|
+
8. Move primary mobile destinations into bottom navigation and deeper/account/notification actions into a menu or drawer.
|
|
217
|
+
9. Add or preserve .native.tsx adapters when the app targets Expo.
|
|
131
218
|
|
|
132
219
|
Preserve behavior:
|
|
133
220
|
- Existing route URLs and access rules.
|
|
134
221
|
- Existing keyboard shortcuts where they are public behavior.
|
|
135
222
|
- Existing analytics or telemetry events on navigation and command actions.
|
|
223
|
+
- Existing notification delivery semantics, unread count semantics, deep links, and mark-read behavior.
|
|
136
224
|
- Existing auth/logout behavior.
|
|
137
225
|
- Existing responsive breakpoints unless there is a documented design-system breakpoint to adopt.
|
|
138
226
|
|
|
139
227
|
Quality gates:
|
|
140
228
|
- Add regression tests around current visible navigation before removing old shell code when coverage is missing.
|
|
141
|
-
- Test active nav state, nested nav expansion, command search/action invocation, breadcrumbs, auth menu, mobile bottom navigation, and PageOutline anchor behavior.
|
|
229
|
+
- Test active nav state, nested nav expansion, command search/action invocation, breadcrumbs, notification unread badge/loading/empty/callback behavior, auth menu, mobile bottom navigation, and PageOutline anchor behavior.
|
|
142
230
|
- Run lint, typecheck, and the app's relevant test/build command.
|
|
143
231
|
- Remove dead app-specific shell components only after the shared shell path is verified.
|
|
144
232
|
|
|
145
233
|
Output:
|
|
146
234
|
- List old shell files removed or simplified.
|
|
147
235
|
- List new shared shell integration points.
|
|
148
|
-
- Include before/after route coverage and verification commands.`,
|
|
236
|
+
- Include before/after route coverage and verification commands.`,b=[{title:"Contracts stay canonical",body:"Use @contractspec/lib.contracts-spec/notifications for operation models, feature metadata, and contract-level compatibility."},{title:"Runtime helpers stay reusable",body:"Use @contractspec/lib.notification for schema contribution, channel adapters, templates, and i18n without importing the deprecated module shim in new code."},{title:"Apps own live state",body:"Fetch, subscribe, persist, mutate, and reconcile notification state in the host app or runtime layer where auth and tenancy are known."},{title:"Shell receives view state",body:"Pass AppShell a ShellNotificationCenter with render-ready items, counts, loading state, and callbacks; the design system only renders affordances."}],g=[{title:"Sidebar",body:"Desktop owns brand, command entry, grouped navigation, nested items, and account actions in one persistent scanning area."},{title:"Topbar",body:"Breadcrumbs stay visible while the current route changes. Command search and notification affordances can live here when the sidebar is collapsed or hidden."},{title:"PageOutline",body:"The right-side in-page navigator replaces ad hoc tables of contents. It supports three levels of section anchors and active state."},{title:"Notifications",body:"The shell renders unread badges, item lists, loading/empty states, mark-read actions, and deep-link selection from host-owned notification state."},{title:"Mobile adapters",body:"Small web and native surfaces move primary destinations to bottom navigation and reserve drawers or menus for deep navigation, notifications, and account actions."}];import{CodeBlock as c,InstallCommand as R}from"@contractspec/lib.design-system";import{Box as l,HStack as A,VStack as i}from"@contractspec/lib.design-system/layout";import{Code as o,H1 as S,H2 as s,H3 as f,P as r,Text as v}from"@contractspec/lib.design-system/typography";import y from"@contractspec/lib.ui-link";import{ChevronRight as M}from"lucide-react";import{jsx as e,jsxs as a}from"react/jsx-runtime";function K(){return a(i,{className:"space-y-8",children:[a(i,{className:"space-y-4",children:[e(S,{className:"font-bold text-4xl",children:"Application shell"}),a(r,{className:"text-lg text-muted-foreground",children:["A reusable navigation system for product apps: desktop sidebar, topbar breadcrumbs, command search, account actions, mobile adapters, and a Notion-style ",e(o,{children:"PageOutline"})," for page sections, with prop-driven in-app notifications for web and native shells."]})]}),a(i,{className:"space-y-4",children:[e(s,{className:"font-bold text-2xl",children:"Installation"}),e(R,{package:"@contractspec/lib.design-system"})]}),a(i,{className:"space-y-4",children:[e(s,{className:"font-bold text-2xl",children:"What It Standardizes"}),e(l,{className:"grid gap-4 md:grid-cols-2",children:g.map((t)=>a(l,{className:"card-subtle p-4",children:[e(f,{className:"font-semibold",children:t.title}),e(r,{className:"mt-2 text-muted-foreground text-sm leading-7",children:t.body})]},t.title))})]}),a(i,{className:"space-y-4",children:[e(s,{className:"font-bold text-2xl",children:"Import Surface"}),e(r,{className:"text-muted-foreground",children:"The shell is exposed as a focused design-system subpath so apps can adopt navigation chrome without pulling unrelated documentation or marketing helpers."}),e(c,{language:"tsx",filename:"app-shell-example.tsx",code:p})]}),a(i,{className:"space-y-4",children:[e(s,{className:"font-bold text-2xl",children:"Notification Center Boundary"}),a(r,{className:"text-muted-foreground",children:["Notifications are part of the shell experience, but the design system only renders the affordance. Contracts, runtime helpers, persistence, delivery, auth, and subscriptions stay outside the shell and feed a render-ready ",e(o,{children:"ShellNotificationCenter"})," into"," ",e(o,{children:"AppShell"}),"."]}),e(l,{className:"grid gap-4 md:grid-cols-2",children:b.map((t)=>a(l,{className:"card-subtle p-4",children:[e(f,{className:"font-semibold",children:t.title}),e(r,{className:"mt-2 text-muted-foreground text-sm leading-7",children:t.body})]},t.title))}),e(c,{language:"tsx",filename:"notification-center-boundary.ts",code:m})]}),a(i,{className:"space-y-4",children:[e(s,{className:"font-bold text-2xl",children:"AI Prompt: Build From Scratch"}),e(r,{className:"text-muted-foreground",children:"Use this prompt when the app does not already have a shell, command surface, page outline, or in-app notification center."}),e(c,{language:"markdown",filename:"implement-application-shell.md",code:u})]}),a(i,{className:"space-y-4",children:[e(s,{className:"font-bold text-2xl",children:"AI Prompt: Refactor An App"}),e(r,{className:"text-muted-foreground",children:"Use this prompt when an app already has custom navigation chrome and notification UI that need to migrate without breaking route behavior, unread counts, or delivery semantics."}),e(c,{language:"markdown",filename:"refactor-to-application-shell.md",code:h})]}),a(i,{className:"card-subtle space-y-3 p-6",children:[e(s,{className:"font-bold text-2xl",children:"Naming"}),a(r,{className:"text-muted-foreground",children:["Use ",e(o,{children:"AppShell"})," for the whole navigation frame and"," ",e(o,{children:"PageOutline"})," for the in-page navigation helper. The latter is the product-app equivalent of a table of contents, but it is intentionally named for live page sections rather than static documentation. Use ",e(o,{children:"ShellNotifications"})," for the notification affordance when it is rendered directly, or pass the same data contract through ",e(o,{children:"AppShell"})," with the"," ",e(o,{children:"notifications"})," prop."]})]}),a(A,{className:"flex flex-wrap items-center gap-3 pt-2",children:[e(y,{href:"/docs/libraries/cross-platform-ui",className:"btn-ghost",children:e(v,{children:"Cross-platform UI"})}),a(y,{href:"/docs/libraries/design-system",className:"btn-primary",children:[e(v,{children:"Design System"})," ",e(M,{size:16})]})]})]})}export{K as LibrariesApplicationShellPage};
|
|
@@ -1,5 +1,122 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var Z=Object.defineProperty;var b=(F)=>F;function W(F,K){this[F]=b.bind(null,K)}var O=(F,K)=>{for(var v in K)Z(F,v,{get:K[v],enumerable:!0,configurable:!0,set:W.bind(K,v)})};var B=(F,K)=>()=>(F&&(K=F(F=0)),K);import{CodeBlock as $,InstallCommand as X}from"@contractspec/lib.design-system";import{HStack as g,VStack as Q}from"@contractspec/lib.design-system/layout";import{List as h,ListItem as J}from"@contractspec/lib.design-system/list";import{Code as q,H1 as u,H2 as U,H3 as y,P as Y,Text as z}from"@contractspec/lib.design-system/typography";import G from"@contractspec/lib.ui-link";import{ChevronRight as M}from"lucide-react";import{jsx as f,jsxs as w}from"react/jsx-runtime";var p=`import { defineDataView } from '@contractspec/lib.contracts-spec/data-views';
|
|
3
|
+
|
|
4
|
+
export const AccountsDataView = defineDataView({
|
|
5
|
+
meta: {
|
|
6
|
+
key: 'crm.accounts',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
title: 'Accounts',
|
|
9
|
+
description: 'Customer account workspace',
|
|
10
|
+
domain: 'crm',
|
|
11
|
+
entity: 'account',
|
|
12
|
+
owners: ['@crm'],
|
|
13
|
+
tags: ['crm', 'accounts'],
|
|
14
|
+
stability: 'stable',
|
|
15
|
+
},
|
|
16
|
+
source: {
|
|
17
|
+
primary: { key: 'crm.accounts.list', version: '1.0.0' },
|
|
18
|
+
},
|
|
19
|
+
view: {
|
|
20
|
+
kind: 'table',
|
|
21
|
+
fields: [
|
|
22
|
+
{ key: 'name', label: 'Name', dataPath: 'name', sortable: true },
|
|
23
|
+
{ key: 'owner', label: 'Owner', dataPath: 'owner' },
|
|
24
|
+
{ key: 'arr', label: 'ARR', dataPath: 'arr', format: { type: 'currency', currency: 'EUR' } },
|
|
25
|
+
{
|
|
26
|
+
key: 'internalNotes',
|
|
27
|
+
label: 'Internal notes',
|
|
28
|
+
dataPath: 'internalNotes',
|
|
29
|
+
visibility: { minDataDepth: 'detailed' },
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
columns: [
|
|
33
|
+
{ field: 'name' },
|
|
34
|
+
{ field: 'owner' },
|
|
35
|
+
{ field: 'arr' },
|
|
36
|
+
{ field: 'internalNotes' },
|
|
37
|
+
],
|
|
38
|
+
collection: {
|
|
39
|
+
viewModes: {
|
|
40
|
+
defaultMode: 'table',
|
|
41
|
+
allowedModes: ['list', 'grid', 'table'],
|
|
42
|
+
},
|
|
43
|
+
pagination: {
|
|
44
|
+
pageSize: 25,
|
|
45
|
+
pageSizeOptions: [10, 25, 50],
|
|
46
|
+
},
|
|
47
|
+
toolbar: {
|
|
48
|
+
search: true,
|
|
49
|
+
viewMode: true,
|
|
50
|
+
filters: true,
|
|
51
|
+
density: true,
|
|
52
|
+
dataDepth: true,
|
|
53
|
+
},
|
|
54
|
+
density: 'comfortable',
|
|
55
|
+
dataDepth: 'standard',
|
|
56
|
+
personalization: {
|
|
57
|
+
enabled: true,
|
|
58
|
+
persist: {
|
|
59
|
+
viewMode: true,
|
|
60
|
+
density: true,
|
|
61
|
+
dataDepth: true,
|
|
62
|
+
pageSize: true,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});`,D=`import { DataViewRenderer } from '@contractspec/lib.design-system';
|
|
68
|
+
import { resolveDataViewPreferences } from '@contractspec/lib.personalization/data-view-preferences';
|
|
69
|
+
|
|
70
|
+
const resolved = resolveDataViewPreferences({
|
|
71
|
+
spec: AccountsDataView,
|
|
72
|
+
preferences: profile.canonical,
|
|
73
|
+
insights,
|
|
74
|
+
record: savedDataViewPreference,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
<DataViewRenderer
|
|
78
|
+
spec={AccountsDataView}
|
|
79
|
+
items={accounts}
|
|
80
|
+
defaultViewMode={resolved.viewMode}
|
|
81
|
+
defaultDensity={resolved.density}
|
|
82
|
+
defaultDataDepth={resolved.dataDepth}
|
|
83
|
+
pagination={{
|
|
84
|
+
page,
|
|
85
|
+
pageSize: resolved.pageSize ?? 25,
|
|
86
|
+
total,
|
|
87
|
+
}}
|
|
88
|
+
onViewModeChange={(viewMode) => {
|
|
89
|
+
tracker.trackDataViewInteraction({
|
|
90
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
91
|
+
dataViewVersion: AccountsDataView.meta.version,
|
|
92
|
+
action: 'view_mode_changed',
|
|
93
|
+
viewMode,
|
|
94
|
+
});
|
|
95
|
+
}}
|
|
96
|
+
onDensityChange={(density) => {
|
|
97
|
+
tracker.trackDataViewInteraction({
|
|
98
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
99
|
+
action: 'density_changed',
|
|
100
|
+
density,
|
|
101
|
+
});
|
|
102
|
+
}}
|
|
103
|
+
onDataDepthChange={(dataDepth) => {
|
|
104
|
+
tracker.trackDataViewInteraction({
|
|
105
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
106
|
+
action: 'data_depth_changed',
|
|
107
|
+
dataDepth,
|
|
108
|
+
});
|
|
109
|
+
}}
|
|
110
|
+
/>;
|
|
111
|
+
`,N=`Implement a production DataView for <entity>.
|
|
112
|
+
|
|
113
|
+
Requirements:
|
|
114
|
+
- Define one canonical DataViewSpec with kind 'table', collection viewModes for list/grid/table, pagination defaults, toolbar search/filter/view mode/density/dataDepth controls, and personalization persist hints.
|
|
115
|
+
- Mark fields that should only appear in richer experiences with visibility.minDataDepth.
|
|
116
|
+
- Render it with DataViewRenderer using plain props from resolveDataViewPreferences.
|
|
117
|
+
- Track user interactions with trackDataViewInteraction for view mode, density, data depth, search, filters, sorting, and pagination.
|
|
118
|
+
- Keep @contractspec/lib.design-system independent from @contractspec/lib.personalization.
|
|
119
|
+
- Add focused tests for default resolution, invalid-mode fallback, data-depth projection, and behavior-derived preferred view mode.`;function l(){return w(Q,{className:"space-y-8",children:[w(Q,{className:"space-y-4",children:[f(u,{className:"font-bold text-4xl",children:"DataViews Runtime Library"}),w(Y,{className:"text-lg text-muted-foreground",children:["The ",f(q,{children:"@contractspec/lib.contracts-spec/data-views"})," and"," ",f(q,{children:"@contractspec/lib.design-system"})," libraries provide the runtime logic and UI components to render DataViews in your application."]})]}),w(Q,{className:"space-y-4",children:[f(U,{className:"font-bold text-2xl",children:"Installation"}),f(X,{package:["@contractspec/lib.contracts-spec","@contractspec/lib.design-system"]})]}),w(Q,{className:"space-y-4",children:[f(U,{className:"font-bold text-2xl",children:"DataViewRenderer"}),f(Y,{className:"text-muted-foreground",children:"The primary component for rendering any DataView. It automatically selects the correct layout (List, Table, Grid, Detail) based on the spec."}),f($,{language:"tsx",code:`import { DataViewRenderer } from '@contractspec/lib.design-system';
|
|
3
120
|
import { MyUserList } from './specs/users.data-view';
|
|
4
121
|
|
|
5
122
|
export function UserPage() {
|
|
@@ -11,7 +128,7 @@ export function UserPage() {
|
|
|
11
128
|
onPageChange={(page) => fetchPage(page)}
|
|
12
129
|
/>
|
|
13
130
|
);
|
|
14
|
-
}`}),
|
|
131
|
+
}`}),f(y,{className:"font-semibold text-xl",children:"Props"}),w(h,{className:"list-disc space-y-2 pl-6 text-muted-foreground",children:[f(J,{children:w(z,{children:[f(q,{children:"spec"}),": The DataViewSpec definition."]})}),f(J,{children:w(z,{children:[f(q,{children:"items"}),": Array of data items to render."]})}),f(J,{children:w(z,{children:[f(q,{children:"filters"}),": Current filter state object."]})}),f(J,{children:w(z,{children:[f(q,{children:"onFilterChange"}),": Callback when typed filters change. Renderers emit ",f(q,{children:"DataViewFilterValue"})," objects for numeric, percent, currency, temporal, duration, and boolean filters."]})}),f(J,{children:w(z,{children:[f(q,{children:"pagination"}),": Object with ",f(q,{children:"page"}),","," ",f(q,{children:"pageSize"}),", ",f(q,{children:"total"}),"."]})}),f(J,{children:w(z,{children:[f(q,{children:"onPageChange"}),": Callback when page changes."]})}),f(J,{children:w(z,{children:[f(q,{children:"viewMode"})," / ",f(q,{children:"defaultViewMode"}),": Controlled or initial collection mode for specs that allow ",f(q,{children:"list"}),","," ",f(q,{children:"grid"}),", or ",f(q,{children:"table"})," projections through"," ",f(q,{children:"view.collection.viewModes"}),"."]})}),f(J,{children:w(z,{children:[f(q,{children:"density"})," / ",f(q,{children:"defaultDensity"}),": Controlled or initial density for collection renderers. Host apps can seed this from ",f(q,{children:"@contractspec/lib.personalization"})," while specs can declare ",f(q,{children:"view.collection.density"})," and table"," ",f(q,{children:"view.density"})," defaults."]})}),f(J,{children:w(z,{children:[f(q,{children:"dataDepth"})," / ",f(q,{children:"defaultDataDepth"}),": Controlled or initial summary/standard/detailed/exhaustive projection. Fields can declare ",f(q,{children:"visibility.minDataDepth"}),", and collection specs can opt into ",f(q,{children:"view.collection.personalization"})," ","persistence hints."]})})]})]}),w(Q,{className:"space-y-4",children:[f(U,{className:"font-bold text-2xl",children:"Collection Defaults And Data Depth"}),w(Y,{className:"text-muted-foreground",children:["Use one authored ",f(q,{children:"DataViewSpec"})," for list, grid, and table experiences. ",f(q,{children:"view.collection"})," declares allowed modes, toolbar controls, pagination defaults, density, data depth, and persistence hints. ",f(q,{children:"visibility.minDataDepth"})," lets a field appear only when the renderer is in a detailed or exhaustive mode."]}),f($,{language:"typescript",code:p})]}),w(Q,{className:"space-y-4",children:[f(U,{className:"font-bold text-2xl",children:"Personalization Bridge"}),w(Y,{className:"text-muted-foreground",children:["Resolve user preferences in the host app, then pass ordinary renderer props into ",f(q,{children:"DataViewRenderer"}),". The bridge helper lives in"," ",f(q,{children:"@contractspec/lib.personalization"}),", so the design-system renderer stays portable for apps that do not use personalization. See the"," ",f(G,{href:"/docs/libraries/personalization",className:"text-[color:var(--rust)] underline underline-offset-4",children:f(z,{children:"personalization library guide"})})," ","for the behavior tracker, analyzer, and DataView preference resolver."]}),f($,{language:"tsx",code:D})]}),w(Q,{className:"space-y-4",children:[f(U,{className:"font-bold text-2xl",children:"Agent Prompt"}),f(Y,{className:"text-muted-foreground",children:"Use this prompt when asking an implementation agent to add a preference-aware collection DataView without breaking package boundaries."}),f($,{language:"markdown",code:N})]}),w(Q,{className:"space-y-4",children:[f(U,{className:"font-bold text-2xl",children:"Query Generation"}),w(Y,{className:"text-muted-foreground",children:["The ",f(q,{children:"DataViewQueryGenerator"})," utility helps translate DataView parameters (filters, sorting, pagination) into query arguments for your backend."]}),f($,{language:"typescript",code:`import { DataViewQueryGenerator } from '@contractspec/lib.contracts-spec/data-views/query-generator';
|
|
15
132
|
|
|
16
133
|
const generator = new DataViewQueryGenerator(MyUserList);
|
|
17
134
|
const params = {
|
|
@@ -26,4 +143,4 @@ const params = {
|
|
|
26
143
|
const errors = generator.validateParams(params);
|
|
27
144
|
const query = generator.generate(params);
|
|
28
145
|
|
|
29
|
-
// query.input contains skip/take plus the typed filter payloads.`})]}),
|
|
146
|
+
// query.input contains skip/take plus the typed filter payloads.`})]}),w(g,{className:"items-center gap-4 pt-4",children:[f(G,{href:"/docs/libraries",className:"btn-ghost",children:f(z,{children:"Back to Libraries"})}),w(G,{href:"/docs/libraries/data-backend",className:"btn-primary",children:[f(z,{children:"Next: Data & Backend"})," ",f(M,{size:16})]})]})]})}export{l as LibrariesDataViewsPage};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var c=Object.defineProperty;var s=(o)=>o;function l(o,a){this[o]=s.bind(null,a)}var v=(o,a)=>{for(var n in a)c(o,n,{get:a[n],enumerable:!0,configurable:!0,set:l.bind(a,n)})};var y=(o,a)=>()=>(o&&(a=o(o=0)),a);import{CodeBlock as r,InstallCommand as d}from"@contractspec/lib.design-system";import i from"@contractspec/lib.ui-link";import{ChevronRight as m}from"lucide-react";import{jsx as e,jsxs as t}from"react/jsx-runtime";var p=`import { Button, DataTable } from '@contractspec/lib.design-system';
|
|
3
3
|
import { useContractTable } from '@contractspec/lib.presentation-runtime-react';
|
|
4
4
|
|
|
5
5
|
import { SHOWCASE_ROWS } from '@contractspec/example.data-grid-showcase/ui/data-grid-showcase.data';
|
|
@@ -81,6 +81,105 @@ export function TenantSurface({ children }: { children: React.ReactNode }) {
|
|
|
81
81
|
import { Select } from '@contractspec/lib.design-system/controls';
|
|
82
82
|
import { FormDialog } from '@contractspec/lib.design-system/forms';
|
|
83
83
|
import { HStack } from '@contractspec/lib.design-system/layout';
|
|
84
|
+
import { AdaptivePanel } from '@contractspec/lib.design-system/components/overlays';
|
|
85
|
+
import { ObjectReferenceHandler } from '@contractspec/lib.design-system/components/object-reference';
|
|
84
86
|
|
|
85
87
|
// Root imports remain supported:
|
|
86
|
-
import { Button, DataTable } from '@contractspec/lib.design-system'
|
|
88
|
+
import { Button, DataTable } from '@contractspec/lib.design-system';`,f=`import {
|
|
89
|
+
ObjectReferenceHandler,
|
|
90
|
+
createDefaultObjectReferenceActions,
|
|
91
|
+
createMapsReferenceActions,
|
|
92
|
+
type ObjectReferenceDescriptor,
|
|
93
|
+
type ObjectReferenceOpenHrefHandler,
|
|
94
|
+
} from '@contractspec/lib.design-system';
|
|
95
|
+
|
|
96
|
+
const customerContact: ObjectReferenceDescriptor = {
|
|
97
|
+
id: 'user.amina',
|
|
98
|
+
kind: 'user',
|
|
99
|
+
label: 'Amina Laurent',
|
|
100
|
+
description: 'Customer success owner',
|
|
101
|
+
href: '/customers/acme/users/amina',
|
|
102
|
+
properties: [
|
|
103
|
+
{
|
|
104
|
+
id: 'user.amina.email',
|
|
105
|
+
kind: 'email',
|
|
106
|
+
label: 'Email',
|
|
107
|
+
value: 'amina@example.com',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'user.amina.phone',
|
|
111
|
+
kind: 'phone',
|
|
112
|
+
label: 'Phone',
|
|
113
|
+
value: '+33 1 23 45 67 89',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
sections: [
|
|
117
|
+
{
|
|
118
|
+
id: 'customer-site',
|
|
119
|
+
title: 'Primary site',
|
|
120
|
+
properties: [
|
|
121
|
+
{
|
|
122
|
+
id: 'customer-site.address',
|
|
123
|
+
kind: 'address',
|
|
124
|
+
label: 'Paris office',
|
|
125
|
+
value: '10 rue de Rivoli, 75001 Paris',
|
|
126
|
+
actions: createMapsReferenceActions({
|
|
127
|
+
id: 'customer-site.address',
|
|
128
|
+
kind: 'address',
|
|
129
|
+
label: 'Paris office',
|
|
130
|
+
value: '10 rue de Rivoli, 75001 Paris',
|
|
131
|
+
}),
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const openHref: ObjectReferenceOpenHrefHandler = (href, _event, options) => {
|
|
139
|
+
if (options.target === 'new-page') {
|
|
140
|
+
window.open(href, '_blank', 'noopener,noreferrer');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
window.location.assign(href);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
<ObjectReferenceHandler
|
|
148
|
+
reference={customerContact}
|
|
149
|
+
actions={createDefaultObjectReferenceActions(customerContact)}
|
|
150
|
+
interactivityVisibility="icon"
|
|
151
|
+
openTarget="same-page"
|
|
152
|
+
panelMode="responsive"
|
|
153
|
+
mobilePanelMode="drawer"
|
|
154
|
+
desktopPanelMode="sheet"
|
|
155
|
+
responsiveBreakpoint="md"
|
|
156
|
+
openHref={openHref}
|
|
157
|
+
/>;`,g=`import { AdaptivePanel } from '@contractspec/lib.design-system/components/overlays';
|
|
158
|
+
|
|
159
|
+
<AdaptivePanel
|
|
160
|
+
open={open}
|
|
161
|
+
onOpenChange={setOpen}
|
|
162
|
+
trigger={<button type="button">Edit</button>}
|
|
163
|
+
title="Edit customer"
|
|
164
|
+
description="Update contact and site details."
|
|
165
|
+
mode="responsive"
|
|
166
|
+
mobileMode="drawer"
|
|
167
|
+
desktopMode="sheet"
|
|
168
|
+
breakpoint="md"
|
|
169
|
+
sheetSide="right"
|
|
170
|
+
drawerDirection="bottom"
|
|
171
|
+
>
|
|
172
|
+
{content}
|
|
173
|
+
</AdaptivePanel>;`,b=`Find every user-facing address, phone number, email, user, customer, file, URL, and tenant-specific object reference currently rendered as inert text.
|
|
174
|
+
|
|
175
|
+
Replace each one with ObjectReferenceHandler from @contractspec/lib.design-system. Keep descriptors data-only: id, kind, label, value, href, openTarget, properties, sections, metadata, iconKey, and ariaLabel are allowed; React callbacks belong in handler props only.
|
|
176
|
+
|
|
177
|
+
Use properties and sections for rich references. For example, a user reference can expose email, phone, address, files, and customer links in one panel instead of rendering separate disconnected strings.
|
|
178
|
+
|
|
179
|
+
Use panelMode="responsive" by default. Let desktop render a sheet and small screens render a bottom drawer through AdaptivePanel. Do not call Sheet or Drawer directly for this interaction unless a lower-level primitive is being implemented.
|
|
180
|
+
|
|
181
|
+
Use openTarget="same-page" unless product requirements explicitly require a new page. Put custom copy, navigation, analytics, permissions, or tenant-specific actions in copyHandler, openHref, actionHandlers, onAction, and onActionError.
|
|
182
|
+
|
|
183
|
+
For addresses, use createMapsReferenceActions so users can choose Google Maps, Apple Maps, or Waze. For email and phone references, prefer createDefaultObjectReferenceActions unless a product-specific action set is required.
|
|
184
|
+
|
|
185
|
+
After replacing references, verify keyboard access, visible affordance choice (none, underline, or icon), safe href behavior, mobile drawer layout, and desktop sheet layout.`;function k(){return t("div",{className:"space-y-8",children:[t("div",{className:"space-y-4",children:[e("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.design-system"}),t("p",{className:"text-muted-foreground",children:["High-level design system components, patterns, and layouts for LSSM applications. Built on top of ",e("code",{children:"@contractspec/lib.ui-kit"}),"."]})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Installation"}),e(d,{package:"@contractspec/lib.design-system"})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"What It Provides"}),t("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[t("li",{children:[e("strong",{children:"Composite Components"}),": Molecules and Organisms that solve common UI problems"]}),t("li",{children:[e("strong",{children:"Layouts"}),": Ready-to-use page structures for dashboards, marketing sites, and lists"]}),t("li",{children:[e("strong",{children:"Data Views"}),": Standardized renderers for lists, tables, and detail views"]}),t("li",{children:[e("strong",{children:"Forms"}),": Zod-integrated form layouts and components"]}),t("li",{children:[e("strong",{children:"Code Display"}),": Syntax-highlighted code blocks with package manager tabs"]}),t("li",{children:[e("strong",{children:"Platform Utilities"}),": Hooks for responsive and adaptive design"]}),t("li",{children:[e("strong",{children:"Object References"}),": Clickable references for addresses, phone numbers, users, customers, files, URLs, and custom objects"]}),t("li",{children:[e("strong",{children:"Adaptive Panels"}),": One panel API that resolves to a desktop sheet or mobile drawer"]}),t("li",{children:[e("strong",{children:"Theme Bridge"}),": ThemeSpec to Tailwind variables, presets, CSS text, and runtime light/dark mode"]}),t("li",{children:[e("strong",{children:"Legal Templates"}),": Compliant templates for Terms, Privacy, and GDPR"]})]})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"ThemeSpec to Tailwind"}),t("p",{className:"text-muted-foreground",children:["The theme bridge keeps ",e("code",{children:"ThemeSpec"})," as the source of truth and exposes no-generation Tailwind helpers, optional CSS text serialization, runtime CSS variables, light/dark modes, and OKLCH color pass-through."]}),e(r,{language:"tsx",code:u})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Focused import surfaces"}),e("p",{className:"text-muted-foreground",children:"New code can use focused subpaths for theme, controls, forms, and layout while existing root imports remain compatible."}),e(r,{language:"tsx",code:h})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Actionable object references"}),t("p",{className:"text-muted-foreground",children:["Use ",e("code",{children:"ObjectReferenceHandler"})," whenever a product surface renders an object that may need quick interaction: addresses, phone numbers, emails, users, customers, files, URLs, and tenant-specific objects. The goal is to avoid inert references while keeping the descriptor contract declarative enough for OSS consumers and future contract-generated surfaces."]}),t("div",{className:"grid gap-4 md:grid-cols-2",children:[t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Descriptor model"}),t("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[t("li",{children:["References use data-only descriptors: ",e("code",{children:"id"}),","," ",e("code",{children:"kind"}),", ",e("code",{children:"label"}),", ",e("code",{children:"value"}),","," ",e("code",{children:"href"}),", ",e("code",{children:"openTarget"}),","," ",e("code",{children:"metadata"}),", ",e("code",{children:"iconKey"}),", and"," ",e("code",{children:"ariaLabel"}),"."]}),t("li",{children:["Rich references use nested ",e("code",{children:"properties"})," and"," ",e("code",{children:"sections"}),", so one user or customer can expose email, phone, address, files, and links inside the same panel."]}),t("li",{children:["Reference kinds are ",e("code",{children:"address"}),", ",e("code",{children:"email"}),","," ",e("code",{children:"phone"}),", ",e("code",{children:"user"}),", ",e("code",{children:"customer"}),","," ",e("code",{children:"file"}),", ",e("code",{children:"url"}),", and ",e("code",{children:"custom"}),"."]})]})]}),t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Runtime behavior"}),t("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[t("li",{children:["Choose visibility with ",e("code",{children:"interactivityVisibility"}),":",e("code",{children:"none"}),", ",e("code",{children:"underline"}),", or ",e("code",{children:"icon"}),"."]}),t("li",{children:["Detail navigation defaults to ",e("code",{children:"same-page"}),"; set"," ",e("code",{children:'openTarget="new-page"'})," on the handler, reference, or action when a new page is required."]}),t("li",{children:["Host apps provide behavior through ",e("code",{children:"copyHandler"}),","," ",e("code",{children:"openHref"}),", ",e("code",{children:"actionHandlers"}),","," ",e("code",{children:"onAction"}),", and ",e("code",{children:"onActionError"}),"."]})]})]}),t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Default actions"}),t("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[t("li",{children:[e("code",{children:"createDefaultObjectReferenceActions"})," adds copy, open, email, phone, and map actions when the descriptor supports them."]}),t("li",{children:[e("code",{children:"createMapsReferenceActions"})," creates Google Maps, Apple Maps, Waze, or geo actions for address references."]}),e("li",{children:"Safe href handling allows expected app, web, email, phone, and map URLs while rejecting unsafe schemes."})]})]}),t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Extension points"}),t("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[t("li",{children:["Use ",e("code",{children:"renderTrigger"}),", ",e("code",{children:"renderDetail"}),","," ",e("code",{children:"renderAction"}),", ",e("code",{children:"renderProperty"}),","," ",e("code",{children:"renderSection"}),", and ",e("code",{children:"iconRenderer"})," to wrap or overload presentation."]}),e("li",{children:"Keep tenant-specific permissions, analytics, and integration side effects at the host boundary through runtime handlers."})]})]})]}),e(r,{language:"tsx",code:f})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Adaptive panels"}),t("p",{className:"text-muted-foreground",children:[e("code",{children:"AdaptivePanel"})," is the shared overlay decision for surfaces that should feel native on both desktop and small screens. Its default responsive mode renders a sheet at the configured desktop breakpoint and a drawer below it. ",e("code",{children:"ObjectReferenceHandler"})," uses this panel contract through ",e("code",{children:"panelMode"}),","," ",e("code",{children:"mobilePanelMode"}),", ",e("code",{children:"desktopPanelMode"}),", and"," ",e("code",{children:"responsiveBreakpoint"}),"."]}),e(r,{language:"tsx",code:g})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Prompt for adoption work"}),e("p",{className:"text-muted-foreground",children:"Use this prompt when asking an agent or downstream OSS consumer to replace inert references across an application."}),e(r,{language:"text",code:b})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Data table example"}),t("p",{className:"text-muted-foreground",children:["This is the composed lane from the canonical"," ",e(i,{href:"/docs/examples/data-grid-showcase",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Data Grid Showcase"}),". The design-system wrapper owns title, description, header actions, and the opinionated card shell on top of the raw web primitive."]}),e(r,{language:"tsx",code:p})]}),t("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Key Exports"}),t("div",{className:"grid gap-4 md:grid-cols-2",children:[t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Organisms"}),t("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"AppShell, PageOutline"}),e("li",{children:"AppLayout, AppHeader, AppSidebar"}),e("li",{children:"MarketingLayout, HeroSection"}),e("li",{children:"ListCardPage, ListTablePage"})]})]}),t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Data & Forms"}),t("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"DataTable"}),e("li",{children:"DataViewTable"}),e("li",{children:"DataViewRenderer"}),e("li",{children:"ZodForm"}),e("li",{children:"FormLayout, FormDialog"})]})]}),t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Code Display"}),t("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"CodeBlock (syntax highlighting)"}),e("li",{children:"CommandTabs (package manager tabs)"}),e("li",{children:"InstallCommand (convenience wrapper)"}),e("li",{children:"CopyButton"})]})]}),t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Providers"}),e("ul",{className:"space-y-1 text-muted-foreground text-sm",children:e("li",{children:"PackageManagerProvider"})})]}),t("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"References & Overlays"}),t("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"ObjectReferenceHandler"}),e("li",{children:"createDefaultObjectReferenceActions"}),e("li",{children:"createMapsReferenceActions"}),e("li",{children:"AdaptivePanel"})]})]})]})]}),t("div",{className:"card-subtle space-y-3 p-6",children:[e("h2",{className:"font-bold text-2xl",children:"Where this layer fits"}),t("p",{className:"text-muted-foreground",children:["Read"," ",e(i,{href:"/docs/libraries/application-shell",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Application shell"})," ","for the shared sidebar, topbar, command search, mobile navigation, and"," ",e("code",{children:"PageOutline"})," pattern. Read"," ",e(i,{href:"/docs/libraries/cross-platform-ui",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Cross-platform UI"})," ","for the package split between shared runtime controllers, leaf platform primitives, and this composed design-system layer."]})]}),t("div",{className:"flex items-center gap-4 pt-4",children:[e(i,{href:"/docs/libraries/ui-kit-web",className:"btn-ghost",children:"Previous: UI Kit Web"}),t(i,{href:"/docs/libraries/accessibility",className:"btn-primary",children:["Next: Accessibility ",e(m,{size:16})]})]})]})}export{k as LibrariesDesignSystemPage};
|