@dowel-ui/react 0.4.0 → 0.7.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/README.md +9 -5
- package/dist/blocks/admin-dashboard/meta.js +31 -0
- package/dist/blocks/admin-dashboard/meta.js.map +1 -0
- package/dist/blocks/agent-console/meta.js +27 -0
- package/dist/blocks/agent-console/meta.js.map +1 -0
- package/dist/blocks/ai-dashboard/meta.js +25 -0
- package/dist/blocks/ai-dashboard/meta.js.map +1 -0
- package/dist/blocks/ai-workspace/meta.js +33 -0
- package/dist/blocks/ai-workspace/meta.js.map +1 -0
- package/dist/blocks/analytics/meta.js +24 -0
- package/dist/blocks/analytics/meta.js.map +1 -0
- package/dist/blocks/billing/meta.js +25 -0
- package/dist/blocks/billing/meta.js.map +1 -0
- package/dist/blocks/command-center/meta.js +28 -0
- package/dist/blocks/command-center/meta.js.map +1 -0
- package/dist/blocks/crm/meta.js +32 -0
- package/dist/blocks/crm/meta.js.map +1 -0
- package/dist/blocks/onboarding/meta.js +23 -0
- package/dist/blocks/onboarding/meta.js.map +1 -0
- package/dist/components/accordion/accordion.js +1 -1
- package/dist/components/accordion/accordion.js.map +1 -1
- package/dist/components/activity-feed/activity-feed.js +1 -1
- package/dist/components/activity-feed/activity-feed.js.map +1 -1
- package/dist/components/ai-agent-plan/ai-agent-plan.js +1 -1
- package/dist/components/ai-agent-plan/ai-agent-plan.js.map +1 -1
- package/dist/components/ai-extraction-review/ai-extraction-review.d.ts +52 -0
- package/dist/components/ai-extraction-review/ai-extraction-review.d.ts.map +1 -0
- package/dist/components/ai-extraction-review/ai-extraction-review.js +249 -0
- package/dist/components/ai-extraction-review/ai-extraction-review.js.map +1 -0
- package/dist/components/ai-extraction-review/extraction-model.d.ts +94 -0
- package/dist/components/ai-extraction-review/extraction-model.d.ts.map +1 -0
- package/dist/components/ai-extraction-review/extraction-model.js +91 -0
- package/dist/components/ai-extraction-review/extraction-model.js.map +1 -0
- package/dist/components/ai-extraction-review/index.d.ts +3 -0
- package/dist/components/ai-extraction-review/index.js +3 -0
- package/dist/components/ai-extraction-review/meta.js +17 -0
- package/dist/components/ai-extraction-review/meta.js.map +1 -0
- package/dist/components/ai-prompt-input/ai-prompt-input.js +1 -1
- package/dist/components/ai-prompt-input/ai-prompt-input.js.map +1 -1
- package/dist/components/ai-reasoning/ai-reasoning.js +1 -1
- package/dist/components/ai-reasoning/ai-reasoning.js.map +1 -1
- package/dist/components/ai-response/ai-response.js +2 -2
- package/dist/components/ai-response/ai-response.js.map +1 -1
- package/dist/components/ai-suggested-value/ai-suggested-value.d.ts +72 -0
- package/dist/components/ai-suggested-value/ai-suggested-value.d.ts.map +1 -0
- package/dist/components/ai-suggested-value/ai-suggested-value.js +126 -0
- package/dist/components/ai-suggested-value/ai-suggested-value.js.map +1 -0
- package/dist/components/ai-suggested-value/index.d.ts +2 -0
- package/dist/components/ai-suggested-value/index.js +2 -0
- package/dist/components/ai-suggested-value/meta.js +17 -0
- package/dist/components/ai-suggested-value/meta.js.map +1 -0
- package/dist/components/ai-tool/ai-tool.js +2 -2
- package/dist/components/ai-tool/ai-tool.js.map +1 -1
- package/dist/components/breadcrumb/breadcrumb.d.ts +52 -0
- package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -0
- package/dist/components/breadcrumb/breadcrumb.js +141 -0
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -0
- package/dist/components/breadcrumb/index.d.ts +2 -0
- package/dist/components/breadcrumb/index.js +2 -0
- package/dist/components/breadcrumb/meta.js +17 -0
- package/dist/components/breadcrumb/meta.js.map +1 -0
- package/dist/components/calendar/calendar.js +2 -2
- package/dist/components/calendar/calendar.js.map +1 -1
- package/dist/components/code-block/code-block.js +1 -1
- package/dist/components/code-block/code-block.js.map +1 -1
- package/dist/components/collapsible/collapsible.d.ts +30 -0
- package/dist/components/collapsible/collapsible.d.ts.map +1 -0
- package/dist/components/collapsible/collapsible.js +38 -0
- package/dist/components/collapsible/collapsible.js.map +1 -0
- package/dist/components/collapsible/index.d.ts +2 -0
- package/dist/components/collapsible/index.js +2 -0
- package/dist/components/collapsible/meta.js +17 -0
- package/dist/components/collapsible/meta.js.map +1 -0
- package/dist/components/combobox/combobox.js +2 -2
- package/dist/components/combobox/combobox.js.map +1 -1
- package/dist/components/command/command.js +1 -1
- package/dist/components/command/command.js.map +1 -1
- package/dist/components/confirm-typed/confirm-typed.d.ts +47 -0
- package/dist/components/confirm-typed/confirm-typed.d.ts.map +1 -0
- package/dist/components/confirm-typed/confirm-typed.js +106 -0
- package/dist/components/confirm-typed/confirm-typed.js.map +1 -0
- package/dist/components/confirm-typed/index.d.ts +2 -0
- package/dist/components/confirm-typed/index.js +2 -0
- package/dist/components/confirm-typed/meta.js +17 -0
- package/dist/components/confirm-typed/meta.js.map +1 -0
- package/dist/components/cron-editor/cron-editor.d.ts +36 -0
- package/dist/components/cron-editor/cron-editor.d.ts.map +1 -0
- package/dist/components/cron-editor/cron-editor.js +493 -0
- package/dist/components/cron-editor/cron-editor.js.map +1 -0
- package/dist/components/cron-editor/cron-expression.d.ts +82 -0
- package/dist/components/cron-editor/cron-expression.d.ts.map +1 -0
- package/dist/components/cron-editor/cron-expression.js +352 -0
- package/dist/components/cron-editor/cron-expression.js.map +1 -0
- package/dist/components/cron-editor/index.d.ts +3 -0
- package/dist/components/cron-editor/index.js +3 -0
- package/dist/components/cron-editor/meta.js +17 -0
- package/dist/components/cron-editor/meta.js.map +1 -0
- package/dist/components/data-table/data-table.d.ts.map +1 -1
- package/dist/components/data-table/data-table.js +4 -1
- package/dist/components/data-table/data-table.js.map +1 -1
- package/dist/components/dialog/dialog.js +2 -2
- package/dist/components/dialog/dialog.js.map +1 -1
- package/dist/components/diff-viewer/diff-viewer.js +4 -4
- package/dist/components/diff-viewer/diff-viewer.js.map +1 -1
- package/dist/components/direction/direction.d.ts +35 -0
- package/dist/components/direction/direction.d.ts.map +1 -0
- package/dist/components/direction/direction.js +14 -0
- package/dist/components/direction/direction.js.map +1 -0
- package/dist/components/direction/index.d.ts +2 -0
- package/dist/components/direction/index.js +2 -0
- package/dist/components/direction/meta.js +17 -0
- package/dist/components/direction/meta.js.map +1 -0
- package/dist/components/dns-record/dns-record.d.ts +61 -0
- package/dist/components/dns-record/dns-record.d.ts.map +1 -0
- package/dist/components/dns-record/dns-record.js +227 -0
- package/dist/components/dns-record/dns-record.js.map +1 -0
- package/dist/components/dns-record/index.d.ts +2 -0
- package/dist/components/dns-record/index.js +2 -0
- package/dist/components/dns-record/meta.js +17 -0
- package/dist/components/dns-record/meta.js.map +1 -0
- package/dist/components/drawer/drawer.js +1 -1
- package/dist/components/drawer/drawer.js.map +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.js +9 -8
- package/dist/components/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/components/input/input.js +1 -1
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/log-viewer/log-viewer.js +2 -2
- package/dist/components/log-viewer/log-viewer.js.map +1 -1
- package/dist/components/meter/meter.js +1 -1
- package/dist/components/meter/meter.js.map +1 -1
- package/dist/components/pagination/pagination.d.ts.map +1 -1
- package/dist/components/pagination/pagination.js +3 -2
- package/dist/components/pagination/pagination.js.map +1 -1
- package/dist/components/permission-matrix/index.d.ts +3 -0
- package/dist/components/permission-matrix/index.js +3 -0
- package/dist/components/permission-matrix/meta.js +17 -0
- package/dist/components/permission-matrix/meta.js.map +1 -0
- package/dist/components/permission-matrix/permission-matrix.d.ts +46 -0
- package/dist/components/permission-matrix/permission-matrix.d.ts.map +1 -0
- package/dist/components/permission-matrix/permission-matrix.js +199 -0
- package/dist/components/permission-matrix/permission-matrix.js.map +1 -0
- package/dist/components/permission-matrix/permission-model.d.ts +53 -0
- package/dist/components/permission-matrix/permission-model.d.ts.map +1 -0
- package/dist/components/permission-matrix/permission-model.js +64 -0
- package/dist/components/permission-matrix/permission-model.js.map +1 -0
- package/dist/components/record-diff/record-diff.js +4 -4
- package/dist/components/record-diff/record-diff.js.map +1 -1
- package/dist/components/secret-field/index.d.ts +2 -0
- package/dist/components/secret-field/index.js +2 -0
- package/dist/components/secret-field/meta.js +17 -0
- package/dist/components/secret-field/meta.js.map +1 -0
- package/dist/components/secret-field/secret-field.d.ts +58 -0
- package/dist/components/secret-field/secret-field.d.ts.map +1 -0
- package/dist/components/secret-field/secret-field.js +168 -0
- package/dist/components/secret-field/secret-field.js.map +1 -0
- package/dist/components/select/select.js +2 -2
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/session-expiry/index.d.ts +2 -0
- package/dist/components/session-expiry/index.js +2 -0
- package/dist/components/session-expiry/meta.js +17 -0
- package/dist/components/session-expiry/meta.js.map +1 -0
- package/dist/components/session-expiry/session-expiry.d.ts +64 -0
- package/dist/components/session-expiry/session-expiry.d.ts.map +1 -0
- package/dist/components/session-expiry/session-expiry.js +185 -0
- package/dist/components/session-expiry/session-expiry.js.map +1 -0
- package/dist/components/sheet/sheet.d.ts.map +1 -1
- package/dist/components/sheet/sheet.js +2 -2
- package/dist/components/sheet/sheet.js.map +1 -1
- package/dist/components/shortcut-recorder/index.d.ts +3 -0
- package/dist/components/shortcut-recorder/index.js +3 -0
- package/dist/components/shortcut-recorder/meta.js +17 -0
- package/dist/components/shortcut-recorder/meta.js.map +1 -0
- package/dist/components/shortcut-recorder/shortcut-model.d.ts +67 -0
- package/dist/components/shortcut-recorder/shortcut-model.d.ts.map +1 -0
- package/dist/components/shortcut-recorder/shortcut-model.js +168 -0
- package/dist/components/shortcut-recorder/shortcut-model.js.map +1 -0
- package/dist/components/shortcut-recorder/shortcut-recorder.d.ts +47 -0
- package/dist/components/shortcut-recorder/shortcut-recorder.d.ts.map +1 -0
- package/dist/components/shortcut-recorder/shortcut-recorder.js +212 -0
- package/dist/components/shortcut-recorder/shortcut-recorder.js.map +1 -0
- package/dist/components/sidebar/index.d.ts +2 -0
- package/dist/components/sidebar/index.js +2 -0
- package/dist/components/sidebar/meta.js +17 -0
- package/dist/components/sidebar/meta.js.map +1 -0
- package/dist/components/sidebar/sidebar.d.ts +69 -0
- package/dist/components/sidebar/sidebar.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar.js +256 -0
- package/dist/components/sidebar/sidebar.js.map +1 -0
- package/dist/components/sync-status/index.d.ts +2 -0
- package/dist/components/sync-status/index.js +2 -0
- package/dist/components/sync-status/meta.js +17 -0
- package/dist/components/sync-status/meta.js.map +1 -0
- package/dist/components/sync-status/sync-status.d.ts +65 -0
- package/dist/components/sync-status/sync-status.d.ts.map +1 -0
- package/dist/components/sync-status/sync-status.js +103 -0
- package/dist/components/sync-status/sync-status.js.map +1 -0
- package/dist/components/table/table.js +2 -2
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/tags-input/tags-input.js +1 -1
- package/dist/components/tags-input/tags-input.js.map +1 -1
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/index.js +2 -0
- package/dist/components/textarea/meta.js +17 -0
- package/dist/components/textarea/meta.js.map +1 -0
- package/dist/components/textarea/textarea.d.ts +43 -0
- package/dist/components/textarea/textarea.d.ts.map +1 -0
- package/dist/components/textarea/textarea.js +119 -0
- package/dist/components/textarea/textarea.js.map +1 -0
- package/dist/components/time-range-picker/time-range-picker.js +3 -3
- package/dist/components/time-range-picker/time-range-picker.js.map +1 -1
- package/dist/components/toast/toast.d.ts.map +1 -1
- package/dist/components/toast/toast.js +2 -2
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/index.d.ts +36 -2
- package/dist/index.js +22 -3
- package/dist/lib/styles.d.ts +16 -1
- package/dist/lib/styles.d.ts.map +1 -1
- package/dist/lib/styles.js +16 -1
- package/dist/lib/styles.js.map +1 -1
- package/dist/registry/blocks.d.ts.map +1 -1
- package/dist/registry/blocks.js +27 -9
- package/dist/registry/blocks.js.map +1 -1
- package/dist/registry/components.d.ts.map +1 -1
- package/dist/registry/components.js +84 -54
- package/dist/registry/components.js.map +1 -1
- package/dist/registry/schema.d.ts +8 -0
- package/dist/registry/schema.d.ts.map +1 -1
- package/dist/registry/schema.js.map +1 -1
- package/package.json +5 -4
- package/src/components/accordion/accordion.tsx +1 -1
- package/src/components/activity-feed/activity-feed.tsx +1 -1
- package/src/components/ai-agent-plan/ai-agent-plan.tsx +0 -0
- package/src/components/ai-extraction-review/ai-extraction-review.tsx +492 -0
- package/src/components/ai-extraction-review/extraction-model.ts +159 -0
- package/src/components/ai-extraction-review/index.ts +13 -0
- package/src/components/ai-extraction-review/meta.ts +24 -0
- package/src/components/ai-prompt-input/ai-prompt-input.tsx +1 -1
- package/src/components/ai-reasoning/ai-reasoning.tsx +1 -1
- package/src/components/ai-response/ai-response.tsx +2 -2
- package/src/components/ai-suggested-value/ai-suggested-value.tsx +295 -0
- package/src/components/ai-suggested-value/index.ts +6 -0
- package/src/components/ai-suggested-value/meta.ts +24 -0
- package/src/components/ai-tool/ai-tool.tsx +2 -2
- package/src/components/breadcrumb/breadcrumb.tsx +157 -0
- package/src/components/breadcrumb/index.ts +10 -0
- package/src/components/breadcrumb/meta.ts +19 -0
- package/src/components/calendar/calendar.tsx +2 -2
- package/src/components/code-block/code-block.tsx +1 -1
- package/src/components/collapsible/collapsible.tsx +63 -0
- package/src/components/collapsible/index.ts +6 -0
- package/src/components/collapsible/meta.ts +16 -0
- package/src/components/combobox/combobox.tsx +2 -2
- package/src/components/command/command.tsx +1 -1
- package/src/components/confirm-typed/confirm-typed.tsx +191 -0
- package/src/components/confirm-typed/index.ts +1 -0
- package/src/components/confirm-typed/meta.ts +22 -0
- package/src/components/cron-editor/cron-editor.tsx +676 -0
- package/src/components/cron-editor/cron-expression.ts +552 -0
- package/src/components/cron-editor/index.ts +23 -0
- package/src/components/cron-editor/meta.ts +23 -0
- package/src/components/data-table/data-table.tsx +14 -3
- package/src/components/dialog/dialog.tsx +2 -2
- package/src/components/diff-viewer/diff-viewer.tsx +4 -4
- package/src/components/direction/direction.tsx +38 -0
- package/src/components/direction/index.ts +1 -0
- package/src/components/direction/meta.ts +19 -0
- package/src/components/dns-record/dns-record.tsx +315 -0
- package/src/components/dns-record/index.ts +7 -0
- package/src/components/dns-record/meta.ts +21 -0
- package/src/components/drawer/drawer.tsx +1 -1
- package/src/components/dropdown-menu/dropdown-menu.tsx +14 -8
- package/src/components/input/input.tsx +1 -1
- package/src/components/log-viewer/log-viewer.tsx +2 -2
- package/src/components/meter/meter.tsx +1 -1
- package/src/components/pagination/pagination.tsx +13 -2
- package/src/components/permission-matrix/index.ts +14 -0
- package/src/components/permission-matrix/meta.ts +23 -0
- package/src/components/permission-matrix/permission-matrix.tsx +368 -0
- package/src/components/permission-matrix/permission-model.ts +120 -0
- package/src/components/record-diff/record-diff.tsx +4 -4
- package/src/components/secret-field/index.ts +6 -0
- package/src/components/secret-field/meta.ts +21 -0
- package/src/components/secret-field/secret-field.tsx +284 -0
- package/src/components/select/select.tsx +2 -2
- package/src/components/session-expiry/index.ts +9 -0
- package/src/components/session-expiry/meta.ts +23 -0
- package/src/components/session-expiry/session-expiry.tsx +321 -0
- package/src/components/sheet/sheet.tsx +8 -4
- package/src/components/shortcut-recorder/index.ts +19 -0
- package/src/components/shortcut-recorder/meta.ts +22 -0
- package/src/components/shortcut-recorder/shortcut-model.ts +204 -0
- package/src/components/shortcut-recorder/shortcut-recorder.tsx +336 -0
- package/src/components/sidebar/index.ts +19 -0
- package/src/components/sidebar/meta.ts +25 -0
- package/src/components/sidebar/sidebar.tsx +374 -0
- package/src/components/sync-status/index.ts +9 -0
- package/src/components/sync-status/meta.ts +21 -0
- package/src/components/sync-status/sync-status.tsx +217 -0
- package/src/components/table/table.tsx +3 -3
- package/src/components/tags-input/tags-input.tsx +1 -1
- package/src/components/textarea/index.ts +1 -0
- package/src/components/textarea/meta.ts +21 -0
- package/src/components/textarea/textarea.tsx +210 -0
- package/src/components/time-range-picker/time-range-picker.tsx +3 -3
- package/src/components/toast/toast.tsx +14 -6
- package/src/index.ts +15 -0
- package/src/lib/styles.ts +16 -0
- package/src/registry/blocks.ts +18 -0
- package/src/registry/components.ts +30 -0
- package/src/registry/schema.ts +8 -0
- package/src/blocks/admin-users/admin-users.tsx +0 -251
- package/src/blocks/admin-users/index.ts +0 -1
- package/src/blocks/admin-users/meta.ts +0 -27
- package/src/blocks/ai-chat/ai-chat.tsx +0 -280
- package/src/blocks/ai-chat/index.ts +0 -7
- package/src/blocks/ai-chat/meta.ts +0 -32
- package/src/blocks/dashboard/dashboard.tsx +0 -192
- package/src/blocks/dashboard/index.ts +0 -6
- package/src/blocks/dashboard/meta.ts +0 -18
- package/src/blocks/forgot-password/forgot-password.tsx +0 -158
- package/src/blocks/forgot-password/index.ts +0 -1
- package/src/blocks/forgot-password/meta.ts +0 -18
- package/src/blocks/login/index.ts +0 -1
- package/src/blocks/login/login.tsx +0 -178
- package/src/blocks/login/meta.ts +0 -18
- package/src/blocks/pricing/index.ts +0 -1
- package/src/blocks/pricing/meta.ts +0 -18
- package/src/blocks/pricing/pricing.tsx +0 -176
- package/src/blocks/settings/index.ts +0 -6
- package/src/blocks/settings/meta.ts +0 -29
- package/src/blocks/settings/settings.tsx +0 -317
- package/src/blocks/signup/index.ts +0 -1
- package/src/blocks/signup/meta.ts +0 -18
- package/src/blocks/signup/signup.tsx +0 -240
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.js","names":["accordionMeta","activityFeedMeta","aiActionLedgerMeta","aiAgentPlanMeta","aiAgentStatusMeta","aiApprovalRequestMeta","aiConversationMeta","aiDisclosureMeta","aiInlineCompletionMeta","aiMessageMeta","aiModelSelectorMeta","aiPromptInputMeta","aiReasoningMeta","aiResponseMeta","aiSourcesMeta","aiStructuredOutputMeta","aiTokenUsageMeta","aiToolMeta","alertMeta","avatarMeta","badgeMeta","buttonMeta","calendarMeta","cardMeta","checkboxMeta","codeBlockMeta","comboboxMeta","commandMeta","dataTableMeta","datePickerMeta","dialogMeta","diffViewerMeta","drawerMeta","dropdownMenuMeta","emptyStateMeta","fileUploadMeta","formMeta","inputMeta","labelMeta","logViewerMeta","meterMeta","metricDeltaMeta","paginationMeta","popoverMeta","progressMeta","radioGroupMeta","recordDiffMeta","selectMeta","separatorMeta","sheetMeta","skeletonMeta","sliderMeta","spinnerMeta","switchMeta","tableMeta","tabsMeta","tagsInputMeta","timeRangePickerMeta","toastMeta","tooltipMeta"],"sources":["../../src/registry/components.ts"],"sourcesContent":["import type { ComponentMeta } from \"./schema\";\n\nimport { meta as accordionMeta } from \"@/components/accordion/meta\";\nimport { meta as activityFeedMeta } from \"@/components/activity-feed/meta\";\nimport { meta as aiActionLedgerMeta } from \"@/components/ai-action-ledger/meta\";\nimport { meta as aiAgentPlanMeta } from \"@/components/ai-agent-plan/meta\";\nimport { meta as aiAgentStatusMeta } from \"@/components/ai-agent-status/meta\";\nimport { meta as aiApprovalRequestMeta } from \"@/components/ai-approval-request/meta\";\nimport { meta as aiConversationMeta } from \"@/components/ai-conversation/meta\";\nimport { meta as aiDisclosureMeta } from \"@/components/ai-disclosure/meta\";\nimport { meta as aiInlineCompletionMeta } from \"@/components/ai-inline-completion/meta\";\nimport { meta as aiMessageMeta } from \"@/components/ai-message/meta\";\nimport { meta as aiModelSelectorMeta } from \"@/components/ai-model-selector/meta\";\nimport { meta as aiPromptInputMeta } from \"@/components/ai-prompt-input/meta\";\nimport { meta as aiReasoningMeta } from \"@/components/ai-reasoning/meta\";\nimport { meta as aiResponseMeta } from \"@/components/ai-response/meta\";\nimport { meta as aiSourcesMeta } from \"@/components/ai-sources/meta\";\nimport { meta as aiStructuredOutputMeta } from \"@/components/ai-structured-output/meta\";\nimport { meta as aiTokenUsageMeta } from \"@/components/ai-token-usage/meta\";\nimport { meta as aiToolMeta } from \"@/components/ai-tool/meta\";\nimport { meta as alertMeta } from \"@/components/alert/meta\";\nimport { meta as avatarMeta } from \"@/components/avatar/meta\";\nimport { meta as badgeMeta } from \"@/components/badge/meta\";\nimport { meta as buttonMeta } from \"@/components/button/meta\";\nimport { meta as calendarMeta } from \"@/components/calendar/meta\";\nimport { meta as cardMeta } from \"@/components/card/meta\";\nimport { meta as checkboxMeta } from \"@/components/checkbox/meta\";\nimport { meta as codeBlockMeta } from \"@/components/code-block/meta\";\nimport { meta as comboboxMeta } from \"@/components/combobox/meta\";\nimport { meta as commandMeta } from \"@/components/command/meta\";\nimport { meta as dataTableMeta } from \"@/components/data-table/meta\";\nimport { meta as datePickerMeta } from \"@/components/date-picker/meta\";\nimport { meta as dialogMeta } from \"@/components/dialog/meta\";\nimport { meta as diffViewerMeta } from \"@/components/diff-viewer/meta\";\nimport { meta as drawerMeta } from \"@/components/drawer/meta\";\nimport { meta as dropdownMenuMeta } from \"@/components/dropdown-menu/meta\";\nimport { meta as emptyStateMeta } from \"@/components/empty-state/meta\";\nimport { meta as fileUploadMeta } from \"@/components/file-upload/meta\";\nimport { meta as formMeta } from \"@/components/form/meta\";\nimport { meta as inputMeta } from \"@/components/input/meta\";\nimport { meta as labelMeta } from \"@/components/label/meta\";\nimport { meta as logViewerMeta } from \"@/components/log-viewer/meta\";\nimport { meta as meterMeta } from \"@/components/meter/meta\";\nimport { meta as metricDeltaMeta } from \"@/components/metric-delta/meta\";\nimport { meta as paginationMeta } from \"@/components/pagination/meta\";\nimport { meta as popoverMeta } from \"@/components/popover/meta\";\nimport { meta as progressMeta } from \"@/components/progress/meta\";\nimport { meta as radioGroupMeta } from \"@/components/radio-group/meta\";\nimport { meta as recordDiffMeta } from \"@/components/record-diff/meta\";\nimport { meta as selectMeta } from \"@/components/select/meta\";\nimport { meta as separatorMeta } from \"@/components/separator/meta\";\nimport { meta as sheetMeta } from \"@/components/sheet/meta\";\nimport { meta as skeletonMeta } from \"@/components/skeleton/meta\";\nimport { meta as sliderMeta } from \"@/components/slider/meta\";\nimport { meta as spinnerMeta } from \"@/components/spinner/meta\";\nimport { meta as switchMeta } from \"@/components/switch/meta\";\nimport { meta as tableMeta } from \"@/components/table/meta\";\nimport { meta as tabsMeta } from \"@/components/tabs/meta\";\nimport { meta as tagsInputMeta } from \"@/components/tags-input/meta\";\nimport { meta as timeRangePickerMeta } from \"@/components/time-range-picker/meta\";\nimport { meta as toastMeta } from \"@/components/toast/meta\";\nimport { meta as tooltipMeta } from \"@/components/tooltip/meta\";\n\n/**\n * Every component in the registry.\n *\n * An explicit list rather than a glob: the registry build runs in plain Node,\n * where bundler-only globbing is unavailable, and a static list is also what\n * lets the bundle tree-shake. `meta.test.ts` fails if a component directory\n * exists that is missing from here, so it cannot silently fall out of date.\n *\n * Identifiers carry a `Meta` suffix because component names include reserved\n * words — `switch` cannot be a binding name.\n */\nexport const componentMetas: ComponentMeta[] = [\n accordionMeta,\n activityFeedMeta,\n aiActionLedgerMeta,\n aiAgentPlanMeta,\n aiAgentStatusMeta,\n aiApprovalRequestMeta,\n aiConversationMeta,\n aiDisclosureMeta,\n aiInlineCompletionMeta,\n aiMessageMeta,\n aiModelSelectorMeta,\n aiPromptInputMeta,\n aiReasoningMeta,\n aiResponseMeta,\n aiSourcesMeta,\n aiStructuredOutputMeta,\n aiTokenUsageMeta,\n aiToolMeta,\n alertMeta,\n avatarMeta,\n badgeMeta,\n buttonMeta,\n calendarMeta,\n cardMeta,\n checkboxMeta,\n codeBlockMeta,\n comboboxMeta,\n commandMeta,\n dataTableMeta,\n datePickerMeta,\n dialogMeta,\n diffViewerMeta,\n drawerMeta,\n dropdownMenuMeta,\n emptyStateMeta,\n fileUploadMeta,\n formMeta,\n inputMeta,\n labelMeta,\n logViewerMeta,\n meterMeta,\n metricDeltaMeta,\n paginationMeta,\n popoverMeta,\n progressMeta,\n radioGroupMeta,\n recordDiffMeta,\n selectMeta,\n separatorMeta,\n sheetMeta,\n skeletonMeta,\n sliderMeta,\n spinnerMeta,\n switchMeta,\n tableMeta,\n tabsMeta,\n tagsInputMeta,\n timeRangePickerMeta,\n toastMeta,\n tooltipMeta,\n];\n\n// This file is the `@dowel-ui/react/registry` entry point, so the block barrel is\n// re-exported here — the registry build reads both through one import.\nexport { blockMetas } from \"./blocks\";\nexport { COMPONENT_CATEGORIES, COMPONENT_STATUSES } from \"./schema\";\nexport type { ComponentCategory, ComponentMeta, ComponentStatus } from \"./schema\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"components.js","names":["accordionMeta","activityFeedMeta","aiActionLedgerMeta","aiAgentPlanMeta","aiAgentStatusMeta","aiApprovalRequestMeta","aiConversationMeta","aiDisclosureMeta","aiExtractionReviewMeta","aiInlineCompletionMeta","aiMessageMeta","aiModelSelectorMeta","aiPromptInputMeta","aiReasoningMeta","aiResponseMeta","aiSourcesMeta","aiStructuredOutputMeta","aiSuggestedValueMeta","aiTokenUsageMeta","aiToolMeta","alertMeta","avatarMeta","badgeMeta","breadcrumbMeta","buttonMeta","calendarMeta","cardMeta","checkboxMeta","codeBlockMeta","collapsibleMeta","comboboxMeta","commandMeta","confirmTypedMeta","cronEditorMeta","dataTableMeta","datePickerMeta","dialogMeta","directionMeta","diffViewerMeta","dnsRecordMeta","drawerMeta","dropdownMenuMeta","emptyStateMeta","fileUploadMeta","formMeta","inputMeta","labelMeta","logViewerMeta","meterMeta","metricDeltaMeta","paginationMeta","permissionMatrixMeta","popoverMeta","progressMeta","radioGroupMeta","recordDiffMeta","secretFieldMeta","selectMeta","separatorMeta","sessionExpiryMeta","sheetMeta","sidebarMeta","shortcutRecorderMeta","skeletonMeta","sliderMeta","spinnerMeta","switchMeta","syncStatusMeta","tableMeta","tabsMeta","tagsInputMeta","timeRangePickerMeta","textareaMeta","toastMeta","tooltipMeta"],"sources":["../../src/registry/components.ts"],"sourcesContent":["import type { ComponentMeta } from \"./schema\";\n\nimport { meta as accordionMeta } from \"@/components/accordion/meta\";\nimport { meta as activityFeedMeta } from \"@/components/activity-feed/meta\";\nimport { meta as aiActionLedgerMeta } from \"@/components/ai-action-ledger/meta\";\nimport { meta as aiAgentPlanMeta } from \"@/components/ai-agent-plan/meta\";\nimport { meta as aiAgentStatusMeta } from \"@/components/ai-agent-status/meta\";\nimport { meta as aiApprovalRequestMeta } from \"@/components/ai-approval-request/meta\";\nimport { meta as aiConversationMeta } from \"@/components/ai-conversation/meta\";\nimport { meta as aiDisclosureMeta } from \"@/components/ai-disclosure/meta\";\nimport { meta as aiExtractionReviewMeta } from \"@/components/ai-extraction-review/meta\";\nimport { meta as aiInlineCompletionMeta } from \"@/components/ai-inline-completion/meta\";\nimport { meta as aiMessageMeta } from \"@/components/ai-message/meta\";\nimport { meta as aiModelSelectorMeta } from \"@/components/ai-model-selector/meta\";\nimport { meta as aiPromptInputMeta } from \"@/components/ai-prompt-input/meta\";\nimport { meta as aiReasoningMeta } from \"@/components/ai-reasoning/meta\";\nimport { meta as aiResponseMeta } from \"@/components/ai-response/meta\";\nimport { meta as aiSourcesMeta } from \"@/components/ai-sources/meta\";\nimport { meta as aiStructuredOutputMeta } from \"@/components/ai-structured-output/meta\";\nimport { meta as aiSuggestedValueMeta } from \"@/components/ai-suggested-value/meta\";\nimport { meta as aiTokenUsageMeta } from \"@/components/ai-token-usage/meta\";\nimport { meta as aiToolMeta } from \"@/components/ai-tool/meta\";\nimport { meta as alertMeta } from \"@/components/alert/meta\";\nimport { meta as avatarMeta } from \"@/components/avatar/meta\";\nimport { meta as badgeMeta } from \"@/components/badge/meta\";\nimport { meta as breadcrumbMeta } from \"@/components/breadcrumb/meta\";\nimport { meta as buttonMeta } from \"@/components/button/meta\";\nimport { meta as calendarMeta } from \"@/components/calendar/meta\";\nimport { meta as cardMeta } from \"@/components/card/meta\";\nimport { meta as checkboxMeta } from \"@/components/checkbox/meta\";\nimport { meta as codeBlockMeta } from \"@/components/code-block/meta\";\nimport { meta as collapsibleMeta } from \"@/components/collapsible/meta\";\nimport { meta as comboboxMeta } from \"@/components/combobox/meta\";\nimport { meta as commandMeta } from \"@/components/command/meta\";\nimport { meta as confirmTypedMeta } from \"@/components/confirm-typed/meta\";\nimport { meta as cronEditorMeta } from \"@/components/cron-editor/meta\";\nimport { meta as dataTableMeta } from \"@/components/data-table/meta\";\nimport { meta as datePickerMeta } from \"@/components/date-picker/meta\";\nimport { meta as directionMeta } from \"@/components/direction/meta\";\nimport { meta as dialogMeta } from \"@/components/dialog/meta\";\nimport { meta as diffViewerMeta } from \"@/components/diff-viewer/meta\";\nimport { meta as dnsRecordMeta } from \"@/components/dns-record/meta\";\nimport { meta as drawerMeta } from \"@/components/drawer/meta\";\nimport { meta as dropdownMenuMeta } from \"@/components/dropdown-menu/meta\";\nimport { meta as emptyStateMeta } from \"@/components/empty-state/meta\";\nimport { meta as fileUploadMeta } from \"@/components/file-upload/meta\";\nimport { meta as formMeta } from \"@/components/form/meta\";\nimport { meta as inputMeta } from \"@/components/input/meta\";\nimport { meta as labelMeta } from \"@/components/label/meta\";\nimport { meta as logViewerMeta } from \"@/components/log-viewer/meta\";\nimport { meta as meterMeta } from \"@/components/meter/meta\";\nimport { meta as metricDeltaMeta } from \"@/components/metric-delta/meta\";\nimport { meta as paginationMeta } from \"@/components/pagination/meta\";\nimport { meta as permissionMatrixMeta } from \"@/components/permission-matrix/meta\";\nimport { meta as popoverMeta } from \"@/components/popover/meta\";\nimport { meta as progressMeta } from \"@/components/progress/meta\";\nimport { meta as radioGroupMeta } from \"@/components/radio-group/meta\";\nimport { meta as recordDiffMeta } from \"@/components/record-diff/meta\";\nimport { meta as secretFieldMeta } from \"@/components/secret-field/meta\";\nimport { meta as selectMeta } from \"@/components/select/meta\";\nimport { meta as separatorMeta } from \"@/components/separator/meta\";\nimport { meta as sessionExpiryMeta } from \"@/components/session-expiry/meta\";\nimport { meta as sidebarMeta } from \"@/components/sidebar/meta\";\nimport { meta as sheetMeta } from \"@/components/sheet/meta\";\nimport { meta as shortcutRecorderMeta } from \"@/components/shortcut-recorder/meta\";\nimport { meta as skeletonMeta } from \"@/components/skeleton/meta\";\nimport { meta as sliderMeta } from \"@/components/slider/meta\";\nimport { meta as spinnerMeta } from \"@/components/spinner/meta\";\nimport { meta as switchMeta } from \"@/components/switch/meta\";\nimport { meta as syncStatusMeta } from \"@/components/sync-status/meta\";\nimport { meta as tableMeta } from \"@/components/table/meta\";\nimport { meta as tabsMeta } from \"@/components/tabs/meta\";\nimport { meta as tagsInputMeta } from \"@/components/tags-input/meta\";\nimport { meta as timeRangePickerMeta } from \"@/components/time-range-picker/meta\";\nimport { meta as textareaMeta } from \"@/components/textarea/meta\";\nimport { meta as toastMeta } from \"@/components/toast/meta\";\nimport { meta as tooltipMeta } from \"@/components/tooltip/meta\";\n\n/**\n * Every component in the registry.\n *\n * An explicit list rather than a glob: the registry build runs in plain Node,\n * where bundler-only globbing is unavailable, and a static list is also what\n * lets the bundle tree-shake. `meta.test.ts` fails if a component directory\n * exists that is missing from here, so it cannot silently fall out of date.\n *\n * Identifiers carry a `Meta` suffix because component names include reserved\n * words — `switch` cannot be a binding name.\n */\nexport const componentMetas: ComponentMeta[] = [\n accordionMeta,\n activityFeedMeta,\n aiActionLedgerMeta,\n aiAgentPlanMeta,\n aiAgentStatusMeta,\n aiApprovalRequestMeta,\n aiConversationMeta,\n aiDisclosureMeta,\n aiExtractionReviewMeta,\n aiInlineCompletionMeta,\n aiMessageMeta,\n aiModelSelectorMeta,\n aiPromptInputMeta,\n aiReasoningMeta,\n aiResponseMeta,\n aiSourcesMeta,\n aiStructuredOutputMeta,\n aiSuggestedValueMeta,\n aiTokenUsageMeta,\n aiToolMeta,\n alertMeta,\n avatarMeta,\n badgeMeta,\n breadcrumbMeta,\n buttonMeta,\n calendarMeta,\n cardMeta,\n checkboxMeta,\n codeBlockMeta,\n collapsibleMeta,\n comboboxMeta,\n commandMeta,\n confirmTypedMeta,\n cronEditorMeta,\n dataTableMeta,\n datePickerMeta,\n dialogMeta,\n directionMeta,\n diffViewerMeta,\n dnsRecordMeta,\n drawerMeta,\n dropdownMenuMeta,\n emptyStateMeta,\n fileUploadMeta,\n formMeta,\n inputMeta,\n labelMeta,\n logViewerMeta,\n meterMeta,\n metricDeltaMeta,\n paginationMeta,\n permissionMatrixMeta,\n popoverMeta,\n progressMeta,\n radioGroupMeta,\n recordDiffMeta,\n secretFieldMeta,\n selectMeta,\n separatorMeta,\n sessionExpiryMeta,\n sheetMeta,\n sidebarMeta,\n shortcutRecorderMeta,\n skeletonMeta,\n sliderMeta,\n spinnerMeta,\n switchMeta,\n syncStatusMeta,\n tableMeta,\n tabsMeta,\n tagsInputMeta,\n timeRangePickerMeta,\n textareaMeta,\n toastMeta,\n tooltipMeta,\n];\n\n// This file is the `@dowel-ui/react/registry` entry point, so the block barrel is\n// re-exported here — the registry build reads both through one import.\nexport { blockMetas } from \"./blocks\";\nexport { COMPONENT_CATEGORIES, COMPONENT_STATUSES } from \"./schema\";\nexport type { ComponentCategory, ComponentMeta, ComponentStatus } from \"./schema\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyFA,MAAa,iBAAkC;CAC7CA;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;CACAC;AACF"}
|
|
@@ -36,6 +36,14 @@ interface ComponentMeta {
|
|
|
36
36
|
files: string[];
|
|
37
37
|
/** Accessibility notes surfaced on the docs page. */
|
|
38
38
|
a11y?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the source is public.
|
|
41
|
+
*
|
|
42
|
+
* Omitted means `free`, and free is a promise: an item that has shipped
|
|
43
|
+
* installable without a licence stays that way. Marking an existing component
|
|
44
|
+
* `pro` breaks every project that already installs it.
|
|
45
|
+
*/
|
|
46
|
+
access?: "free" | "pro";
|
|
39
47
|
}
|
|
40
48
|
/** Identity helper that gives editors autocomplete inside `meta.ts`. */
|
|
41
49
|
declare function defineMeta<const T extends ComponentMeta>(meta: T): T;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/registry/schema.ts"],"mappings":";;;;;;;;;cASa;KAYD,4BAA4B;cAE3B;KAED,0BAA0B;UAErB;;EAEf;;;;;;;;EAQA;;EAEA;;EAEA;EACA,UAAU;EACV,QAAQ;;EAER;;EAEA;;EAEA;;EAEA;;;iBAIc,iBAAiB,UAAU,eAAe,MAAM,IAAI"}
|
|
1
|
+
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/registry/schema.ts"],"mappings":";;;;;;;;;cASa;KAYD,4BAA4B;cAE3B;KAED,0BAA0B;UAErB;;EAEf;;;;;;;;EAQA;;EAEA;;EAEA;EACA,UAAU;EACV,QAAQ;;EAER;;EAEA;;EAEA;;EAEA;;;;;;;;EAQA;;;iBAIc,iBAAiB,UAAU,eAAe,MAAM,IAAI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":[],"sources":["../../src/registry/schema.ts"],"sourcesContent":["/**\n * Registry metadata contract.\n *\n * Every component ships a `meta.ts` describing what the CLI must install\n * alongside it. This file defines the *type* only; `meta.test.ts` validates\n * every declaration against the source's real imports, so metadata cannot drift\n * from the code it describes. See docs/architecture/0003-registry-metadata.md.\n */\n\nexport const COMPONENT_CATEGORIES = [\n \"foundation\",\n \"display\",\n \"navigation\",\n \"overlay\",\n \"layout\",\n \"form\",\n \"feedback\",\n \"data\",\n \"ai\",\n] as const;\n\nexport type ComponentCategory = (typeof COMPONENT_CATEGORIES)[number];\n\nexport const COMPONENT_STATUSES = [\"stable\", \"beta\", \"experimental\"] as const;\n\nexport type ComponentStatus = (typeof COMPONENT_STATUSES)[number];\n\nexport interface ComponentMeta {\n /** Registry id. Must match the directory name and the CLI argument. */\n name: string;\n /**\n * What kind of registry entry this is.\n *\n * Components are the building blocks; blocks are whole sections assembled\n * from them. They install into different places and are browsed differently,\n * so the distinction is explicit rather than inferred from the category.\n */\n kind?: \"component\" | \"block\";\n /** Display name for docs and Storybook. */\n title: string;\n /** One sentence, used on listing pages and by `<cli> list`. */\n description: string;\n category: ComponentCategory;\n status: ComponentStatus;\n /** npm packages the source imports. Peer deps (react) are excluded. */\n dependencies: string[];\n /** Other registry components this one imports. */\n registryDependencies: string[];\n /** Files the CLI copies, relative to the component directory. */\n files: string[];\n /** Accessibility notes surfaced on the docs page. */\n a11y?: string;\n}\n\n/** Identity helper that gives editors autocomplete inside `meta.ts`. */\nexport function defineMeta<const T extends ComponentMeta>(meta: T): T {\n return meta;\n}\n"],"mappings":";;;;;;;;;AASA,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAIA,MAAa,qBAAqB;CAAC;CAAU;CAAQ;AAAc;;
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../src/registry/schema.ts"],"sourcesContent":["/**\n * Registry metadata contract.\n *\n * Every component ships a `meta.ts` describing what the CLI must install\n * alongside it. This file defines the *type* only; `meta.test.ts` validates\n * every declaration against the source's real imports, so metadata cannot drift\n * from the code it describes. See docs/architecture/0003-registry-metadata.md.\n */\n\nexport const COMPONENT_CATEGORIES = [\n \"foundation\",\n \"display\",\n \"navigation\",\n \"overlay\",\n \"layout\",\n \"form\",\n \"feedback\",\n \"data\",\n \"ai\",\n] as const;\n\nexport type ComponentCategory = (typeof COMPONENT_CATEGORIES)[number];\n\nexport const COMPONENT_STATUSES = [\"stable\", \"beta\", \"experimental\"] as const;\n\nexport type ComponentStatus = (typeof COMPONENT_STATUSES)[number];\n\nexport interface ComponentMeta {\n /** Registry id. Must match the directory name and the CLI argument. */\n name: string;\n /**\n * What kind of registry entry this is.\n *\n * Components are the building blocks; blocks are whole sections assembled\n * from them. They install into different places and are browsed differently,\n * so the distinction is explicit rather than inferred from the category.\n */\n kind?: \"component\" | \"block\";\n /** Display name for docs and Storybook. */\n title: string;\n /** One sentence, used on listing pages and by `<cli> list`. */\n description: string;\n category: ComponentCategory;\n status: ComponentStatus;\n /** npm packages the source imports. Peer deps (react) are excluded. */\n dependencies: string[];\n /** Other registry components this one imports. */\n registryDependencies: string[];\n /** Files the CLI copies, relative to the component directory. */\n files: string[];\n /** Accessibility notes surfaced on the docs page. */\n a11y?: string;\n /**\n * Whether the source is public.\n *\n * Omitted means `free`, and free is a promise: an item that has shipped\n * installable without a licence stays that way. Marking an existing component\n * `pro` breaks every project that already installs it.\n */\n access?: \"free\" | \"pro\";\n}\n\n/** Identity helper that gives editors autocomplete inside `meta.ts`. */\nexport function defineMeta<const T extends ComponentMeta>(meta: T): T {\n return meta;\n}\n"],"mappings":";;;;;;;;;AASA,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAIA,MAAa,qBAAqB;CAAC;CAAU;CAAQ;AAAc;;AAwCnE,SAAgB,WAA0C,MAAY;CACpE,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dowel-ui/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Source-first React components for SaaS and AI products —
|
|
5
|
+
"description": "Source-first React components for SaaS and AI products — 75 accessible components you install as code you own, not as a dependency.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"react",
|
|
8
8
|
"ui",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"files": [
|
|
40
40
|
"dist",
|
|
41
41
|
"src",
|
|
42
|
+
"!src/blocks",
|
|
42
43
|
"!src/**/*.test.ts",
|
|
43
44
|
"!src/**/*.test.tsx",
|
|
44
45
|
"!src/**/*.stories.tsx"
|
|
@@ -95,8 +96,8 @@
|
|
|
95
96
|
"vite": "8.2.2",
|
|
96
97
|
"vitest": "4.1.10",
|
|
97
98
|
"zod": "4.5.4",
|
|
98
|
-
"@dowel-ui/
|
|
99
|
-
"@dowel-ui/
|
|
99
|
+
"@dowel-ui/themes": "0.7.0",
|
|
100
|
+
"@dowel-ui/config": "0.7.0"
|
|
100
101
|
},
|
|
101
102
|
"scripts": {
|
|
102
103
|
"build": "tsdown",
|
|
@@ -37,7 +37,7 @@ export function AccordionTrigger({ className, children, ...props }: AccordionTri
|
|
|
37
37
|
<AccordionPrimitive.Trigger
|
|
38
38
|
data-slot="accordion-trigger"
|
|
39
39
|
className={cn(
|
|
40
|
-
"flex flex-1 items-start justify-between gap-4 py-4 text-
|
|
40
|
+
"flex flex-1 items-start justify-between gap-4 py-4 text-start text-sm font-medium",
|
|
41
41
|
"transition-colors duration-[var(--duration-fast)] hover:text-primary",
|
|
42
42
|
"disabled:pointer-events-none disabled:opacity-55",
|
|
43
43
|
"[&[data-state=open]>svg]:rotate-180",
|
|
@@ -29,7 +29,7 @@ export function ActivityItem({ className, last, ...props }: ActivityItemProps) {
|
|
|
29
29
|
"relative flex gap-3 pb-6 last:pb-0",
|
|
30
30
|
// The rail is a pseudo-element on the item, so it is decorative by
|
|
31
31
|
// construction rather than by remembering an aria-hidden.
|
|
32
|
-
"before:absolute before:top-7 before:bottom-1 before:
|
|
32
|
+
"before:absolute before:start-[0.6875rem] before:top-7 before:bottom-1 before:w-px before:bg-border",
|
|
33
33
|
"last:before:hidden data-[last]:before:hidden",
|
|
34
34
|
className,
|
|
35
35
|
)}
|
|
Binary file
|
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
useEffect,
|
|
5
|
+
useId,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
type ComponentPropsWithRef,
|
|
10
|
+
type KeyboardEvent,
|
|
11
|
+
type ReactNode,
|
|
12
|
+
} from "react";
|
|
13
|
+
|
|
14
|
+
import { disabledStyles, focusRing } from "@/lib/styles";
|
|
15
|
+
import { cn } from "@/lib/utils";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
evidenceOf,
|
|
19
|
+
isSourced,
|
|
20
|
+
segmentSource,
|
|
21
|
+
summarizeReview,
|
|
22
|
+
type ExtractionField,
|
|
23
|
+
type FieldDecision,
|
|
24
|
+
type SourceRun,
|
|
25
|
+
} from "./extraction-model";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The check after extraction: the document on one side, what the model read
|
|
29
|
+
* out of it on the other, and a decision about every field.
|
|
30
|
+
*
|
|
31
|
+
* Every extraction demo shows the filled object and stops. The products that
|
|
32
|
+
* run extraction for a living — invoice capture, KYC onboarding, claims intake —
|
|
33
|
+
* all have this screen, each built from scratch, because a value that cannot
|
|
34
|
+
* be checked can only be trusted, and nobody who is paying an invoice trusts a
|
|
35
|
+
* model that far. No component library ships it.
|
|
36
|
+
*
|
|
37
|
+
* The link is the component. Each field carries where in the source it was
|
|
38
|
+
* read from, quoted in text under the value as well as highlighted in the
|
|
39
|
+
* document, so a reviewer who cannot see the highlight still has the evidence.
|
|
40
|
+
* And a value with no evidence is said outright — "the model supplied this
|
|
41
|
+
* without evidence" — because that is the case a review exists to catch, and
|
|
42
|
+
* the one every filled-object view renders identically to a good value.
|
|
43
|
+
*
|
|
44
|
+
* Evidence is a text offset, not a bounding box. A language model reads text,
|
|
45
|
+
* and a text layer with offsets is what every OCR pipeline already yields.
|
|
46
|
+
* Boxes over a rendered page need page rendering, zoom and geometry, and are a
|
|
47
|
+
* different component; this one does not pretend at them.
|
|
48
|
+
*
|
|
49
|
+
* Decisions are controlled and the component writes nothing. It reports that
|
|
50
|
+
* a field was accepted as proposed, corrected from what was proposed, or
|
|
51
|
+
* rejected — a richer record than a form's submitted values, and the one an
|
|
52
|
+
* audit later needs — and leaves what to do with it to the application.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
export interface ExtractionReviewProps extends Omit<
|
|
56
|
+
ComponentPropsWithRef<"section">,
|
|
57
|
+
"children"
|
|
58
|
+
> {
|
|
59
|
+
/** What the model read. Every span indexes into it. */
|
|
60
|
+
source: string;
|
|
61
|
+
/** Names the source — "Invoice 4471.pdf, page 1". */
|
|
62
|
+
sourceLabel?: string;
|
|
63
|
+
/** What is being reviewed, as the heading. */
|
|
64
|
+
heading: string;
|
|
65
|
+
fields: ExtractionField[];
|
|
66
|
+
/** Per-field decisions, keyed by field name. Controlled. */
|
|
67
|
+
decisions?: Record<string, FieldDecision>;
|
|
68
|
+
/** Omit to render the review as a record rather than something to operate. */
|
|
69
|
+
onDecision?: (name: string, decision: FieldDecision) => void;
|
|
70
|
+
/** True while fields are still arriving. Missing values wait instead of reading as not found. */
|
|
71
|
+
streaming?: boolean;
|
|
72
|
+
/** Confidence below this is called low, in words. */
|
|
73
|
+
lowConfidenceBelow?: number;
|
|
74
|
+
children?: ReactNode;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function ExtractionReview({
|
|
78
|
+
className,
|
|
79
|
+
source,
|
|
80
|
+
sourceLabel = "Source",
|
|
81
|
+
heading,
|
|
82
|
+
fields,
|
|
83
|
+
decisions = {},
|
|
84
|
+
onDecision,
|
|
85
|
+
streaming = false,
|
|
86
|
+
lowConfidenceBelow = 0.7,
|
|
87
|
+
children,
|
|
88
|
+
...props
|
|
89
|
+
}: ExtractionReviewProps) {
|
|
90
|
+
const headingId = useId();
|
|
91
|
+
const [activeField, setActiveField] = useState<string | null>(null);
|
|
92
|
+
|
|
93
|
+
const runs = useMemo(() => segmentSource(source, fields), [source, fields]);
|
|
94
|
+
const summary = useMemo(
|
|
95
|
+
() => summarizeReview(source, fields, decisions),
|
|
96
|
+
[source, fields, decisions],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<section
|
|
101
|
+
data-slot="extraction-review"
|
|
102
|
+
data-complete={summary.complete || undefined}
|
|
103
|
+
aria-labelledby={headingId}
|
|
104
|
+
aria-busy={streaming || undefined}
|
|
105
|
+
className={cn("flex flex-col gap-3", className)}
|
|
106
|
+
{...props}
|
|
107
|
+
>
|
|
108
|
+
<div className="flex flex-wrap items-baseline justify-between gap-2">
|
|
109
|
+
<h3 id={headingId} className="text-sm font-medium">
|
|
110
|
+
{heading}
|
|
111
|
+
</h3>
|
|
112
|
+
{/* Live from the start and short, so each decision is followed by
|
|
113
|
+
where the review stands rather than by silence. Evidence gaps are
|
|
114
|
+
counted here too: they are the reason to read carefully, and worth
|
|
115
|
+
knowing before starting rather than discovering on field six. */}
|
|
116
|
+
<p
|
|
117
|
+
data-slot="extraction-review-summary"
|
|
118
|
+
aria-live="polite"
|
|
119
|
+
className="text-xs text-muted-foreground"
|
|
120
|
+
>
|
|
121
|
+
{streaming
|
|
122
|
+
? "Fields are still arriving"
|
|
123
|
+
: `${String(summary.reviewed)} of ${String(summary.total)} reviewed`}
|
|
124
|
+
{summary.unsourced.length > 0
|
|
125
|
+
? ` · ${String(summary.unsourced.length)} without evidence`
|
|
126
|
+
: null}
|
|
127
|
+
</p>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{children}
|
|
131
|
+
|
|
132
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
133
|
+
<SourcePanel
|
|
134
|
+
label={sourceLabel}
|
|
135
|
+
runs={runs}
|
|
136
|
+
active={activeField}
|
|
137
|
+
decisions={decisions}
|
|
138
|
+
/>
|
|
139
|
+
|
|
140
|
+
<ol data-slot="extraction-fields" className="m-0 flex list-none flex-col gap-3 p-0">
|
|
141
|
+
{fields.map((field) => (
|
|
142
|
+
<ReviewField
|
|
143
|
+
key={field.name}
|
|
144
|
+
field={field}
|
|
145
|
+
source={source}
|
|
146
|
+
decision={decisions[field.name]}
|
|
147
|
+
streaming={streaming}
|
|
148
|
+
lowConfidenceBelow={lowConfidenceBelow}
|
|
149
|
+
active={activeField === field.name}
|
|
150
|
+
onActivate={() => {
|
|
151
|
+
setActiveField(field.name);
|
|
152
|
+
}}
|
|
153
|
+
onDecision={onDecision}
|
|
154
|
+
/>
|
|
155
|
+
))}
|
|
156
|
+
</ol>
|
|
157
|
+
</div>
|
|
158
|
+
</section>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function SourcePanel({
|
|
163
|
+
label,
|
|
164
|
+
runs,
|
|
165
|
+
active,
|
|
166
|
+
decisions,
|
|
167
|
+
}: {
|
|
168
|
+
label: string;
|
|
169
|
+
runs: SourceRun[];
|
|
170
|
+
active: string | null;
|
|
171
|
+
decisions: Record<string, FieldDecision>;
|
|
172
|
+
}) {
|
|
173
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
174
|
+
|
|
175
|
+
// Bring the active field's evidence into view. Focus stays where it is —
|
|
176
|
+
// in the field — so a keyboard user is shown the source without being
|
|
177
|
+
// moved into it.
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (!active || !ref.current) return;
|
|
180
|
+
const mark = ref.current.querySelector(`mark[data-active]`);
|
|
181
|
+
mark?.scrollIntoView({ block: "nearest" });
|
|
182
|
+
}, [active]);
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div
|
|
186
|
+
ref={ref}
|
|
187
|
+
data-slot="extraction-source"
|
|
188
|
+
// A scrolling box has to be focusable to be scrolled by keyboard, and a
|
|
189
|
+
// focusable box needs a name.
|
|
190
|
+
role="region"
|
|
191
|
+
aria-label={label}
|
|
192
|
+
tabIndex={0}
|
|
193
|
+
// Sticks beside the fields on a wide screen, so the evidence for field
|
|
194
|
+
// nine is still in view when the reviewer reaches it.
|
|
195
|
+
className={cn(
|
|
196
|
+
"max-h-96 overflow-auto rounded-lg border border-border bg-muted/30 p-3 md:sticky md:top-0 md:self-start",
|
|
197
|
+
focusRing,
|
|
198
|
+
)}
|
|
199
|
+
>
|
|
200
|
+
{runs.length === 0 ? (
|
|
201
|
+
<p className="text-xs text-muted-foreground">No source text.</p>
|
|
202
|
+
) : (
|
|
203
|
+
<pre className="m-0 font-sans text-sm leading-relaxed break-words whitespace-pre-wrap">
|
|
204
|
+
{runs.map((run, index) =>
|
|
205
|
+
run.fields.length === 0 ? (
|
|
206
|
+
<span key={index}>{run.text}</span>
|
|
207
|
+
) : (
|
|
208
|
+
// A mark element, so the evidence survives as structure rather
|
|
209
|
+
// than only as a tint. No label is inserted into the text: a
|
|
210
|
+
// document read aloud with field names spliced into it is not
|
|
211
|
+
// the document, and the field already quotes its evidence.
|
|
212
|
+
<mark
|
|
213
|
+
key={index}
|
|
214
|
+
data-fields={run.fields.join(" ")}
|
|
215
|
+
data-active={active !== null && run.fields.includes(active) ? "" : undefined}
|
|
216
|
+
className={cn(
|
|
217
|
+
"rounded-[2px] text-inherit",
|
|
218
|
+
run.fields.every((name) => decisions[name]?.kind === "rejected")
|
|
219
|
+
? "bg-muted line-through decoration-muted-foreground"
|
|
220
|
+
: "bg-primary/15",
|
|
221
|
+
active !== null &&
|
|
222
|
+
run.fields.includes(active) &&
|
|
223
|
+
"bg-primary/30 ring-1 ring-primary ring-inset",
|
|
224
|
+
)}
|
|
225
|
+
>
|
|
226
|
+
{run.text}
|
|
227
|
+
</mark>
|
|
228
|
+
),
|
|
229
|
+
)}
|
|
230
|
+
</pre>
|
|
231
|
+
)}
|
|
232
|
+
</div>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Whitespace collapsed and cut short, for quoting evidence under a field. */
|
|
237
|
+
function quote(text: string, limit = 80): string {
|
|
238
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
239
|
+
return collapsed.length > limit ? `${collapsed.slice(0, limit - 1)}…` : collapsed;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function ReviewField({
|
|
243
|
+
field,
|
|
244
|
+
source,
|
|
245
|
+
decision,
|
|
246
|
+
streaming,
|
|
247
|
+
lowConfidenceBelow,
|
|
248
|
+
active,
|
|
249
|
+
onActivate,
|
|
250
|
+
onDecision,
|
|
251
|
+
}: {
|
|
252
|
+
field: ExtractionField;
|
|
253
|
+
source: string;
|
|
254
|
+
decision?: FieldDecision;
|
|
255
|
+
streaming: boolean;
|
|
256
|
+
lowConfidenceBelow: number;
|
|
257
|
+
active: boolean;
|
|
258
|
+
onActivate: () => void;
|
|
259
|
+
onDecision?: (name: string, decision: FieldDecision) => void;
|
|
260
|
+
}) {
|
|
261
|
+
const inputId = useId();
|
|
262
|
+
const evidenceId = useId();
|
|
263
|
+
const statusId = useId();
|
|
264
|
+
const confidenceId = useId();
|
|
265
|
+
|
|
266
|
+
// The reviewer's typing, kept apart from the model's value so the decision
|
|
267
|
+
// can say which is which.
|
|
268
|
+
const [draft, setDraft] = useState<string | null>(null);
|
|
269
|
+
|
|
270
|
+
const proposed = field.value ?? "";
|
|
271
|
+
const decided = decision && decision.kind !== "rejected" ? decision.value : undefined;
|
|
272
|
+
const current = draft ?? decided ?? proposed;
|
|
273
|
+
const edited = current !== proposed;
|
|
274
|
+
const changedSince = decided !== undefined && current !== decided;
|
|
275
|
+
|
|
276
|
+
const arriving = streaming && field.value === undefined;
|
|
277
|
+
const sourced = isSourced(source, field);
|
|
278
|
+
const evidence = sourced ? evidenceOf(source, field.span) : "";
|
|
279
|
+
const unsourced = !arriving && field.value !== undefined && !sourced;
|
|
280
|
+
|
|
281
|
+
const accept = () => {
|
|
282
|
+
onDecision?.(
|
|
283
|
+
field.name,
|
|
284
|
+
edited
|
|
285
|
+
? { kind: "corrected", value: current, proposed }
|
|
286
|
+
: { kind: "accepted", value: current },
|
|
287
|
+
);
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const onKeyDown = (event: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
291
|
+
if (event.key !== "Enter") return;
|
|
292
|
+
// Enter confirms an IME candidate before it means anything else. Without
|
|
293
|
+
// this, a reviewer typing a Japanese correction accepts a fragment of it.
|
|
294
|
+
if (event.nativeEvent.isComposing) return;
|
|
295
|
+
if (field.multiline && !(event.ctrlKey || event.metaKey)) return;
|
|
296
|
+
event.preventDefault();
|
|
297
|
+
accept();
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const status = arriving
|
|
301
|
+
? "Arriving"
|
|
302
|
+
: !decision
|
|
303
|
+
? "Not reviewed"
|
|
304
|
+
: decision.kind === "rejected"
|
|
305
|
+
? "Rejected"
|
|
306
|
+
: changedSince
|
|
307
|
+
? `Changed since it was ${decision.kind}`
|
|
308
|
+
: decision.kind === "accepted"
|
|
309
|
+
? "Accepted"
|
|
310
|
+
: decision.proposed
|
|
311
|
+
? `Corrected from “${quote(decision.proposed, 40)}”`
|
|
312
|
+
: "Supplied by the reviewer";
|
|
313
|
+
|
|
314
|
+
const low = field.confidence !== undefined && field.confidence < lowConfidenceBelow;
|
|
315
|
+
const percent =
|
|
316
|
+
field.confidence === undefined
|
|
317
|
+
? null
|
|
318
|
+
: new Intl.NumberFormat(undefined, { style: "percent", maximumFractionDigits: 0 }).format(
|
|
319
|
+
field.confidence,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
const describedBy = [evidenceId, statusId, percent !== null ? confidenceId : null]
|
|
323
|
+
.filter(Boolean)
|
|
324
|
+
.join(" ");
|
|
325
|
+
|
|
326
|
+
const controlClass = cn(
|
|
327
|
+
"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm",
|
|
328
|
+
edited && "border-warning",
|
|
329
|
+
focusRing,
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
return (
|
|
333
|
+
<li
|
|
334
|
+
data-slot="extraction-field"
|
|
335
|
+
data-field={field.name}
|
|
336
|
+
data-state={arriving ? "arriving" : (decision?.kind ?? "undecided")}
|
|
337
|
+
data-active={active || undefined}
|
|
338
|
+
data-unsourced={unsourced || undefined}
|
|
339
|
+
// Focus anywhere in the field — value, either button — is the reviewer
|
|
340
|
+
// looking at it, so the source follows without a separate step.
|
|
341
|
+
onFocus={onActivate}
|
|
342
|
+
className={cn(
|
|
343
|
+
"flex flex-col gap-1 rounded-lg border p-3",
|
|
344
|
+
active ? "border-primary" : "border-border",
|
|
345
|
+
decision?.kind === "rejected" && "bg-muted/40",
|
|
346
|
+
)}
|
|
347
|
+
>
|
|
348
|
+
<div className="flex flex-wrap items-baseline justify-between gap-2">
|
|
349
|
+
{onDecision && !arriving ? (
|
|
350
|
+
<label htmlFor={inputId} className="text-xs font-medium text-muted-foreground">
|
|
351
|
+
{field.label}
|
|
352
|
+
</label>
|
|
353
|
+
) : (
|
|
354
|
+
<span className="text-xs font-medium text-muted-foreground">{field.label}</span>
|
|
355
|
+
)}
|
|
356
|
+
{/* Status as a word, outside the label so editing never renames the
|
|
357
|
+
control under a screen reader user. */}
|
|
358
|
+
<span
|
|
359
|
+
id={statusId}
|
|
360
|
+
data-slot="extraction-field-status"
|
|
361
|
+
className={cn(
|
|
362
|
+
"text-xs",
|
|
363
|
+
decision?.kind === "rejected" ? "text-destructive" : "text-muted-foreground",
|
|
364
|
+
changedSince && "text-warning",
|
|
365
|
+
)}
|
|
366
|
+
>
|
|
367
|
+
{status}
|
|
368
|
+
</span>
|
|
369
|
+
</div>
|
|
370
|
+
|
|
371
|
+
{arriving ? (
|
|
372
|
+
<span
|
|
373
|
+
aria-hidden="true"
|
|
374
|
+
className="block h-8 w-full animate-pulse-soft rounded-md bg-muted"
|
|
375
|
+
/>
|
|
376
|
+
) : !onDecision ? (
|
|
377
|
+
<p className="rounded-md bg-muted px-2 py-1.5 text-sm break-words">
|
|
378
|
+
{current || <span className="text-muted-foreground">Empty</span>}
|
|
379
|
+
</p>
|
|
380
|
+
) : field.multiline ? (
|
|
381
|
+
<textarea
|
|
382
|
+
id={inputId}
|
|
383
|
+
rows={3}
|
|
384
|
+
value={current}
|
|
385
|
+
aria-describedby={describedBy}
|
|
386
|
+
onChange={(event) => {
|
|
387
|
+
setDraft(event.target.value);
|
|
388
|
+
}}
|
|
389
|
+
onKeyDown={onKeyDown}
|
|
390
|
+
className={cn(controlClass, "resize-none")}
|
|
391
|
+
/>
|
|
392
|
+
) : (
|
|
393
|
+
<input
|
|
394
|
+
id={inputId}
|
|
395
|
+
type="text"
|
|
396
|
+
value={current}
|
|
397
|
+
aria-describedby={describedBy}
|
|
398
|
+
onChange={(event) => {
|
|
399
|
+
setDraft(event.target.value);
|
|
400
|
+
}}
|
|
401
|
+
onKeyDown={onKeyDown}
|
|
402
|
+
className={controlClass}
|
|
403
|
+
/>
|
|
404
|
+
)}
|
|
405
|
+
|
|
406
|
+
{/* The evidence in text. This is the accessible path to the source, and
|
|
407
|
+
for a sighted reviewer it is the comparison itself — "1 March 2026"
|
|
408
|
+
beside "2026-03-01" is a normalisation, not an error, and only reads
|
|
409
|
+
that way with both in view. */}
|
|
410
|
+
<p
|
|
411
|
+
id={evidenceId}
|
|
412
|
+
data-slot="extraction-field-evidence"
|
|
413
|
+
className={cn("text-xs", unsourced ? "text-warning" : "text-muted-foreground")}
|
|
414
|
+
>
|
|
415
|
+
{arriving
|
|
416
|
+
? "Waiting for the model"
|
|
417
|
+
: sourced
|
|
418
|
+
? `In the source: “${quote(evidence)}”`
|
|
419
|
+
: field.value === undefined
|
|
420
|
+
? "The model found nothing for this field."
|
|
421
|
+
: "Not in the source — the model supplied this without evidence."}
|
|
422
|
+
</p>
|
|
423
|
+
|
|
424
|
+
{percent !== null ? (
|
|
425
|
+
<p
|
|
426
|
+
id={confidenceId}
|
|
427
|
+
data-slot="extraction-field-confidence"
|
|
428
|
+
data-low={low || undefined}
|
|
429
|
+
className={cn("text-xs", low ? "text-warning" : "text-muted-foreground")}
|
|
430
|
+
>
|
|
431
|
+
{low ? `Low confidence, ${percent} — worth checking` : `${percent} confidence`}
|
|
432
|
+
</p>
|
|
433
|
+
) : null}
|
|
434
|
+
|
|
435
|
+
{onDecision && !arriving ? (
|
|
436
|
+
<div className="mt-1 flex flex-wrap items-center gap-2">
|
|
437
|
+
<FieldButton
|
|
438
|
+
variant="primary"
|
|
439
|
+
aria-label={`${edited ? "Accept correction" : "Accept"} — ${field.label}`}
|
|
440
|
+
aria-pressed={
|
|
441
|
+
decision !== undefined && decision.kind !== "rejected" && !changedSince
|
|
442
|
+
}
|
|
443
|
+
onClick={accept}
|
|
444
|
+
>
|
|
445
|
+
{edited ? "Accept correction" : "Accept"}
|
|
446
|
+
</FieldButton>
|
|
447
|
+
<FieldButton
|
|
448
|
+
aria-label={`Reject — ${field.label}`}
|
|
449
|
+
aria-pressed={decision?.kind === "rejected"}
|
|
450
|
+
onClick={() => {
|
|
451
|
+
onDecision(field.name, { kind: "rejected" });
|
|
452
|
+
}}
|
|
453
|
+
>
|
|
454
|
+
Reject
|
|
455
|
+
</FieldButton>
|
|
456
|
+
{sourced ? (
|
|
457
|
+
<FieldButton
|
|
458
|
+
aria-label={`Show in source — ${field.label}`}
|
|
459
|
+
className="ms-auto"
|
|
460
|
+
onClick={onActivate}
|
|
461
|
+
>
|
|
462
|
+
Show in source
|
|
463
|
+
</FieldButton>
|
|
464
|
+
) : null}
|
|
465
|
+
</div>
|
|
466
|
+
) : null}
|
|
467
|
+
</li>
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function FieldButton({
|
|
472
|
+
className,
|
|
473
|
+
variant = "default",
|
|
474
|
+
...props
|
|
475
|
+
}: ComponentPropsWithRef<"button"> & { variant?: "default" | "primary" }) {
|
|
476
|
+
return (
|
|
477
|
+
<button
|
|
478
|
+
type="button"
|
|
479
|
+
className={cn(
|
|
480
|
+
"rounded-md border px-2.5 py-1 text-xs font-medium transition-colors",
|
|
481
|
+
variant === "primary" &&
|
|
482
|
+
"border-primary bg-primary text-primary-foreground hover:bg-primary-hover aria-pressed:bg-primary-active",
|
|
483
|
+
variant === "default" &&
|
|
484
|
+
"border-input bg-background hover:bg-accent hover:text-accent-foreground aria-pressed:bg-secondary aria-pressed:text-secondary-foreground",
|
|
485
|
+
focusRing,
|
|
486
|
+
disabledStyles,
|
|
487
|
+
className,
|
|
488
|
+
)}
|
|
489
|
+
{...props}
|
|
490
|
+
/>
|
|
491
|
+
);
|
|
492
|
+
}
|