@cohesivesystems/presentation-tailwind 0.1.0-alpha.1
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/LICENSE +55 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation-shell-layout-runtime.d.ts +29 -0
- package/dist/navigation-shell-layout-runtime.d.ts.map +1 -0
- package/dist/navigation-shell-layout-runtime.js +70 -0
- package/dist/navigation-shell-layout-runtime.js.map +1 -0
- package/dist/presentation-design-system.d.ts +144 -0
- package/dist/presentation-design-system.d.ts.map +1 -0
- package/dist/presentation-design-system.js +468 -0
- package/dist/presentation-design-system.js.map +1 -0
- package/dist/presentation-routed-surface-layout.d.ts +24 -0
- package/dist/presentation-routed-surface-layout.d.ts.map +1 -0
- package/dist/presentation-routed-surface-layout.js +38 -0
- package/dist/presentation-routed-surface-layout.js.map +1 -0
- package/dist/presentation-text-badge.d.ts +13 -0
- package/dist/presentation-text-badge.d.ts.map +1 -0
- package/dist/presentation-text-badge.js +23 -0
- package/dist/presentation-text-badge.js.map +1 -0
- package/package.json +59 -0
- package/src/index.ts +6 -0
- package/src/navigation-shell-layout-runtime.ts +135 -0
- package/src/presentation-design-system.ts +773 -0
- package/src/presentation-routed-surface-layout.ts +87 -0
- package/src/presentation-text-badge.ts +28 -0
- package/src/theme.css +7 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ActionDefinition,
|
|
3
|
+
ActionPlacementDefinition,
|
|
4
|
+
DesignIntent,
|
|
5
|
+
InputFormGroupDefinition,
|
|
6
|
+
NavigationShellSlotDefinition,
|
|
7
|
+
} from '@cohesivesystems/presentation-contracts'
|
|
8
|
+
import {
|
|
9
|
+
inputFormGroupKinds,
|
|
10
|
+
navigationShellSlotKinds,
|
|
11
|
+
} from '@cohesivesystems/presentation-contracts'
|
|
12
|
+
import type {
|
|
13
|
+
PresentationDesignIntentFieldName,
|
|
14
|
+
} from '@cohesivesystems/presentation-core'
|
|
15
|
+
|
|
16
|
+
export interface PresentationDesignSystemDesignIntentInterpretation {
|
|
17
|
+
readonly ignoredFields: readonly PresentationDesignIntentFieldName[]
|
|
18
|
+
readonly interpretedFields: readonly PresentationDesignIntentFieldName[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface PresentationDesignSystemDiagnostics {
|
|
22
|
+
readonly navigationShellFrame: PresentationDesignSystemDesignIntentInterpretation
|
|
23
|
+
readonly navigationShellSlot: PresentationDesignSystemDesignIntentInterpretation
|
|
24
|
+
readonly routedSurfaceLayout: PresentationDesignSystemDesignIntentInterpretation
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PresentationRoutedSurfaceClassNameContext {
|
|
28
|
+
readonly design: DesignIntent | null | undefined
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface PresentationToneClassNameContext {
|
|
32
|
+
readonly tone: string | null | undefined
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PresentationDocumentWorkspaceNodeClassNameContext {
|
|
36
|
+
readonly isActiveSearchMatch?: boolean
|
|
37
|
+
readonly isSearchMatch?: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface PresentationDocumentWorkspaceToneClassNameContext {
|
|
41
|
+
readonly label?: string | null | undefined
|
|
42
|
+
readonly tone: string | null | undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface PresentationSurfaceChromeClassNameContext {
|
|
46
|
+
readonly design?: DesignIntent | null | undefined
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface PresentationInputFormGroupClassNameContext {
|
|
50
|
+
readonly group: InputFormGroupDefinition
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface PresentationNavigationShellClassNameContext {
|
|
54
|
+
readonly design: DesignIntent | null | undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface PresentationNavigationShellSlotClassNameContext {
|
|
58
|
+
readonly slot: NavigationShellSlotDefinition
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface PresentationActionButtonContext {
|
|
62
|
+
readonly action: ActionDefinition | null
|
|
63
|
+
readonly placement: ActionPlacementDefinition
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type PresentationActionButtonSize =
|
|
67
|
+
'default' | 'icon' | 'icon-lg' | 'icon-sm' | 'icon-xs' | 'lg' | 'sm' | 'xs'
|
|
68
|
+
|
|
69
|
+
export type PresentationActionButtonVariant =
|
|
70
|
+
'default' | 'destructive' | 'ghost' | 'link' | 'outline' | 'secondary'
|
|
71
|
+
|
|
72
|
+
export interface PresentationDesignSystemClassNames {
|
|
73
|
+
readonly badge: {
|
|
74
|
+
readonly tone: (context: PresentationToneClassNameContext) => string
|
|
75
|
+
}
|
|
76
|
+
readonly documentWorkspace: {
|
|
77
|
+
readonly actionRow: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
78
|
+
readonly actionIcon: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
79
|
+
readonly codeCell: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
80
|
+
readonly codeTable: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
81
|
+
readonly constraintBlock: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
82
|
+
readonly constraintList: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
83
|
+
readonly contentPane: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
84
|
+
readonly dataTableContainer: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
85
|
+
readonly detailContent: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
86
|
+
readonly detailEmpty: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
87
|
+
readonly detailHeader: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
88
|
+
readonly detailHeaderContent: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
89
|
+
readonly detailPanel: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
90
|
+
readonly detailSubtitle: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
91
|
+
readonly detailTable: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
92
|
+
readonly detailTableLabelCell: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
93
|
+
readonly detailTableRow: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
94
|
+
readonly detailTableValueCell: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
95
|
+
readonly detailTableValueText: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
96
|
+
readonly detailTitle: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
97
|
+
readonly errorMessage: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
98
|
+
readonly iconTone: (context: PresentationDocumentWorkspaceToneClassNameContext) => string
|
|
99
|
+
readonly inlineMeta: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
100
|
+
readonly loadingMessage: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
101
|
+
readonly nodeBadge: (context: PresentationDocumentWorkspaceToneClassNameContext) => string
|
|
102
|
+
readonly nodeLabel: (context: PresentationDocumentWorkspaceNodeClassNameContext) => string
|
|
103
|
+
readonly nodeLabelText: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
104
|
+
readonly root: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
105
|
+
readonly section: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
106
|
+
readonly sectionBody: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
107
|
+
readonly sectionHeading: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
108
|
+
readonly sectionHeadingRow: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
109
|
+
readonly splitter: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
110
|
+
readonly splitterHandle: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
111
|
+
readonly status: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
112
|
+
readonly tableCell: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
113
|
+
readonly tableHeader: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
114
|
+
readonly tableHeaderCell: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
115
|
+
readonly treePane: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
116
|
+
}
|
|
117
|
+
readonly formSurface: {
|
|
118
|
+
readonly actionRow: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
119
|
+
readonly content: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
120
|
+
readonly field: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
121
|
+
readonly group: (context: PresentationInputFormGroupClassNameContext) => string
|
|
122
|
+
readonly groups: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
123
|
+
readonly rangeGroup: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
124
|
+
readonly root: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
125
|
+
}
|
|
126
|
+
readonly metricDashboard: {
|
|
127
|
+
readonly root: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
128
|
+
}
|
|
129
|
+
readonly navigationShell: {
|
|
130
|
+
readonly brandBadge: (context: PresentationNavigationShellClassNameContext) => string
|
|
131
|
+
readonly brandSubtitle: (context: PresentationNavigationShellClassNameContext) => string
|
|
132
|
+
readonly brandTitle: (context: PresentationNavigationShellClassNameContext) => string
|
|
133
|
+
readonly header: (context: PresentationNavigationShellClassNameContext) => string
|
|
134
|
+
readonly headerContent: (context: PresentationNavigationShellClassNameContext) => string
|
|
135
|
+
readonly headerNavigation: (context: PresentationNavigationShellClassNameContext) => string
|
|
136
|
+
readonly navigationItem: (context: PresentationNavigationShellClassNameContext) => string
|
|
137
|
+
readonly root: (context: PresentationNavigationShellClassNameContext) => string
|
|
138
|
+
readonly slotRoot: (context: PresentationNavigationShellSlotClassNameContext) => string
|
|
139
|
+
}
|
|
140
|
+
readonly routedSurface: {
|
|
141
|
+
readonly content: (context: PresentationRoutedSurfaceClassNameContext) => string
|
|
142
|
+
readonly root: (context: PresentationRoutedSurfaceClassNameContext) => string
|
|
143
|
+
}
|
|
144
|
+
readonly recordDetail: {
|
|
145
|
+
readonly root: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
146
|
+
}
|
|
147
|
+
readonly statusNotice: {
|
|
148
|
+
readonly tone: (context: PresentationToneClassNameContext) => string
|
|
149
|
+
}
|
|
150
|
+
readonly viewSurface: {
|
|
151
|
+
readonly content: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
152
|
+
readonly root: (context: PresentationSurfaceChromeClassNameContext) => string
|
|
153
|
+
}
|
|
154
|
+
readonly toggle: {
|
|
155
|
+
readonly tone: (context: PresentationToneClassNameContext) => string
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface PresentationDesignSystemComponents {
|
|
160
|
+
readonly actionButton: {
|
|
161
|
+
readonly size: (context: PresentationActionButtonContext) => PresentationActionButtonSize
|
|
162
|
+
readonly variant: (context: PresentationActionButtonContext) => PresentationActionButtonVariant
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface PresentationDesignSystem {
|
|
167
|
+
readonly classNames: PresentationDesignSystemClassNames
|
|
168
|
+
readonly components: PresentationDesignSystemComponents
|
|
169
|
+
readonly diagnostics: PresentationDesignSystemDiagnostics
|
|
170
|
+
readonly id: string
|
|
171
|
+
readonly target: string
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const workspaceRoleTokens = new Set([
|
|
175
|
+
'detail',
|
|
176
|
+
'details',
|
|
177
|
+
'execution-details',
|
|
178
|
+
])
|
|
179
|
+
|
|
180
|
+
const fullWidthRoleTokens = new Set([
|
|
181
|
+
'catalog',
|
|
182
|
+
'collection',
|
|
183
|
+
'document-workspace',
|
|
184
|
+
'editor',
|
|
185
|
+
'list',
|
|
186
|
+
'table',
|
|
187
|
+
'workspace',
|
|
188
|
+
])
|
|
189
|
+
|
|
190
|
+
const wideRoleTokens = new Set([
|
|
191
|
+
'catalog',
|
|
192
|
+
'collection',
|
|
193
|
+
'list',
|
|
194
|
+
'table',
|
|
195
|
+
])
|
|
196
|
+
|
|
197
|
+
const workspaceSizeHints = new Set([
|
|
198
|
+
'2xl',
|
|
199
|
+
'full',
|
|
200
|
+
'max',
|
|
201
|
+
'screen',
|
|
202
|
+
'xl',
|
|
203
|
+
])
|
|
204
|
+
|
|
205
|
+
const wideSizeHints = new Set([
|
|
206
|
+
'wide',
|
|
207
|
+
])
|
|
208
|
+
|
|
209
|
+
export const tailwindPresentationDesignSystem: PresentationDesignSystem = {
|
|
210
|
+
classNames: {
|
|
211
|
+
badge: {
|
|
212
|
+
tone: ({ tone }) => badgeClassByTone[coercePresentationTone(tone)],
|
|
213
|
+
},
|
|
214
|
+
documentWorkspace: {
|
|
215
|
+
actionRow: () => 'mt-3',
|
|
216
|
+
actionIcon: () => 'size-3.5',
|
|
217
|
+
codeCell: () => 'border-b border-slate-950/8 px-3 py-2 font-mono text-[0.72rem] font-semibold text-slate-900',
|
|
218
|
+
codeTable: () => 'w-full border-separate border-spacing-0 text-left text-xs',
|
|
219
|
+
constraintBlock: () => 'overflow-auto px-3 py-2 text-xs text-slate-700',
|
|
220
|
+
constraintList: () => 'grid gap-2',
|
|
221
|
+
contentPane: () => 'h-full overflow-auto px-2 py-2',
|
|
222
|
+
dataTableContainer: () =>
|
|
223
|
+
'mt-2 max-h-86 overflow-auto rounded-md border border-slate-950/8 bg-white/72',
|
|
224
|
+
detailContent: () => 'min-h-0 flex-1 overflow-auto px-4 py-3',
|
|
225
|
+
detailEmpty: () =>
|
|
226
|
+
'flex h-full items-center justify-center px-4 py-3 text-sm text-slate-500',
|
|
227
|
+
detailHeader: () => 'border-b border-slate-950/8 px-4 py-3',
|
|
228
|
+
detailHeaderContent: () => 'flex min-w-0 items-center gap-2',
|
|
229
|
+
detailPanel: () => 'flex h-full min-w-0 flex-col overflow-hidden bg-slate-50/55',
|
|
230
|
+
detailSubtitle: () =>
|
|
231
|
+
'text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-slate-500',
|
|
232
|
+
detailTable: () => 'w-full border-separate border-spacing-0 text-left text-sm',
|
|
233
|
+
detailTableLabelCell: () =>
|
|
234
|
+
'w-36 border-b border-slate-950/8 py-2 pr-3 text-xs font-semibold uppercase tracking-[0.12em] text-slate-500',
|
|
235
|
+
detailTableRow: () => 'align-top',
|
|
236
|
+
detailTableValueCell: () => 'border-b border-slate-950/8 py-2 text-slate-800',
|
|
237
|
+
detailTableValueText: () => 'wrap-break-word',
|
|
238
|
+
detailTitle: () => 'truncate text-sm font-semibold text-slate-950',
|
|
239
|
+
errorMessage: () =>
|
|
240
|
+
'mt-4 rounded-md border border-red-300/60 bg-red-50 px-3 py-2 text-sm text-red-800',
|
|
241
|
+
iconTone: ({ tone }) => documentWorkspaceIconClassByTone[coerceDocumentWorkspaceTone(tone)],
|
|
242
|
+
inlineMeta: () => 'mt-1 wrap-break-word font-mono text-[0.68rem] text-slate-500',
|
|
243
|
+
loadingMessage: () => 'mt-4 text-sm text-slate-500',
|
|
244
|
+
nodeBadge: ({ label, tone }) =>
|
|
245
|
+
resolveDocumentWorkspaceNodeBadgeClassName(coerceDocumentWorkspaceTone(tone), label),
|
|
246
|
+
nodeLabel: ({ isActiveSearchMatch, isSearchMatch }) =>
|
|
247
|
+
[
|
|
248
|
+
'flex min-w-0 flex-wrap items-center gap-1.5 rounded-md px-1 py-0.5 text-sm text-slate-700',
|
|
249
|
+
isSearchMatch ? 'bg-amber-50 ring-1 ring-amber-200/70' : '',
|
|
250
|
+
isActiveSearchMatch ? 'bg-amber-100 ring-amber-300/80' : '',
|
|
251
|
+
].filter(Boolean).join(' '),
|
|
252
|
+
nodeLabelText: () => 'min-w-0 truncate font-medium text-slate-900',
|
|
253
|
+
root: () =>
|
|
254
|
+
'h-full min-h-170 overflow-hidden rounded-md border border-slate-950/10 bg-white/72',
|
|
255
|
+
section: () => 'mt-4',
|
|
256
|
+
sectionBody: () => 'mt-2',
|
|
257
|
+
sectionHeading: () => 'text-sm font-semibold text-slate-950',
|
|
258
|
+
sectionHeadingRow: () => 'flex flex-wrap items-center gap-2',
|
|
259
|
+
splitter: () =>
|
|
260
|
+
'group flex w-2 items-stretch justify-center bg-slate-950/4 outline-none transition-colors hover:bg-slate-950/8 focus-visible:bg-slate-950/10',
|
|
261
|
+
splitterHandle: () => 'my-3 w-px rounded-full bg-slate-950/14 group-hover:bg-slate-950/25',
|
|
262
|
+
status: () =>
|
|
263
|
+
'rounded-md border border-slate-950/8 bg-white/65 px-4 py-3 text-sm text-slate-500',
|
|
264
|
+
tableCell: () => 'border-b border-slate-950/8 px-3 py-2 text-slate-800',
|
|
265
|
+
tableHeader: () => 'sticky top-0 bg-white',
|
|
266
|
+
tableHeaderCell: () =>
|
|
267
|
+
'border-b border-slate-950/8 px-3 py-2 font-semibold uppercase tracking-[0.12em] text-slate-500',
|
|
268
|
+
treePane: () => 'h-full overflow-auto px-2 py-2',
|
|
269
|
+
},
|
|
270
|
+
formSurface: {
|
|
271
|
+
actionRow: () => 'flex flex-wrap items-end justify-end gap-2',
|
|
272
|
+
content: () => 'grid gap-4',
|
|
273
|
+
field: () => 'grid min-w-0 gap-1.5',
|
|
274
|
+
group: ({ group }) => resolveInputFormGroupClassName(group),
|
|
275
|
+
groups: () => 'grid gap-4',
|
|
276
|
+
rangeGroup: () => 'grid gap-2 sm:grid-cols-2',
|
|
277
|
+
root: () => 'relative z-30 overflow-visible bg-white/76',
|
|
278
|
+
},
|
|
279
|
+
metricDashboard: {
|
|
280
|
+
root: () => 'bg-white/76',
|
|
281
|
+
},
|
|
282
|
+
navigationShell: {
|
|
283
|
+
brandBadge: () => 'border-teal-700/15 bg-teal-50 text-teal-700',
|
|
284
|
+
brandSubtitle: () => 'text-xs text-slate-500',
|
|
285
|
+
brandTitle: () => 'text-sm font-medium text-slate-950',
|
|
286
|
+
header: ({ design }) => {
|
|
287
|
+
const density = normalizeDesignToken(design?.Density)
|
|
288
|
+
const paddingClassName = density === 'comfortable' ? 'px-4 py-3' : 'px-4 py-2'
|
|
289
|
+
|
|
290
|
+
return [
|
|
291
|
+
'sticky top-0 z-40 border-b border-slate-950/8 bg-white/86',
|
|
292
|
+
paddingClassName,
|
|
293
|
+
'shadow-[0_12px_30px_rgba(15,23,42,0.06)] backdrop-blur-xl',
|
|
294
|
+
].join(' ')
|
|
295
|
+
},
|
|
296
|
+
headerContent: ({ design }) => [
|
|
297
|
+
'mx-auto flex',
|
|
298
|
+
resolveNavigationShellHeaderMaxWidthClassName(design),
|
|
299
|
+
'flex-wrap items-center justify-between gap-3',
|
|
300
|
+
].join(' '),
|
|
301
|
+
headerNavigation: () => 'flex flex-wrap items-center gap-1',
|
|
302
|
+
navigationItem: () => 'text-slate-700',
|
|
303
|
+
root: () => 'min-h-screen bg-background',
|
|
304
|
+
slotRoot: ({ slot }) => resolveNavigationShellSlotRootClassName(slot),
|
|
305
|
+
},
|
|
306
|
+
routedSurface: {
|
|
307
|
+
content: ({ design }) => resolveRoutedSurfaceContentClassName(design),
|
|
308
|
+
root: () =>
|
|
309
|
+
'flex min-h-[calc(100vh-4rem)] flex-col bg-[radial-gradient(circle_at_top_left,rgba(255,255,255,0.92),transparent_28%),linear-gradient(180deg,#f7f5f0_0%,#f6f8fb_48%,#e8eef6_100%)] px-4 py-5 text-slate-700',
|
|
310
|
+
},
|
|
311
|
+
recordDetail: {
|
|
312
|
+
root: () => 'bg-white/76',
|
|
313
|
+
},
|
|
314
|
+
statusNotice: {
|
|
315
|
+
tone: ({ tone }) => statusNoticeClassByTone[coercePresentationTone(tone)],
|
|
316
|
+
},
|
|
317
|
+
toggle: {
|
|
318
|
+
tone: ({ tone }) =>
|
|
319
|
+
[
|
|
320
|
+
inactiveToggleClassName,
|
|
321
|
+
toggleClassByTone[coercePresentationTone(tone)],
|
|
322
|
+
].join(' '),
|
|
323
|
+
},
|
|
324
|
+
viewSurface: {
|
|
325
|
+
content: () => 'flex min-h-0 flex-1 flex-col gap-4',
|
|
326
|
+
root: () => 'min-h-155 bg-white/76',
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
components: {
|
|
330
|
+
actionButton: {
|
|
331
|
+
size: ({ action }) => resolveActionButtonSize(action),
|
|
332
|
+
variant: ({ action, placement }) => resolveActionButtonVariant(action, placement),
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
diagnostics: {
|
|
336
|
+
navigationShellFrame: {
|
|
337
|
+
ignoredFields: [
|
|
338
|
+
'Role',
|
|
339
|
+
'Variant',
|
|
340
|
+
'Tone',
|
|
341
|
+
'Layout',
|
|
342
|
+
],
|
|
343
|
+
interpretedFields: [
|
|
344
|
+
'Density',
|
|
345
|
+
'Size',
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
navigationShellSlot: {
|
|
349
|
+
ignoredFields: [
|
|
350
|
+
'Role',
|
|
351
|
+
'Variant',
|
|
352
|
+
'Tone',
|
|
353
|
+
'Size',
|
|
354
|
+
],
|
|
355
|
+
interpretedFields: [
|
|
356
|
+
'Density',
|
|
357
|
+
'Layout',
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
routedSurfaceLayout: {
|
|
361
|
+
ignoredFields: [
|
|
362
|
+
'Variant',
|
|
363
|
+
'Tone',
|
|
364
|
+
'Density',
|
|
365
|
+
],
|
|
366
|
+
interpretedFields: [
|
|
367
|
+
'Role',
|
|
368
|
+
'Size',
|
|
369
|
+
'Layout',
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
id: 'tailwind-default',
|
|
374
|
+
target: 'tailwind',
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const presentationToneValues = [
|
|
378
|
+
'accent',
|
|
379
|
+
'danger',
|
|
380
|
+
'info',
|
|
381
|
+
'muted',
|
|
382
|
+
'neutral',
|
|
383
|
+
'success',
|
|
384
|
+
'warning',
|
|
385
|
+
] as const
|
|
386
|
+
|
|
387
|
+
type PresentationTone = (typeof presentationToneValues)[number]
|
|
388
|
+
type PresentationDocumentWorkspaceTone =
|
|
389
|
+
| PresentationTone
|
|
390
|
+
| 'cardinality'
|
|
391
|
+
| 'data-type'
|
|
392
|
+
| 'enum'
|
|
393
|
+
| 'field'
|
|
394
|
+
| 'graph'
|
|
395
|
+
| 'loop'
|
|
396
|
+
| 'nullability'
|
|
397
|
+
| 'presence'
|
|
398
|
+
| 'repeat'
|
|
399
|
+
| 'requirement'
|
|
400
|
+
| 'scalar'
|
|
401
|
+
| 'segment'
|
|
402
|
+
| 'sequence'
|
|
403
|
+
| 'shape'
|
|
404
|
+
| 'structural-type'
|
|
405
|
+
| 'type'
|
|
406
|
+
| 'union'
|
|
407
|
+
|
|
408
|
+
const presentationTones = new Set<string>(presentationToneValues)
|
|
409
|
+
const documentWorkspaceTones = new Set<string>([
|
|
410
|
+
...presentationToneValues,
|
|
411
|
+
'cardinality',
|
|
412
|
+
'data-type',
|
|
413
|
+
'enum',
|
|
414
|
+
'field',
|
|
415
|
+
'graph',
|
|
416
|
+
'loop',
|
|
417
|
+
'nullability',
|
|
418
|
+
'presence',
|
|
419
|
+
'repeat',
|
|
420
|
+
'requirement',
|
|
421
|
+
'scalar',
|
|
422
|
+
'segment',
|
|
423
|
+
'sequence',
|
|
424
|
+
'shape',
|
|
425
|
+
'structural-type',
|
|
426
|
+
'type',
|
|
427
|
+
'union',
|
|
428
|
+
])
|
|
429
|
+
|
|
430
|
+
const badgeClassByTone = {
|
|
431
|
+
accent: 'border-indigo-700/15 bg-indigo-50 text-indigo-700',
|
|
432
|
+
danger: 'border-red-700/15 bg-red-50 text-red-700',
|
|
433
|
+
info: 'border-sky-700/15 bg-sky-50 text-sky-700',
|
|
434
|
+
muted: 'border-slate-950/10 bg-slate-100 text-slate-700',
|
|
435
|
+
neutral: 'border-slate-950/10 bg-slate-100 text-slate-700',
|
|
436
|
+
success: 'border-teal-700/15 bg-teal-50 text-teal-700',
|
|
437
|
+
warning: 'border-amber-700/15 bg-amber-50 text-amber-800',
|
|
438
|
+
} satisfies Readonly<Record<PresentationTone, string>>
|
|
439
|
+
|
|
440
|
+
const statusNoticeClassByTone = {
|
|
441
|
+
accent: 'border-indigo-300/50 bg-indigo-50 text-indigo-800',
|
|
442
|
+
danger: 'border-red-300/60 bg-red-50 text-red-800',
|
|
443
|
+
info: 'border-sky-300/50 bg-sky-50 text-sky-800',
|
|
444
|
+
muted: 'border-slate-950/10 bg-slate-100 text-slate-700',
|
|
445
|
+
neutral: 'border-slate-950/10 bg-slate-100 text-slate-700',
|
|
446
|
+
success: 'border-teal-300/50 bg-teal-50 text-teal-800',
|
|
447
|
+
warning: 'border-amber-300/50 bg-amber-50 text-amber-900',
|
|
448
|
+
} satisfies Readonly<Record<PresentationTone, string>>
|
|
449
|
+
|
|
450
|
+
const toggleClassByTone = {
|
|
451
|
+
accent: 'data-[state=on]:border-indigo-700/15 data-[state=on]:bg-indigo-50 data-[state=on]:text-indigo-700',
|
|
452
|
+
danger: 'data-[state=on]:border-red-700/15 data-[state=on]:bg-red-50 data-[state=on]:text-red-700',
|
|
453
|
+
info: 'data-[state=on]:border-sky-700/15 data-[state=on]:bg-sky-50 data-[state=on]:text-sky-700',
|
|
454
|
+
muted: 'data-[state=on]:border-slate-950/10 data-[state=on]:bg-slate-100 data-[state=on]:text-slate-700',
|
|
455
|
+
neutral: 'data-[state=on]:border-slate-950/10 data-[state=on]:bg-slate-100 data-[state=on]:text-slate-700',
|
|
456
|
+
success: 'data-[state=on]:border-teal-700/15 data-[state=on]:bg-teal-50 data-[state=on]:text-teal-700',
|
|
457
|
+
warning: 'data-[state=on]:border-amber-700/15 data-[state=on]:bg-amber-50 data-[state=on]:text-amber-800',
|
|
458
|
+
} satisfies Readonly<Record<PresentationTone, string>>
|
|
459
|
+
|
|
460
|
+
const inactiveToggleClassName =
|
|
461
|
+
'data-[state=off]:border-slate-950/10 data-[state=off]:bg-white data-[state=off]:text-slate-500'
|
|
462
|
+
|
|
463
|
+
const documentWorkspaceIconClassByTone = {
|
|
464
|
+
accent: 'text-indigo-700',
|
|
465
|
+
cardinality: 'text-violet-700',
|
|
466
|
+
danger: 'text-red-700',
|
|
467
|
+
'data-type': 'text-teal-700',
|
|
468
|
+
enum: 'text-amber-700',
|
|
469
|
+
field: 'text-indigo-700',
|
|
470
|
+
graph: 'text-slate-700',
|
|
471
|
+
info: 'text-sky-700',
|
|
472
|
+
loop: 'text-violet-700',
|
|
473
|
+
muted: 'text-slate-600',
|
|
474
|
+
neutral: 'text-slate-700',
|
|
475
|
+
nullability: 'text-amber-700',
|
|
476
|
+
presence: 'text-sky-700',
|
|
477
|
+
repeat: 'text-violet-700',
|
|
478
|
+
requirement: 'text-amber-700',
|
|
479
|
+
scalar: 'text-teal-700',
|
|
480
|
+
segment: 'text-sky-700',
|
|
481
|
+
sequence: 'text-sky-700',
|
|
482
|
+
shape: 'text-sky-700',
|
|
483
|
+
structural: 'text-sky-700',
|
|
484
|
+
'structural-type': 'text-sky-700',
|
|
485
|
+
success: 'text-teal-700',
|
|
486
|
+
type: 'text-teal-700',
|
|
487
|
+
union: 'text-violet-700',
|
|
488
|
+
warning: 'text-amber-700',
|
|
489
|
+
} satisfies Readonly<Record<PresentationDocumentWorkspaceTone | 'structural', string>>
|
|
490
|
+
|
|
491
|
+
function resolveRoutedSurfaceContentClassName(
|
|
492
|
+
design: DesignIntent | null | undefined,
|
|
493
|
+
): string {
|
|
494
|
+
if (hasAnyDesignToken(design?.Role, fullWidthRoleTokens)) {
|
|
495
|
+
return 'flex min-h-0 w-full max-w-none flex-1 flex-col gap-5'
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (hasAnyDesignToken(design?.Role, workspaceRoleTokens)) {
|
|
499
|
+
return 'mx-auto flex min-h-0 w-full max-w-7xl flex-1 flex-col gap-5'
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (hasAnyDesignToken(design?.Role, wideRoleTokens)) {
|
|
503
|
+
return 'mx-auto flex min-h-0 w-full max-w-420 flex-1 flex-col gap-5'
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (hasAnyDesignToken(design?.Layout, workspaceRoleTokens)) {
|
|
507
|
+
return 'mx-auto flex min-h-0 w-full max-w-7xl flex-1 flex-col gap-5'
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (hasAnyDesignToken(design?.Layout, wideRoleTokens)) {
|
|
511
|
+
return 'mx-auto flex min-h-0 w-full max-w-420 flex-1 flex-col gap-5'
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const size = normalizeDesignToken(design?.Size)
|
|
515
|
+
if (size && workspaceSizeHints.has(size)) {
|
|
516
|
+
return 'mx-auto flex min-h-0 w-full max-w-7xl flex-1 flex-col gap-5'
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (size && wideSizeHints.has(size)) {
|
|
520
|
+
return 'mx-auto flex min-h-0 w-full max-w-420 flex-1 flex-col gap-5'
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return 'mx-auto flex min-h-0 w-full max-w-360 flex-1 flex-col gap-5'
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function resolveActionButtonVariant(
|
|
527
|
+
action: ActionDefinition | null,
|
|
528
|
+
placement: ActionPlacementDefinition,
|
|
529
|
+
): PresentationActionButtonVariant {
|
|
530
|
+
const designVariant = normalizeDesignToken(action?.Design?.Variant)
|
|
531
|
+
const tone = normalizeDesignToken(action?.Design?.Tone)
|
|
532
|
+
const intent = normalizeDesignToken(placement.Intent)
|
|
533
|
+
if (
|
|
534
|
+
tone === 'warning' ||
|
|
535
|
+
tone === 'danger' ||
|
|
536
|
+
intent === 'warning' ||
|
|
537
|
+
intent === 'danger' ||
|
|
538
|
+
intent === 'destructive'
|
|
539
|
+
) {
|
|
540
|
+
return 'destructive'
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (intent === 'primary' || designVariant === 'primary') {
|
|
544
|
+
return 'default'
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (designVariant === 'ghost' && placement.Region.startsWith('row')) {
|
|
548
|
+
return 'ghost'
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return 'outline'
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function resolveActionButtonSize(
|
|
555
|
+
action: ActionDefinition | null,
|
|
556
|
+
): PresentationActionButtonSize {
|
|
557
|
+
switch (normalizeDesignToken(action?.Design?.Size)) {
|
|
558
|
+
case 'xs':
|
|
559
|
+
return 'xs'
|
|
560
|
+
case 'lg':
|
|
561
|
+
return 'lg'
|
|
562
|
+
case 'sm':
|
|
563
|
+
case 'md':
|
|
564
|
+
default:
|
|
565
|
+
return 'sm'
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function coercePresentationTone(value: string | null | undefined): PresentationTone {
|
|
570
|
+
const normalized = normalizeDesignToken(value)
|
|
571
|
+
return normalized && presentationTones.has(normalized)
|
|
572
|
+
? normalized as PresentationTone
|
|
573
|
+
: 'info'
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function coerceDocumentWorkspaceTone(
|
|
577
|
+
value: string | null | undefined,
|
|
578
|
+
): PresentationDocumentWorkspaceTone {
|
|
579
|
+
const normalized = normalizeDesignToken(value)
|
|
580
|
+
return normalized && documentWorkspaceTones.has(normalized)
|
|
581
|
+
? normalized as PresentationDocumentWorkspaceTone
|
|
582
|
+
: 'info'
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function resolveDocumentWorkspaceNodeBadgeClassName(
|
|
586
|
+
tone: PresentationDocumentWorkspaceTone,
|
|
587
|
+
label: string | null | undefined,
|
|
588
|
+
) {
|
|
589
|
+
if (tone === 'requirement') {
|
|
590
|
+
return label?.toUpperCase() === 'M'
|
|
591
|
+
? 'h-4 rounded-md border-amber-700/15 bg-amber-50 px-1.5 text-[0.67rem] text-amber-700'
|
|
592
|
+
: 'h-4 rounded-md border-slate-950/10 bg-slate-100 px-1.5 text-[0.67rem] text-slate-600'
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const toneClassName = badgeClassByTone[coerceDocumentWorkspaceBadgeTone(tone)]
|
|
596
|
+
const maxWidthClassName = tone === 'type' ? 'max-w-80 truncate' : ''
|
|
597
|
+
return ['h-4 rounded-md px-1.5 text-[0.67rem]', maxWidthClassName, toneClassName]
|
|
598
|
+
.filter(Boolean)
|
|
599
|
+
.join(' ')
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function coerceDocumentWorkspaceBadgeTone(
|
|
603
|
+
tone: PresentationDocumentWorkspaceTone,
|
|
604
|
+
): PresentationTone {
|
|
605
|
+
switch (tone) {
|
|
606
|
+
case 'cardinality':
|
|
607
|
+
case 'repeat':
|
|
608
|
+
case 'union':
|
|
609
|
+
return 'accent'
|
|
610
|
+
case 'data-type':
|
|
611
|
+
case 'scalar':
|
|
612
|
+
case 'success':
|
|
613
|
+
case 'type':
|
|
614
|
+
return 'success'
|
|
615
|
+
case 'enum':
|
|
616
|
+
case 'nullability':
|
|
617
|
+
case 'requirement':
|
|
618
|
+
case 'warning':
|
|
619
|
+
return 'warning'
|
|
620
|
+
case 'field':
|
|
621
|
+
case 'shape':
|
|
622
|
+
case 'info':
|
|
623
|
+
case 'presence':
|
|
624
|
+
case 'sequence':
|
|
625
|
+
return 'info'
|
|
626
|
+
case 'danger':
|
|
627
|
+
return 'danger'
|
|
628
|
+
case 'muted':
|
|
629
|
+
case 'neutral':
|
|
630
|
+
case 'graph':
|
|
631
|
+
case 'loop':
|
|
632
|
+
case 'segment':
|
|
633
|
+
case 'structural-type':
|
|
634
|
+
return 'neutral'
|
|
635
|
+
case 'accent':
|
|
636
|
+
return 'accent'
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function resolveNavigationShellHeaderMaxWidthClassName(
|
|
641
|
+
design: DesignIntent | null | undefined,
|
|
642
|
+
) {
|
|
643
|
+
switch (normalizeDesignToken(design?.Size)) {
|
|
644
|
+
case '2xl':
|
|
645
|
+
case 'full':
|
|
646
|
+
case 'max':
|
|
647
|
+
case 'screen':
|
|
648
|
+
case 'xl':
|
|
649
|
+
return 'max-w-7xl'
|
|
650
|
+
case 'lg':
|
|
651
|
+
case 'wide':
|
|
652
|
+
default:
|
|
653
|
+
return 'max-w-420'
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function resolveNavigationShellSlotRootClassName(
|
|
658
|
+
slot: NavigationShellSlotDefinition,
|
|
659
|
+
): string {
|
|
660
|
+
const density = normalizeDesignToken(slot.Design?.Density)
|
|
661
|
+
const gapClassName = density === 'comfortable' ? 'gap-2' : 'gap-1'
|
|
662
|
+
|
|
663
|
+
if (isNavigationShellSlotKind(slot, navigationShellSlotKinds.brand, 'Brand')) {
|
|
664
|
+
return 'flex items-center gap-2'
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (
|
|
668
|
+
isNavigationShellSlotKind(
|
|
669
|
+
slot,
|
|
670
|
+
navigationShellSlotKinds.primaryNavigation,
|
|
671
|
+
'PrimaryNavigation',
|
|
672
|
+
)
|
|
673
|
+
) {
|
|
674
|
+
return `flex flex-wrap items-center ${gapClassName}`
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (
|
|
678
|
+
isNavigationShellSlotKind(
|
|
679
|
+
slot,
|
|
680
|
+
navigationShellSlotKinds.utilityActions,
|
|
681
|
+
'UtilityActions',
|
|
682
|
+
)
|
|
683
|
+
) {
|
|
684
|
+
return 'flex items-center gap-2'
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (
|
|
688
|
+
isNavigationShellSlotKind(
|
|
689
|
+
slot,
|
|
690
|
+
navigationShellSlotKinds.systemNotices,
|
|
691
|
+
'SystemNotices',
|
|
692
|
+
) ||
|
|
693
|
+
isNavigationShellSlotKind(
|
|
694
|
+
slot,
|
|
695
|
+
navigationShellSlotKinds.routedContent,
|
|
696
|
+
'RoutedContent',
|
|
697
|
+
)
|
|
698
|
+
) {
|
|
699
|
+
return 'contents'
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
switch (normalizeDesignToken(slot.Design?.Layout ?? slot.Placement)) {
|
|
703
|
+
case 'topcenter':
|
|
704
|
+
case 'top-center':
|
|
705
|
+
return `flex flex-wrap items-center ${gapClassName}`
|
|
706
|
+
case 'topright':
|
|
707
|
+
case 'top-right':
|
|
708
|
+
return 'flex items-center gap-2'
|
|
709
|
+
case 'belownavigation':
|
|
710
|
+
case 'below-navigation':
|
|
711
|
+
case 'main':
|
|
712
|
+
return 'contents'
|
|
713
|
+
default:
|
|
714
|
+
return `flex flex-wrap items-center ${gapClassName}`
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
function resolveInputFormGroupClassName(group: InputFormGroupDefinition) {
|
|
719
|
+
const kind = String(group.Kind).toLocaleLowerCase()
|
|
720
|
+
if (group.Id === 'identity' || kind === String(inputFormGroupKinds.identity).toLocaleLowerCase()) {
|
|
721
|
+
return 'grid gap-3 lg:grid-cols-[1fr_1fr_minmax(18rem,1.25fr)]'
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (group.Id === 'lifecycle' || kind === String(inputFormGroupKinds.lifecycle).toLocaleLowerCase()) {
|
|
725
|
+
return 'grid gap-3'
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (group.Display.Orientation === 'horizontal') {
|
|
729
|
+
return 'flex flex-wrap items-end gap-3'
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return 'grid gap-3 lg:grid-cols-2'
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function isNavigationShellSlotKind(
|
|
736
|
+
slot: NavigationShellSlotDefinition,
|
|
737
|
+
numericKind: unknown,
|
|
738
|
+
label: string,
|
|
739
|
+
) {
|
|
740
|
+
const normalizedKind = String(slot.Kind).replace(/[-_\s]/g, '').toLowerCase()
|
|
741
|
+
const normalizedLabel = label.replace(/[-_\s]/g, '').toLowerCase()
|
|
742
|
+
|
|
743
|
+
return slot.Kind === numericKind || normalizedKind === normalizedLabel
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function hasAnyDesignToken(
|
|
747
|
+
value: string | null | undefined,
|
|
748
|
+
tokens: ReadonlySet<string>,
|
|
749
|
+
): boolean {
|
|
750
|
+
return getDesignTokenCandidates(value).some((token) => tokens.has(token))
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function getDesignTokenCandidates(value: string | null | undefined) {
|
|
754
|
+
const normalized = normalizeDesignToken(value)
|
|
755
|
+
if (!normalized) {
|
|
756
|
+
return []
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const parts = normalized
|
|
760
|
+
.split(/[^a-z0-9]+/u)
|
|
761
|
+
.filter(Boolean)
|
|
762
|
+
return [
|
|
763
|
+
normalized,
|
|
764
|
+
...parts,
|
|
765
|
+
...parts.flatMap((part, index) =>
|
|
766
|
+
parts.slice(index + 1).map((next) => `${part}-${next}`),
|
|
767
|
+
),
|
|
768
|
+
]
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function normalizeDesignToken(value: string | null | undefined) {
|
|
772
|
+
return value?.trim().toLowerCase() || null
|
|
773
|
+
}
|