@xemahq/ui-kernel 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/errors/http-error-status.d.ts +17 -0
- package/dist/errors/http-error-status.d.ts.map +1 -0
- package/dist/errors/http-error-status.js +59 -0
- package/dist/errors/http-error-status.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/biome-host/errors.d.ts.map +1 -1
- package/dist/lib/biome-host/errors.js +1 -19
- package/dist/lib/biome-host/errors.js.map +1 -1
- package/dist/offline/index.d.ts.map +1 -1
- package/dist/offline/index.js.map +1 -1
- package/dist/offline/online-controller.d.ts.map +1 -1
- package/dist/offline/online-controller.js +6 -1
- package/dist/offline/online-controller.js.map +1 -1
- package/dist/offline/outbox.d.ts.map +1 -1
- package/dist/offline/outbox.js +2 -24
- package/dist/offline/outbox.js.map +1 -1
- package/package.json +1 -2
- package/src/index.ts +0 -17
- package/src/lib/biome-host/agent-validation.ts +0 -239
- package/src/lib/biome-host/biome-builders.ts +0 -112
- package/src/lib/biome-host/biome-mode.ts +0 -6
- package/src/lib/biome-host/biome-navigation.ts +0 -37
- package/src/lib/biome-host/biome-registry.ts +0 -299
- package/src/lib/biome-host/biome-scope-hooks.ts +0 -41
- package/src/lib/biome-host/biome-scope.tsx +0 -52
- package/src/lib/biome-host/biome-scoped-query.ts +0 -134
- package/src/lib/biome-host/create-biome-orval-config.ts +0 -82
- package/src/lib/biome-host/define-web-biome.spec.ts +0 -221
- package/src/lib/biome-host/define-web-biome.ts +0 -222
- package/src/lib/biome-host/errors.ts +0 -220
- package/src/lib/biome-host/frontend-biome.ts +0 -256
- package/src/lib/biome-host/host-bridge.ts +0 -281
- package/src/lib/biome-host/host-sources.ts +0 -54
- package/src/lib/biome-host/i18n-hooks.ts +0 -51
- package/src/lib/biome-host/i18n-port.test.ts +0 -50
- package/src/lib/biome-host/i18n-port.ts +0 -96
- package/src/lib/biome-host/index.ts +0 -35
- package/src/lib/biome-host/realtime-hooks.ts +0 -75
- package/src/lib/biome-host/realtime-port.ts +0 -115
- package/src/lib/biome-host/session-contributions.ts +0 -296
- package/src/lib/biome-host/use-mutation-with-error-toast.ts +0 -90
- package/src/lib/biome-host/use-page-state.ts +0 -248
- package/src/lib/capabilities/capability-context.ts +0 -25
- package/src/lib/capabilities/capability-provider.tsx +0 -73
- package/src/lib/capabilities/index.ts +0 -17
- package/src/lib/capabilities/types.ts +0 -69
- package/src/lib/capabilities/use-capability.ts +0 -79
- package/src/lib/contribution-registry/contribution-registry.spec.ts +0 -141
- package/src/lib/contribution-registry/contribution-registry.ts +0 -204
- package/src/lib/contribution-registry/index.ts +0 -9
- package/src/lib/contribution-registry/renderable-registry.ts +0 -142
- package/src/lib/system-bus/capability-invoke.ts +0 -92
- package/src/lib/system-bus/deeplink.ts +0 -210
- package/src/lib/system-bus/enums.ts +0 -86
- package/src/lib/system-bus/host-ports.ts +0 -93
- package/src/lib/system-bus/index.ts +0 -16
- package/src/lib/system-bus/intent-registry.ts +0 -109
- package/src/lib/system-bus/intents.ts +0 -113
- package/src/lib/system-bus/palette.ts +0 -78
- package/src/lib/system-bus/system-bus-builder.ts +0 -159
- package/src/lib/system-bus/system-bus.ts +0 -37
- package/src/lib/system-bus/windows.ts +0 -51
- package/src/offline/id.ts +0 -16
- package/src/offline/index.ts +0 -54
- package/src/offline/mutation.ts +0 -75
- package/src/offline/offline-status-badge.tsx +0 -51
- package/src/offline/online-controller.ts +0 -105
- package/src/offline/outbox.test.ts +0 -172
- package/src/offline/outbox.ts +0 -348
- package/src/offline/react-hooks.ts +0 -40
- package/src/offline/react.tsx +0 -32
- package/src/offline/storage.ts +0 -112
- package/src/offline/types.ts +0 -77
- package/src/org-db/components/DbResultTable.tsx +0 -176
- package/src/org-db/index.ts +0 -1
- package/src/pdf/index.ts +0 -11
- package/src/registry/index.ts +0 -9
- package/src/registry/lib/agent-validation-host.ts +0 -36
- package/src/registry/lib/biome-slot.tsx +0 -50
- package/src/registry/lib/biomes-enabled-context.ts +0 -20
- package/src/registry/lib/extension-points.ts +0 -134
- package/src/registry/lib/primitives/SessionEventCard.tsx +0 -164
- package/src/registry/lib/primitives/SessionEventTimeline.tsx +0 -95
- package/src/registry/lib/primitives/SessionMutationBar.tsx +0 -76
- package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +0 -165
- package/src/registry/lib/primitives/index.ts +0 -18
- package/src/registry/lib/session-context-builder.ts +0 -84
- package/src/registry/lib/session-context-provider.tsx +0 -33
- package/src/registry/lib/session-context.ts +0 -21
- package/src/registry/lib/session-selectors.ts +0 -272
- package/src/session/comments/CommentRail.tsx +0 -164
- package/src/session/index.ts +0 -3
- package/src/session/lib/cn.ts +0 -11
- package/src/session/shell/SessionWorkspaceShell.tsx +0 -147
- package/src/session-kit/approvals/ApprovalButton.tsx +0 -89
- package/src/session-kit/approvals/ApprovalCard.tsx +0 -341
- package/src/session-kit/approvals/ApprovalsCenter.tsx +0 -336
- package/src/session-kit/approvals/CapabilityApprovalStickyBar.tsx +0 -118
- package/src/session-kit/approvals/Obligation.tsx +0 -111
- package/src/session-kit/approvals/ScopedBody.tsx +0 -392
- package/src/session-kit/approvals/approval-icons.ts +0 -31
- package/src/session-kit/approvals/approval-model.ts +0 -204
- package/src/session-kit/approvals/index.ts +0 -22
- package/src/session-kit/approvals/obligation-display.ts +0 -100
- package/src/session-kit/approvals/risk-accent.ts +0 -47
- package/src/session-kit/approvals/scope-icons.ts +0 -19
- package/src/session-kit/combobox/Combobox.tsx +0 -358
- package/src/session-kit/combobox/use-click-outside.ts +0 -21
- package/src/session-kit/display/ContextHeader.tsx +0 -148
- package/src/session-kit/display/FileDiffCard.tsx +0 -140
- package/src/session-kit/display/MD.tsx +0 -162
- package/src/session-kit/display/MessageTurn.tsx +0 -157
- package/src/session-kit/display/ThinkingPanel.tsx +0 -81
- package/src/session-kit/display/TodoChecklist.tsx +0 -120
- package/src/session-kit/display/TokenMeter.tsx +0 -89
- package/src/session-kit/display/ToolStrip.tsx +0 -278
- package/src/session-kit/display/TypingDots.tsx +0 -24
- package/src/session-kit/index.ts +0 -44
- package/src/session-kit/lib/enums.ts +0 -66
- package/src/session-kit/lib/portal-accent.ts +0 -30
- package/src/session-kit/lib/status-dot.ts +0 -68
- package/src/session-kit/primitives/Avatar.tsx +0 -44
- package/src/session-kit/primitives/PortalGlyph.tsx +0 -51
- package/src/session-kit/primitives/RiskPill.tsx +0 -95
- package/src/session-kit/primitives/ScopeDot.tsx +0 -47
- package/src/session-kit/primitives/Segmented.tsx +0 -71
- package/src/ui/branding/app-branding-context.ts +0 -20
- package/src/ui/branding/app-branding-provider.tsx +0 -123
- package/src/ui/branding/sanitize.ts +0 -89
- package/src/ui/breakpoints.ts +0 -14
- package/src/ui/capture/document-preview.tsx +0 -166
- package/src/ui/capture/field-spec-to-zod.test.ts +0 -81
- package/src/ui/capture/field-spec-to-zod.ts +0 -174
- package/src/ui/capture/field-spec-validate.ts +0 -236
- package/src/ui/capture/field-spec.test.ts +0 -49
- package/src/ui/capture/field-spec.ts +0 -274
- package/src/ui/capture/index.ts +0 -51
- package/src/ui/capture/schema-field-input.tsx +0 -620
- package/src/ui/capture/schema-form.tsx +0 -149
- package/src/ui/capture/submit-values.test.ts +0 -70
- package/src/ui/capture/submit-values.ts +0 -63
- package/src/ui/capture/use-prefill.ts +0 -186
- package/src/ui/capture/use-schema-validation.ts +0 -145
- package/src/ui/capture/use-wizard.ts +0 -180
- package/src/ui/capture/value-format.ts +0 -32
- package/src/ui/capture/wizard.tsx +0 -105
- package/src/ui/charts/bar-chart.tsx +0 -139
- package/src/ui/charts/chart-frame.tsx +0 -125
- package/src/ui/charts/chart-types.ts +0 -52
- package/src/ui/charts/chart-utils.ts +0 -190
- package/src/ui/charts/charts.test.tsx +0 -204
- package/src/ui/charts/donut-chart.tsx +0 -129
- package/src/ui/charts/index.ts +0 -27
- package/src/ui/charts/line-chart.tsx +0 -202
- package/src/ui/charts/sparkline.tsx +0 -109
- package/src/ui/chrome/AsyncBoundary.tsx +0 -74
- package/src/ui/chrome/EmptyState.tsx +0 -257
- package/src/ui/chrome/ErrorCard.tsx +0 -63
- package/src/ui/chrome/LoadingState.tsx +0 -61
- package/src/ui/chrome/PageHeader.tsx +0 -137
- package/src/ui/chrome/RecordCardList.tsx +0 -98
- package/src/ui/chrome/StateCard.tsx +0 -150
- package/src/ui/chrome/confirm-delete-dialog.tsx +0 -59
- package/src/ui/chrome/page-shell.spec.tsx +0 -117
- package/src/ui/chrome/page-shell.tsx +0 -221
- package/src/ui/chrome/scope-badge.tsx +0 -40
- package/src/ui/chrome/status-badge.tsx +0 -79
- package/src/ui/cn.ts +0 -32
- package/src/ui/design-tokens.ts +0 -372
- package/src/ui/hooks/use-debounced-value.ts +0 -16
- package/src/ui/hooks/use-is-mobile.ts +0 -28
- package/src/ui/index.ts +0 -110
- package/src/ui/pdf/pdf-preview.tsx +0 -122
- package/src/ui/primitives/alert-dialog.tsx +0 -104
- package/src/ui/primitives/async-combobox.tsx +0 -182
- package/src/ui/primitives/badge-variants.ts +0 -21
- package/src/ui/primitives/badge.tsx +0 -25
- package/src/ui/primitives/button-variants.ts +0 -31
- package/src/ui/primitives/button.tsx +0 -29
- package/src/ui/primitives/card.tsx +0 -43
- package/src/ui/primitives/checkbox.tsx +0 -26
- package/src/ui/primitives/collapsible.tsx +0 -9
- package/src/ui/primitives/dialog.tsx +0 -103
- package/src/ui/primitives/dropdown-menu.tsx +0 -179
- package/src/ui/primitives/form-stepper.tsx +0 -94
- package/src/ui/primitives/form-stepper.types.ts +0 -15
- package/src/ui/primitives/input.tsx +0 -22
- package/src/ui/primitives/label.tsx +0 -17
- package/src/ui/primitives/overflow-tabs.tsx +0 -331
- package/src/ui/primitives/popover.tsx +0 -33
- package/src/ui/primitives/preview-device-frame.tsx +0 -213
- package/src/ui/primitives/radio-group.tsx +0 -36
- package/src/ui/primitives/resizable.tsx +0 -67
- package/src/ui/primitives/scroll-area.tsx +0 -38
- package/src/ui/primitives/select.tsx +0 -143
- package/src/ui/primitives/separator.tsx +0 -20
- package/src/ui/primitives/sheet.tsx +0 -107
- package/src/ui/primitives/skeleton.tsx +0 -99
- package/src/ui/primitives/switch.tsx +0 -27
- package/src/ui/primitives/table.tsx +0 -72
- package/src/ui/primitives/tabs.tsx +0 -53
- package/src/ui/primitives/tag-multi-select.tsx +0 -261
- package/src/ui/primitives/textarea.tsx +0 -21
- package/src/ui/primitives/tooltip.tsx +0 -30
- package/src/ui/primitives/url-preview-chrome.tsx +0 -103
- package/src/vista/GenericCatalogueSurface.tsx +0 -179
- package/src/vista/SurfaceFallbackCard.tsx +0 -109
- package/src/vista/VistaPanel.tsx +0 -163
- package/src/vista/form-payload.spec.ts +0 -139
- package/src/vista/html/CustomUiFrame.spec.tsx +0 -127
- package/src/vista/html/CustomUiFrame.tsx +0 -206
- package/src/vista/html/custom-ui-frame-bridge.spec.ts +0 -191
- package/src/vista/html/custom-ui-frame-bridge.ts +0 -98
- package/src/vista/html/custom-ui-frame-contract.ts +0 -88
- package/src/vista/html/custom-ui-intents.spec.ts +0 -135
- package/src/vista/html/custom-ui-intents.ts +0 -155
- package/src/vista/html/custom-ui-srcdoc.spec.ts +0 -151
- package/src/vista/html/custom-ui-srcdoc.ts +0 -193
- package/src/vista/html/index.ts +0 -13
- package/src/vista/index.ts +0 -52
- package/src/vista/surface-catalogue.spec.ts +0 -140
- package/src/vista/surface-catalogue.ts +0 -90
- package/src/vista/surface-icons.ts +0 -57
- package/src/vista/surface-registry.ts +0 -56
- package/src/vista/surfaces/ChartSurface.tsx +0 -34
- package/src/vista/surfaces/FilesSurface.tsx +0 -202
- package/src/vista/surfaces/FormSurface.tsx +0 -380
- package/src/vista/surfaces/HtmlSurface.tsx +0 -43
- package/src/vista/surfaces/TableSurface.tsx +0 -100
- package/src/vista/surfaces/UrlSurface.tsx +0 -40
- package/src/vista/surfaces/blob-surfaces.tsx +0 -139
- package/src/vista/surfaces/elicitation-transport.spec.ts +0 -369
- package/src/vista/surfaces/elicitation-transport.ts +0 -367
- package/src/vista/surfaces/file-surface-utils.ts +0 -69
- package/src/vista/surfaces/index.ts +0 -24
- package/src/vista/surfaces/register-surfaces.tsx +0 -139
- package/src/vista/surfaces/text-surfaces.tsx +0 -132
- package/src/vista/use-vista-tabs.ts +0 -196
- package/src/vista/vista-code-renderer-context.ts +0 -16
- package/src/vista/vista-code-renderer.tsx +0 -35
- package/src/vista/vista-file-context.ts +0 -14
- package/src/vista/vista-file-source.tsx +0 -141
- package/src/vista/vista-form-context.ts +0 -20
- package/src/vista/vista-form-host.tsx +0 -48
- package/src/vista/vista-model.ts +0 -137
- package/src/vista/vista-open-context.tsx +0 -27
- package/src/vista/vista-open-state.ts +0 -11
- package/src/vista/vista-payloads.ts +0 -635
- package/src/vista/vista-tabs-manifest.ts +0 -138
- package/src/vista/vista-tools.ts +0 -232
package/src/ui/design-tokens.ts
DELETED
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Design Token System — Single source of truth for semantic styling.
|
|
3
|
-
*
|
|
4
|
-
* All components import from here. To reskin the app, edit this file + CSS variables.
|
|
5
|
-
* Uses Tailwind classes mapped to semantic states, priorities, and severities.
|
|
6
|
-
*
|
|
7
|
-
* COLOR PHILOSOPHY: Bold, vibrant primary colors (Microsoft-logo style).
|
|
8
|
-
* Red (#F25022), Green (#7FBA00), Blue (#00A4EF), Yellow (#FFB900) — strong, not pastel.
|
|
9
|
-
*
|
|
10
|
-
* DARK MODE: Uses opacity-based colors (e.g. bg-success/15) that adapt naturally.
|
|
11
|
-
* Text colors use dark: variants where needed for readable contrast.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
// ── Status Styles ──────────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
export interface StatusStyle {
|
|
17
|
-
badge: string;
|
|
18
|
-
dot: string;
|
|
19
|
-
text: string;
|
|
20
|
-
bg: string;
|
|
21
|
-
border: string;
|
|
22
|
-
icon: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Reusable style fragments — keep the map below a flat enum-like lookup
|
|
26
|
-
// rather than scattering bg-success/15 strings, so adding a new closed-set
|
|
27
|
-
// status is a one-line entry.
|
|
28
|
-
const SUCCESS_STYLE: StatusStyle = {
|
|
29
|
-
badge: 'bg-success/15 text-success dark:text-success border-success/30',
|
|
30
|
-
dot: 'bg-success',
|
|
31
|
-
text: 'text-success dark:text-success',
|
|
32
|
-
bg: 'bg-success/10',
|
|
33
|
-
border: 'border-success/30',
|
|
34
|
-
icon: 'text-success',
|
|
35
|
-
};
|
|
36
|
-
const WARNING_STYLE: StatusStyle = {
|
|
37
|
-
badge: 'bg-warning/15 text-warning dark:text-warning border-warning/30',
|
|
38
|
-
dot: 'bg-warning',
|
|
39
|
-
text: 'text-warning dark:text-warning',
|
|
40
|
-
bg: 'bg-warning/10',
|
|
41
|
-
border: 'border-warning/30',
|
|
42
|
-
icon: 'text-warning',
|
|
43
|
-
};
|
|
44
|
-
const INFO_STYLE: StatusStyle = {
|
|
45
|
-
badge: 'bg-info/15 text-info dark:text-info border-info/30',
|
|
46
|
-
dot: 'bg-info',
|
|
47
|
-
text: 'text-info dark:text-info',
|
|
48
|
-
bg: 'bg-info/10',
|
|
49
|
-
border: 'border-info/30',
|
|
50
|
-
icon: 'text-info',
|
|
51
|
-
};
|
|
52
|
-
const PRIMARY_STYLE: StatusStyle = {
|
|
53
|
-
badge: 'bg-primary/15 text-primary dark:text-primary border-primary/30',
|
|
54
|
-
dot: 'bg-primary',
|
|
55
|
-
text: 'text-primary dark:text-primary',
|
|
56
|
-
bg: 'bg-primary/10',
|
|
57
|
-
border: 'border-primary/30',
|
|
58
|
-
icon: 'text-primary',
|
|
59
|
-
};
|
|
60
|
-
const DESTRUCTIVE_STYLE: StatusStyle = {
|
|
61
|
-
badge: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30',
|
|
62
|
-
dot: 'bg-destructive',
|
|
63
|
-
text: 'text-destructive dark:text-destructive',
|
|
64
|
-
bg: 'bg-destructive/10',
|
|
65
|
-
border: 'border-destructive/30',
|
|
66
|
-
icon: 'text-destructive',
|
|
67
|
-
};
|
|
68
|
-
const NEUTRAL_STYLE: StatusStyle = {
|
|
69
|
-
badge: 'bg-paper-elev text-ink-3 border-border',
|
|
70
|
-
dot: 'bg-muted-foreground/40',
|
|
71
|
-
text: 'text-ink-3',
|
|
72
|
-
bg: 'bg-muted/30',
|
|
73
|
-
border: 'border-border',
|
|
74
|
-
icon: 'text-ink-3',
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// ── Tone Styles ────────────────────────────────────────────────────
|
|
78
|
-
// Generic tonal palette used by `<ScopeBadge>` and any surface that
|
|
79
|
-
// needs a closed-set chip without a status semantic. Status badges
|
|
80
|
-
// continue to read from STATUS_STYLES (richer shape: badge + dot + …).
|
|
81
|
-
|
|
82
|
-
export type Tone = 'neutral' | 'primary' | 'info' | 'success' | 'warning' | 'danger' | 'accent';
|
|
83
|
-
|
|
84
|
-
export const TONE_STYLES: Record<Tone, string> = {
|
|
85
|
-
neutral: 'bg-paper-elev text-ink-3 border-border',
|
|
86
|
-
primary: 'bg-primary/10 text-primary border-primary/20',
|
|
87
|
-
info: 'bg-info/15 text-info dark:text-info border-info/20',
|
|
88
|
-
success: 'bg-success/15 text-success dark:text-success border-success/20',
|
|
89
|
-
warning: 'bg-warning/15 text-warning dark:text-warning border-warning/20',
|
|
90
|
-
danger: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/20',
|
|
91
|
-
accent: 'bg-amber-500/15 text-amber-700 dark:text-amber-400 border-amber-500/20',
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
export const STATUS_STYLES: Record<string, StatusStyle> = {
|
|
95
|
-
// ── Workflow run states (WorkflowRunStatus enum) ────────────────────
|
|
96
|
-
pending: INFO_STYLE,
|
|
97
|
-
running: WARNING_STYLE,
|
|
98
|
-
waiting_on_approval: WARNING_STYLE,
|
|
99
|
-
waiting_on_human: WARNING_STYLE,
|
|
100
|
-
succeeded: SUCCESS_STYLE,
|
|
101
|
-
failed: DESTRUCTIVE_STYLE,
|
|
102
|
-
cancelled: NEUTRAL_STYLE,
|
|
103
|
-
aborted_for_migration: NEUTRAL_STYLE,
|
|
104
|
-
|
|
105
|
-
// Legacy / generic synonyms — kept so older surfaces (project status,
|
|
106
|
-
// backlog "done") keep rendering correctly. Use the canonical run
|
|
107
|
-
// state above when emitting from new code.
|
|
108
|
-
completed: SUCCESS_STYLE,
|
|
109
|
-
stopped: WARNING_STYLE,
|
|
110
|
-
undone: PRIMARY_STYLE,
|
|
111
|
-
skipped: NEUTRAL_STYLE,
|
|
112
|
-
|
|
113
|
-
// ── Interactive session states (SessionStatus) ──────────────────────
|
|
114
|
-
creating: PRIMARY_STYLE,
|
|
115
|
-
provisioning: PRIMARY_STYLE,
|
|
116
|
-
active: SUCCESS_STYLE,
|
|
117
|
-
paused: WARNING_STYLE,
|
|
118
|
-
recovering: WARNING_STYLE,
|
|
119
|
-
completing: PRIMARY_STYLE,
|
|
120
|
-
archived: NEUTRAL_STYLE,
|
|
121
|
-
|
|
122
|
-
// ── Backlog / work ──────────────────────────────────────────────────
|
|
123
|
-
todo: NEUTRAL_STYLE,
|
|
124
|
-
in_progress: INFO_STYLE,
|
|
125
|
-
in_review: WARNING_STYLE,
|
|
126
|
-
done: SUCCESS_STYLE,
|
|
127
|
-
blocked: DESTRUCTIVE_STYLE,
|
|
128
|
-
|
|
129
|
-
// ── Design System Builder ───────────────────────────────────────────
|
|
130
|
-
open: INFO_STYLE,
|
|
131
|
-
exploring: WARNING_STYLE,
|
|
132
|
-
proposed: PRIMARY_STYLE,
|
|
133
|
-
accepted: SUCCESS_STYLE,
|
|
134
|
-
rejected: DESTRUCTIVE_STYLE,
|
|
135
|
-
merged: NEUTRAL_STYLE,
|
|
136
|
-
|
|
137
|
-
// ── SCM ─────────────────────────────────────────────────────────────
|
|
138
|
-
draft: NEUTRAL_STYLE,
|
|
139
|
-
|
|
140
|
-
// ── Gate ────────────────────────────────────────────────────────────
|
|
141
|
-
approved: SUCCESS_STYLE,
|
|
142
|
-
manual_review: WARNING_STYLE,
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Style for an unrecognised status. Same value `STATUS_STYLES.pending` carries —
|
|
147
|
-
* referenced as the fragment rather than re-read out of the open `Record`, so
|
|
148
|
-
* the fallback is structurally guaranteed instead of being a second lookup that
|
|
149
|
-
* can itself miss (e.g. if the `pending` key were ever renamed).
|
|
150
|
-
*/
|
|
151
|
-
const DEFAULT_STATUS_STYLE: StatusStyle = INFO_STYLE;
|
|
152
|
-
|
|
153
|
-
export function getStatusStyle(status: string): StatusStyle {
|
|
154
|
-
return STATUS_STYLES[status] ?? DEFAULT_STATUS_STYLE;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// ── Priority Styles ────────────────────────────────────────────────
|
|
158
|
-
|
|
159
|
-
export interface PriorityStyle {
|
|
160
|
-
badge: string;
|
|
161
|
-
text: string;
|
|
162
|
-
bg: string;
|
|
163
|
-
border: string;
|
|
164
|
-
label: string;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Lowest priority — also the style for an unrecognised priority. Named so the
|
|
168
|
-
// map entry and `getPriorityStyle`'s fallback are the same proven value rather
|
|
169
|
-
// than a second `Record` lookup that can itself miss.
|
|
170
|
-
const PRIORITY_LOW_STYLE: PriorityStyle = {
|
|
171
|
-
badge: 'bg-paper-elev text-ink-3 border-border',
|
|
172
|
-
text: 'text-ink-3',
|
|
173
|
-
bg: 'bg-muted/30',
|
|
174
|
-
border: 'border-border',
|
|
175
|
-
label: 'Low',
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
export const PRIORITY_STYLES: Record<string, PriorityStyle> = {
|
|
179
|
-
p0: {
|
|
180
|
-
badge: 'bg-destructive text-white border-destructive',
|
|
181
|
-
text: 'text-destructive dark:text-destructive',
|
|
182
|
-
bg: 'bg-destructive/10',
|
|
183
|
-
border: 'border-destructive/30',
|
|
184
|
-
label: 'Critical',
|
|
185
|
-
},
|
|
186
|
-
p1: {
|
|
187
|
-
badge: 'bg-warning text-white border-warning',
|
|
188
|
-
text: 'text-warning dark:text-warning',
|
|
189
|
-
bg: 'bg-warning/10',
|
|
190
|
-
border: 'border-warning/30',
|
|
191
|
-
label: 'High',
|
|
192
|
-
},
|
|
193
|
-
p2: {
|
|
194
|
-
badge: 'bg-warning text-white border-warning',
|
|
195
|
-
text: 'text-warning dark:text-warning',
|
|
196
|
-
bg: 'bg-warning/10',
|
|
197
|
-
border: 'border-warning/30',
|
|
198
|
-
label: 'Medium',
|
|
199
|
-
},
|
|
200
|
-
p3: PRIORITY_LOW_STYLE,
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
export function getPriorityStyle(priority: string): PriorityStyle {
|
|
204
|
-
return PRIORITY_STYLES[priority] ?? PRIORITY_LOW_STYLE;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// ── Severity Styles ────────────────────────────────────────────────
|
|
208
|
-
|
|
209
|
-
export interface SeverityStyle {
|
|
210
|
-
badge: string;
|
|
211
|
-
text: string;
|
|
212
|
-
bg: string;
|
|
213
|
-
border: string;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export const SEVERITY_STYLES: Record<string, SeverityStyle> = {
|
|
217
|
-
critical: {
|
|
218
|
-
badge: 'bg-destructive text-white border-destructive',
|
|
219
|
-
text: 'text-destructive dark:text-destructive',
|
|
220
|
-
bg: 'bg-destructive/10',
|
|
221
|
-
border: 'border-destructive/30',
|
|
222
|
-
},
|
|
223
|
-
error: {
|
|
224
|
-
badge: 'bg-destructive text-white border-destructive',
|
|
225
|
-
text: 'text-destructive dark:text-destructive',
|
|
226
|
-
bg: 'bg-destructive/10',
|
|
227
|
-
border: 'border-destructive/30',
|
|
228
|
-
},
|
|
229
|
-
major: {
|
|
230
|
-
badge: 'bg-warning text-white border-warning',
|
|
231
|
-
text: 'text-warning dark:text-warning',
|
|
232
|
-
bg: 'bg-warning/10',
|
|
233
|
-
border: 'border-warning/30',
|
|
234
|
-
},
|
|
235
|
-
warning: {
|
|
236
|
-
badge: 'bg-warning text-white border-warning',
|
|
237
|
-
text: 'text-warning dark:text-warning',
|
|
238
|
-
bg: 'bg-warning/10',
|
|
239
|
-
border: 'border-warning/30',
|
|
240
|
-
},
|
|
241
|
-
minor: {
|
|
242
|
-
badge: 'bg-info/15 text-info dark:text-info border-info/30',
|
|
243
|
-
text: 'text-info dark:text-info',
|
|
244
|
-
bg: 'bg-info/10',
|
|
245
|
-
border: 'border-info/30',
|
|
246
|
-
},
|
|
247
|
-
info: {
|
|
248
|
-
badge: 'bg-info/15 text-info dark:text-info border-info/30',
|
|
249
|
-
text: 'text-info dark:text-info',
|
|
250
|
-
bg: 'bg-info/10',
|
|
251
|
-
border: 'border-info/30',
|
|
252
|
-
},
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
export function getSeverityStyle(severity: string): SeverityStyle {
|
|
256
|
-
const s = severity.toLowerCase();
|
|
257
|
-
return SEVERITY_STYLES[s] ?? { badge: 'bg-paper-elev text-ink-3 border-border', text: 'text-ink-3', bg: 'bg-muted/30', border: 'border-border' };
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// ── Type Styles (Backlog items) ────────────────────────────────────
|
|
261
|
-
|
|
262
|
-
export const TYPE_STYLES: Record<string, { badge: string; text: string; border: string }> = {
|
|
263
|
-
epic: { badge: 'bg-primary/15 text-primary dark:text-primary border-primary/30', text: 'text-primary dark:text-primary', border: 'border-l-purple-600' },
|
|
264
|
-
story: { badge: 'bg-info/15 text-info dark:text-info border-info/30', text: 'text-info dark:text-info', border: 'border-l-blue-600' },
|
|
265
|
-
task: { badge: 'bg-success/15 text-success dark:text-success border-success/30', text: 'text-success dark:text-success', border: 'border-l-green-600' },
|
|
266
|
-
bug: { badge: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30', text: 'text-destructive dark:text-destructive', border: 'border-l-red-600' },
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
// ── Card Styles ────────────────────────────────────────────────────
|
|
270
|
-
|
|
271
|
-
export const CARD_STYLES = {
|
|
272
|
-
default: 'bg-card border border-border/50 rounded-xl shadow-[var(--shadow-2)]',
|
|
273
|
-
elevated: 'bg-card border border-border/40 rounded-xl shadow-[var(--shadow-8)]',
|
|
274
|
-
dark: 'bg-foreground text-background rounded-xl shadow-[var(--shadow-16)]',
|
|
275
|
-
accent: 'bg-primary/5 border border-primary/15 rounded-xl',
|
|
276
|
-
empty: 'border-2 border-dashed border-border/50 rounded-xl',
|
|
277
|
-
} as const;
|
|
278
|
-
|
|
279
|
-
// ── Section / Typography Styles ────────────────────────────────────
|
|
280
|
-
|
|
281
|
-
export const SECTION_STYLES = {
|
|
282
|
-
pageTitle: 'text-lg sm:text-xl font-semibold tracking-tight text-ink',
|
|
283
|
-
sectionHeader: 'text-sm font-semibold text-ink',
|
|
284
|
-
cardLabel: 'text-[11px] font-semibold uppercase tracking-wider text-ink-3',
|
|
285
|
-
description: 'text-sm text-ink-3',
|
|
286
|
-
metricValue: 'text-xl sm:text-2xl font-semibold tabular-nums text-ink',
|
|
287
|
-
metricLabel: 'text-sm text-ink-3',
|
|
288
|
-
} as const;
|
|
289
|
-
|
|
290
|
-
// ── Importance Styles (Memory) ─────────────────────────────────────
|
|
291
|
-
|
|
292
|
-
export const IMPORTANCE_STYLES: Record<number, { badge: string; label: string; star: string }> = {
|
|
293
|
-
1: { badge: 'bg-paper-elev text-ink-3 border-border', label: 'Low', star: 'text-ink-3' },
|
|
294
|
-
2: { badge: 'bg-info/15 text-info dark:text-info border-info/30', label: 'Normal', star: 'text-info' },
|
|
295
|
-
3: { badge: 'bg-warning/15 text-warning dark:text-warning border-warning/30', label: 'High', star: 'text-warning' },
|
|
296
|
-
4: { badge: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30', label: 'Critical', star: 'text-destructive' },
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
// ── Risk Level Styles ──────────────────────────────────────────────
|
|
300
|
-
|
|
301
|
-
export interface RiskLevelStyle {
|
|
302
|
-
badge: string;
|
|
303
|
-
text: string;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Lowest risk — also the style for an unrecognised level. Named for the same
|
|
307
|
-
// reason as PRIORITY_LOW_STYLE: the fallback must be a proven value, not a
|
|
308
|
-
// second lookup into the open `Record`.
|
|
309
|
-
const RISK_LOW_STYLE: RiskLevelStyle = {
|
|
310
|
-
badge: 'bg-success/15 text-success dark:text-success border-success/30',
|
|
311
|
-
text: 'text-success dark:text-success',
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
export const RISK_LEVEL_STYLES: Record<string, RiskLevelStyle> = {
|
|
315
|
-
low: RISK_LOW_STYLE,
|
|
316
|
-
medium: { badge: 'bg-warning/15 text-warning dark:text-warning border-warning/30', text: 'text-warning dark:text-warning' },
|
|
317
|
-
high: { badge: 'bg-warning/15 text-warning dark:text-warning border-warning/30', text: 'text-warning dark:text-warning' },
|
|
318
|
-
critical: { badge: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30', text: 'text-destructive dark:text-destructive' },
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
export function getRiskLevelStyle(level: string): RiskLevelStyle {
|
|
322
|
-
return RISK_LEVEL_STYLES[level] ?? RISK_LOW_STYLE;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// ── Agent Source Styles ────────────────────────────────────────────
|
|
326
|
-
|
|
327
|
-
export const AGENT_SOURCE_STYLES: Record<string, { border: string; bg: string; icon: string; iconBg: string }> = {
|
|
328
|
-
dynamic: {
|
|
329
|
-
border: 'border-warning/30',
|
|
330
|
-
bg: 'bg-warning/5',
|
|
331
|
-
icon: 'text-warning',
|
|
332
|
-
iconBg: 'bg-warning/10',
|
|
333
|
-
},
|
|
334
|
-
predefined: {
|
|
335
|
-
border: 'border-border',
|
|
336
|
-
bg: 'bg-muted/20',
|
|
337
|
-
icon: 'text-primary',
|
|
338
|
-
iconBg: 'bg-primary/10',
|
|
339
|
-
},
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
// ── Kind Styles (Memory Graph Model) ─────────────────────────────────
|
|
343
|
-
|
|
344
|
-
export const KIND_STYLES: Record<string, string> = {
|
|
345
|
-
LESSON: 'bg-info/15 text-info dark:text-info border-info/30',
|
|
346
|
-
PATTERN: 'bg-primary/15 text-primary dark:text-primary border-primary/30',
|
|
347
|
-
CORRECTION: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30',
|
|
348
|
-
PREFERENCE: 'bg-success/15 text-success dark:text-success border-success/30',
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
// ── State Styles (Memory Graph Model) ────────────────────────────────
|
|
352
|
-
|
|
353
|
-
export const STATE_STYLES: Record<string, string> = {
|
|
354
|
-
CANDIDATE: 'bg-paper-elev text-ink-3 border-border',
|
|
355
|
-
ACTIVE: 'bg-success/15 text-success dark:text-success border-success/30',
|
|
356
|
-
SUPERSEDED: 'bg-paper-elev text-ink-3 border-border line-through',
|
|
357
|
-
CONTRADICTED: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30 line-through',
|
|
358
|
-
REVIEW_REQUIRED: 'bg-warning/15 text-warning dark:text-warning border-warning/30',
|
|
359
|
-
ARCHIVED: 'bg-paper-elev text-ink-3 border-border opacity-60',
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
// ── Origin Styles (Memory Graph Model) ───────────────────────────────
|
|
363
|
-
|
|
364
|
-
export const ORIGIN_STYLES: Record<string, string> = {
|
|
365
|
-
GATE_REJECTION: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30',
|
|
366
|
-
GATE_APPROVAL: 'bg-success/15 text-success dark:text-success border-success/30',
|
|
367
|
-
USER_CORRECTION: 'bg-warning/15 text-warning dark:text-warning border-warning/30',
|
|
368
|
-
MANUAL_OVERRIDE: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30',
|
|
369
|
-
REVIEW_FINDING: 'bg-warning/15 text-warning dark:text-warning border-warning/30',
|
|
370
|
-
PATTERN_DETECTION: 'bg-primary/15 text-primary dark:text-primary border-primary/30',
|
|
371
|
-
USER_CREATED: 'bg-info/15 text-info dark:text-info border-info/30',
|
|
372
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns a debounced version of the provided value.
|
|
5
|
-
* Updates only after `delayMs` milliseconds of inactivity.
|
|
6
|
-
*/
|
|
7
|
-
export function useDebouncedValue<T>(value: T, delayMs = 300): T {
|
|
8
|
-
const [debounced, setDebounced] = useState(value);
|
|
9
|
-
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
const timer = setTimeout(() => setDebounced(value), delayMs);
|
|
12
|
-
return () => clearTimeout(timer);
|
|
13
|
-
}, [value, delayMs]);
|
|
14
|
-
|
|
15
|
-
return debounced;
|
|
16
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
import { MOBILE_BREAKPOINT } from '../breakpoints';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* `true` when the viewport is narrower than the shared {@link MOBILE_BREAKPOINT}
|
|
7
|
-
* (Tailwind's `md`). Server-driven renderers use this to collapse tables to
|
|
8
|
-
* cards, reflow grids and go single-column WITHOUT the author declaring a
|
|
9
|
-
* breakpoint — responsiveness is a property of the primitive, not a checklist.
|
|
10
|
-
*
|
|
11
|
-
* Reads `window.innerWidth`, so it returns `false` until mounted on the client
|
|
12
|
-
* (SSR-safe: no layout thrash, no hydration mismatch beyond the first paint).
|
|
13
|
-
*/
|
|
14
|
-
export function useIsMobile(): boolean {
|
|
15
|
-
const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
19
|
-
const onChange = (): void => {
|
|
20
|
-
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
21
|
-
};
|
|
22
|
-
mql.addEventListener('change', onChange);
|
|
23
|
-
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
24
|
-
return () => mql.removeEventListener('change', onChange);
|
|
25
|
-
}, []);
|
|
26
|
-
|
|
27
|
-
return !!isMobile;
|
|
28
|
-
}
|
package/src/ui/index.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
-
// @xemahq/ui-kernel/ui — shared UI surface for biomes
|
|
3
|
-
//
|
|
4
|
-
// Canonical shadcn primitives + Xema chrome, owned by the kernel so biomes
|
|
5
|
-
// stop deep-importing the host shell's `@/components/ui/*` and re-implementing
|
|
6
|
-
// chrome (ErrorCard / EmptyState / StateCard / PageHeader). Host-framework-
|
|
7
|
-
// agnostic: React + radix + cva + lucide only, no Next/Vite/React-Router.
|
|
8
|
-
//
|
|
9
|
-
// The class-merge helper (`cn`) carries the Xema typography scale so merging
|
|
10
|
-
// matches the host shell exactly.
|
|
11
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
12
|
-
|
|
13
|
-
export { cn } from './cn';
|
|
14
|
-
|
|
15
|
-
// ── design tokens (semantic styling SSOT) ──
|
|
16
|
-
export * from './design-tokens';
|
|
17
|
-
|
|
18
|
-
// ── responsive breakpoint token (JS ↔ Tailwind `md`, single source) ──
|
|
19
|
-
export { MOBILE_BREAKPOINT } from './breakpoints';
|
|
20
|
-
|
|
21
|
-
// ── hooks ──
|
|
22
|
-
export { useDebouncedValue } from './hooks/use-debounced-value';
|
|
23
|
-
export { useIsMobile } from './hooks/use-is-mobile';
|
|
24
|
-
|
|
25
|
-
// ── shadcn primitives ──
|
|
26
|
-
export * from './primitives/button';
|
|
27
|
-
export * from './primitives/button-variants';
|
|
28
|
-
export * from './primitives/badge';
|
|
29
|
-
export * from './primitives/badge-variants';
|
|
30
|
-
export * from './primitives/input';
|
|
31
|
-
export * from './primitives/label';
|
|
32
|
-
export * from './primitives/select';
|
|
33
|
-
export * from './primitives/dialog';
|
|
34
|
-
export * from './primitives/card';
|
|
35
|
-
export * from './primitives/textarea';
|
|
36
|
-
export * from './primitives/tabs';
|
|
37
|
-
export * from './primitives/dropdown-menu';
|
|
38
|
-
export * from './primitives/skeleton';
|
|
39
|
-
export * from './primitives/checkbox';
|
|
40
|
-
export * from './primitives/table';
|
|
41
|
-
export * from './primitives/tooltip';
|
|
42
|
-
export * from './primitives/switch';
|
|
43
|
-
export * from './primitives/separator';
|
|
44
|
-
export * from './primitives/scroll-area';
|
|
45
|
-
export * from './primitives/alert-dialog';
|
|
46
|
-
export * from './primitives/popover';
|
|
47
|
-
export * from './primitives/collapsible';
|
|
48
|
-
export * from './primitives/resizable';
|
|
49
|
-
export * from './primitives/radio-group';
|
|
50
|
-
export * from './primitives/overflow-tabs';
|
|
51
|
-
export * from './primitives/tag-multi-select';
|
|
52
|
-
export * from './primitives/sheet';
|
|
53
|
-
export * from './primitives/form-stepper';
|
|
54
|
-
export * from './primitives/form-stepper.types';
|
|
55
|
-
export * from './primitives/async-combobox';
|
|
56
|
-
export {
|
|
57
|
-
PreviewDeviceFrame,
|
|
58
|
-
type PreviewDevice,
|
|
59
|
-
} from './primitives/preview-device-frame';
|
|
60
|
-
export {
|
|
61
|
-
UrlPreviewChrome,
|
|
62
|
-
type UrlPreviewChromeProps,
|
|
63
|
-
} from './primitives/url-preview-chrome';
|
|
64
|
-
|
|
65
|
-
// ── chart primitives (Wave 9.2 — pure SVG, no external chart lib) ──
|
|
66
|
-
export * from './charts';
|
|
67
|
-
|
|
68
|
-
// ── runtime branding applier (Wave 8.4) ──
|
|
69
|
-
export {
|
|
70
|
-
AppBrandingProvider,
|
|
71
|
-
APP_PRIMARY_COLOR_VAR,
|
|
72
|
-
type AppBrandingProviderProps,
|
|
73
|
-
} from './branding/app-branding-provider';
|
|
74
|
-
export {
|
|
75
|
-
useAppBranding,
|
|
76
|
-
type AppBrandingContextValue,
|
|
77
|
-
} from './branding/app-branding-context';
|
|
78
|
-
|
|
79
|
-
// ── Xema chrome ──
|
|
80
|
-
export { default as ErrorCard, type ErrorMessageFormatter } from './chrome/ErrorCard';
|
|
81
|
-
export { default as StatusBadge, type StatusBadgeProps, type StatusBadgeSize } from './chrome/status-badge';
|
|
82
|
-
export { default as ScopeBadge, type ScopeBadgeProps } from './chrome/scope-badge';
|
|
83
|
-
export {
|
|
84
|
-
default as ConfirmDeleteDialog,
|
|
85
|
-
type ConfirmDeleteDialogProps,
|
|
86
|
-
} from './chrome/confirm-delete-dialog';
|
|
87
|
-
export { default as PageShell } from './chrome/page-shell';
|
|
88
|
-
export {
|
|
89
|
-
default as EmptyState,
|
|
90
|
-
type EmptyStateVariant,
|
|
91
|
-
type EmptyStateSize,
|
|
92
|
-
type EmptyStateLinkComponent,
|
|
93
|
-
} from './chrome/EmptyState';
|
|
94
|
-
export { StateCard } from './chrome/StateCard';
|
|
95
|
-
export {
|
|
96
|
-
RecordCardList,
|
|
97
|
-
type RecordCardField,
|
|
98
|
-
type RecordCardListProps,
|
|
99
|
-
} from './chrome/RecordCardList';
|
|
100
|
-
export { default as PageHeader, PageToolbar } from './chrome/PageHeader';
|
|
101
|
-
export { default as LoadingState, type LoadingStateVariant } from './chrome/LoadingState';
|
|
102
|
-
export { default as AsyncBoundary } from './chrome/AsyncBoundary';
|
|
103
|
-
|
|
104
|
-
// NOTE: `PdfPreview` intentionally does NOT live in this barrel. It pulls in
|
|
105
|
-
// `react-pdf` → `pdfjs-dist` (~1.9 MB), so it ships from the dedicated subpath
|
|
106
|
-
// `@xemahq/ui-kernel/pdf` to keep this `/ui` surface (and app-ui's AppShell)
|
|
107
|
-
// tree-shakeable. Import it from `@xemahq/ui-kernel/pdf`.
|
|
108
|
-
|
|
109
|
-
// ── guided-capture UX kit (B5 — wizard, validation, prefill, schema form) ──
|
|
110
|
-
export * from './capture';
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PdfPreview — a reusable, canvas-rendered PDF viewer with in-app zoom, for any
|
|
5
|
-
* web biome or host surface (exported from `@xemahq/ui-kernel/ui`).
|
|
6
|
-
*
|
|
7
|
-
* WHY canvas, not an `<iframe>`: the bytes are frequently UNTRUSTED (user
|
|
8
|
-
* uploads, third-party artifacts). pdf.js renders each page to a `<canvas>` with
|
|
9
|
-
* NO iframe and NO script execution — strictly safer than embedding the file in
|
|
10
|
-
* a browser viewer — while giving zoom controls a fully-sandboxed iframe cannot.
|
|
11
|
-
* Text/annotation layers are disabled: this is a PREVIEW, not an editor.
|
|
12
|
-
*
|
|
13
|
-
* The component only renders from a resolved `url` (durable publicUrl, dataUrl,
|
|
14
|
-
* or `blob:`); the caller owns fetching/authing/revoking that URL.
|
|
15
|
-
*/
|
|
16
|
-
import { RotateCcw, ZoomIn, ZoomOut } from 'lucide-react';
|
|
17
|
-
import { useCallback, useMemo, useState, type JSX } from 'react';
|
|
18
|
-
import { Document, Page, pdfjs } from 'react-pdf';
|
|
19
|
-
|
|
20
|
-
import { cn } from '../cn';
|
|
21
|
-
|
|
22
|
-
// The pdf.js worker is loaded same-origin (CSP-safe, and CJS-build-safe — no
|
|
23
|
-
// `import.meta`). The HOST app must serve the version-matched worker at this
|
|
24
|
-
// path — host-web copies `pdfjs-dist/build/pdf.worker.min.mjs` into `public/`
|
|
25
|
-
// via its `copy-pdf-worker` script (run on predev/prebuild). Overridable before
|
|
26
|
-
// first render for hosts that serve it elsewhere.
|
|
27
|
-
if (!pdfjs.GlobalWorkerOptions.workerSrc) {
|
|
28
|
-
pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.mjs';
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const MIN_SCALE = 0.5;
|
|
32
|
-
const MAX_SCALE = 3;
|
|
33
|
-
const STEP = 0.25;
|
|
34
|
-
const DEFAULT_SCALE = 1;
|
|
35
|
-
|
|
36
|
-
const clampScale = (s: number): number =>
|
|
37
|
-
Math.min(MAX_SCALE, Math.max(MIN_SCALE, Math.round(s * 100) / 100));
|
|
38
|
-
|
|
39
|
-
export interface PdfPreviewProps {
|
|
40
|
-
/** A resolved, fetchable URL: durable `publicUrl`, `dataUrl`, or `blob:`. */
|
|
41
|
-
readonly url: string;
|
|
42
|
-
/** Human label shown in the toolbar / used as the document title. */
|
|
43
|
-
readonly title?: string;
|
|
44
|
-
readonly className?: string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function PdfPreview({ url, title, className }: PdfPreviewProps): JSX.Element {
|
|
48
|
-
const [numPages, setNumPages] = useState(0);
|
|
49
|
-
const [scale, setScale] = useState(DEFAULT_SCALE);
|
|
50
|
-
const [error, setError] = useState<string | null>(null);
|
|
51
|
-
|
|
52
|
-
// Stable `file` identity so react-pdf doesn't re-fetch on every render.
|
|
53
|
-
const file = useMemo(() => ({ url }), [url]);
|
|
54
|
-
|
|
55
|
-
const zoomOut = useCallback(() => setScale((s) => clampScale(s - STEP)), []);
|
|
56
|
-
const zoomIn = useCallback(() => setScale((s) => clampScale(s + STEP)), []);
|
|
57
|
-
const reset = useCallback(() => setScale(DEFAULT_SCALE), []);
|
|
58
|
-
|
|
59
|
-
const btn =
|
|
60
|
-
'inline-flex h-7 w-7 items-center justify-center rounded text-neutral-600 ' +
|
|
61
|
-
'hover:bg-neutral-200/70 disabled:pointer-events-none disabled:opacity-40 ' +
|
|
62
|
-
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1';
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<div
|
|
66
|
-
className={cn(
|
|
67
|
-
'flex h-[520px] flex-col overflow-hidden rounded border border-neutral-200 bg-white',
|
|
68
|
-
className,
|
|
69
|
-
)}
|
|
70
|
-
>
|
|
71
|
-
<div className="flex items-center gap-1 border-b border-neutral-200 bg-neutral-50 px-2 py-1">
|
|
72
|
-
<button type="button" onClick={zoomOut} disabled={scale <= MIN_SCALE} aria-label="Zoom out" className={btn}>
|
|
73
|
-
<ZoomOut className="h-4 w-4" />
|
|
74
|
-
</button>
|
|
75
|
-
<span className="w-12 text-center text-xs tabular-nums text-neutral-500">
|
|
76
|
-
{Math.round(scale * 100)}%
|
|
77
|
-
</span>
|
|
78
|
-
<button type="button" onClick={zoomIn} disabled={scale >= MAX_SCALE} aria-label="Zoom in" className={btn}>
|
|
79
|
-
<ZoomIn className="h-4 w-4" />
|
|
80
|
-
</button>
|
|
81
|
-
<button type="button" onClick={reset} disabled={scale === DEFAULT_SCALE} aria-label="Reset zoom" className={btn}>
|
|
82
|
-
<RotateCcw className="h-4 w-4" />
|
|
83
|
-
</button>
|
|
84
|
-
{title ? (
|
|
85
|
-
<span className="ml-2 min-w-0 flex-1 truncate text-xs text-neutral-400" title={title}>
|
|
86
|
-
{title}
|
|
87
|
-
</span>
|
|
88
|
-
) : null}
|
|
89
|
-
</div>
|
|
90
|
-
|
|
91
|
-
<div className="flex-1 overflow-auto bg-neutral-100 p-3">
|
|
92
|
-
{error ? (
|
|
93
|
-
<div className="p-4 text-xs text-neutral-500">
|
|
94
|
-
Couldn't render this PDF ({error}). Use the download affordance.
|
|
95
|
-
</div>
|
|
96
|
-
) : (
|
|
97
|
-
<Document
|
|
98
|
-
file={file}
|
|
99
|
-
onLoadSuccess={({ numPages: n }) => {
|
|
100
|
-
setNumPages(n);
|
|
101
|
-
setError(null);
|
|
102
|
-
}}
|
|
103
|
-
onLoadError={(e) => setError(e.message)}
|
|
104
|
-
loading={<div className="p-4 text-xs text-neutral-500">Loading PDF…</div>}
|
|
105
|
-
className="flex flex-col items-center gap-3"
|
|
106
|
-
>
|
|
107
|
-
{Array.from({ length: numPages }, (_, i) => (
|
|
108
|
-
<Page
|
|
109
|
-
key={i}
|
|
110
|
-
pageNumber={i + 1}
|
|
111
|
-
scale={scale}
|
|
112
|
-
renderTextLayer={false}
|
|
113
|
-
renderAnnotationLayer={false}
|
|
114
|
-
className="shadow-sm"
|
|
115
|
-
/>
|
|
116
|
-
))}
|
|
117
|
-
</Document>
|
|
118
|
-
)}
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
);
|
|
122
|
-
}
|