@kerfjs/ui 5.0.0-beta.4 → 5.0.0-beta.41
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 +342 -108
- package/ai/application-ui-diagnostic-ids-v1.json +100 -0
- package/ai/application-ui-profile-sync.cjs +529 -0
- package/ai/application-ui-profile.d.mts +1 -0
- package/ai/application-ui-profile.d.ts +102 -0
- package/ai/application-ui-profile.defaults.json +41 -0
- package/ai/application-ui-profile.mjs +626 -0
- package/ai/application-ui-profile.schema.json +130 -0
- package/ai/catalog-authoring.json +25 -0
- package/ai/catalog-authoring.schema.json +61 -0
- package/ai/compile-time-contracts-v1.json +132 -0
- package/ai/compile-time-contracts-v1.schema.json +51 -0
- package/ai/component-catalog-extension-v2.d.ts +7 -0
- package/ai/component-catalog-extension-v2.schema.json +7 -0
- package/ai/component-catalog-extension.schema.json +79 -0
- package/ai/component-catalog-v2-overrides.json +496 -0
- package/ai/component-catalog-v2.d.ts +90 -0
- package/ai/component-catalog-v2.json +5678 -0
- package/ai/component-catalog-v2.schema.json +298 -0
- package/ai/component-catalog.json +2694 -417
- package/ai/component-catalog.schema.json +39 -0
- package/ai/public-api-signatures-v1.md +1591 -126
- package/ai/skill.md +140 -54
- package/ai/webawesome-jsx-signatures-v1.md +2 -1
- package/analyzer/cli.mjs +49 -0
- package/analyzer/index.d.mts +46 -0
- package/analyzer/index.mjs +1086 -0
- package/analyzer/report.schema.json +66 -0
- package/dist/app-tab.d.ts +15 -4
- package/dist/app-tab.js +3 -1
- package/dist/browser/app-tab.js +1 -0
- package/dist/browser/floating-toolbar.js +3 -0
- package/dist/browser/list-action-row.js +5 -0
- package/dist/browser/list-header.js +7 -0
- package/dist/browser/list-inset-control.js +3 -0
- package/dist/browser/list-inset-text.js +3 -0
- package/dist/browser/list-item.js +5 -0
- package/dist/browser/list.js +3 -0
- package/dist/browser/pane.js +3 -0
- package/dist/browser/row.js +3 -0
- package/dist/browser/segmented-control.js +1 -0
- package/dist/browser/select.js +1 -0
- package/dist/browser/skeleton.js +3 -0
- package/dist/browser/spacer.js +3 -0
- package/dist/browser/state-banner.js +1 -0
- package/dist/browser/sunken-panel.js +3 -0
- package/dist/browser/surface-scaffold.js +3 -0
- package/dist/browser/text.js +3 -0
- package/dist/browser/toolbar-text.js +1 -0
- package/dist/browser/value-table.js +1 -0
- package/dist/catalog-resources.d.ts +35 -0
- package/dist/catalog-resources.js +22 -0
- package/dist/catalog-resources.js.map +1 -0
- package/dist/catalog.d.ts +151 -0
- package/dist/catalog.js +396 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chunk-2TYUFZUC.js +22 -0
- package/dist/chunk-2TYUFZUC.js.map +1 -0
- package/dist/chunk-6NDBE2OK.js +32 -0
- package/dist/chunk-6NDBE2OK.js.map +1 -0
- package/dist/chunk-6WTETUZ6.js +21 -0
- package/dist/chunk-6WTETUZ6.js.map +1 -0
- package/dist/chunk-AQFWBG23.js +83 -0
- package/dist/chunk-AQFWBG23.js.map +1 -0
- package/dist/chunk-B6JYRX3P.js +51 -0
- package/dist/chunk-B6JYRX3P.js.map +1 -0
- package/dist/chunk-C34NZOLJ.js +53 -0
- package/dist/chunk-C34NZOLJ.js.map +1 -0
- package/dist/chunk-CAB6NQ2T.js +102 -0
- package/dist/chunk-CAB6NQ2T.js.map +1 -0
- package/dist/chunk-CK6P5AUK.js +136 -0
- package/dist/chunk-CK6P5AUK.js.map +1 -0
- package/dist/chunk-DAO2VFTT.js +129 -0
- package/dist/chunk-DAO2VFTT.js.map +1 -0
- package/dist/chunk-DEYOGDE7.js +141 -0
- package/dist/chunk-DEYOGDE7.js.map +1 -0
- package/dist/chunk-DYBPI5O2.js +25 -0
- package/dist/chunk-DYBPI5O2.js.map +1 -0
- package/dist/{chunk-TRNBHPNW.js → chunk-E34TE2ZI.js} +12 -8
- package/dist/chunk-E34TE2ZI.js.map +1 -0
- package/dist/chunk-EYALJQQD.js +25 -0
- package/dist/chunk-EYALJQQD.js.map +1 -0
- package/dist/chunk-I45QO2IZ.js +88 -0
- package/dist/chunk-I45QO2IZ.js.map +1 -0
- package/dist/chunk-I4V3UDSA.js +79 -0
- package/dist/chunk-I4V3UDSA.js.map +1 -0
- package/dist/chunk-OGTJNHRG.js +42 -0
- package/dist/chunk-OGTJNHRG.js.map +1 -0
- package/dist/chunk-OL4TC3U2.js +156 -0
- package/dist/chunk-OL4TC3U2.js.map +1 -0
- package/dist/chunk-OMSRSL3B.js +120 -0
- package/dist/chunk-OMSRSL3B.js.map +1 -0
- package/dist/chunk-R3EBGEAW.js +46 -0
- package/dist/chunk-R3EBGEAW.js.map +1 -0
- package/dist/chunk-SOK5EUF7.js +25 -0
- package/dist/chunk-SOK5EUF7.js.map +1 -0
- package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
- package/dist/chunk-SRSJO5QE.js.map +1 -0
- package/dist/chunk-T7DOWS6T.js +61 -0
- package/dist/chunk-T7DOWS6T.js.map +1 -0
- package/dist/chunk-TIGSG6BX.js +218 -0
- package/dist/chunk-TIGSG6BX.js.map +1 -0
- package/dist/chunk-UDHHKZWO.js +41 -0
- package/dist/chunk-UDHHKZWO.js.map +1 -0
- package/dist/{chunk-MQIZAD4A.js → chunk-UKKSMZYT.js} +76 -22
- package/dist/chunk-UKKSMZYT.js.map +1 -0
- package/dist/chunk-V6GQKOX2.js +39 -0
- package/dist/chunk-V6GQKOX2.js.map +1 -0
- package/dist/chunk-V6HCTCVD.js +46 -0
- package/dist/chunk-V6HCTCVD.js.map +1 -0
- package/dist/chunk-VDUJZF5G.js +515 -0
- package/dist/chunk-VDUJZF5G.js.map +1 -0
- package/dist/chunk-VXFGMDA7.js +31 -0
- package/dist/chunk-VXFGMDA7.js.map +1 -0
- package/dist/chunk-WN52USHV.js +115 -0
- package/dist/chunk-WN52USHV.js.map +1 -0
- package/dist/chunk-WSXUPSID.js +43 -0
- package/dist/chunk-WSXUPSID.js.map +1 -0
- package/dist/chunk-X5GRDQ7V.js +50 -0
- package/dist/chunk-X5GRDQ7V.js.map +1 -0
- package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
- package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
- package/dist/chunk-ZASJJMGV.js +17 -0
- package/dist/chunk-ZASJJMGV.js.map +1 -0
- package/dist/chunk-ZPWZIVI6.js +47 -0
- package/dist/chunk-ZPWZIVI6.js.map +1 -0
- package/dist/collapsible-panel.d.ts +77 -0
- package/dist/collapsible-panel.js +84 -0
- package/dist/collapsible-panel.js.map +1 -0
- package/dist/css-values.d.ts +75 -0
- package/dist/css-values.js +3 -0
- package/dist/css-values.js.map +1 -0
- package/dist/device-class.d.ts +62 -0
- package/dist/device-class.js +103 -0
- package/dist/device-class.js.map +1 -0
- package/dist/disclosure-arrow.js +1 -1
- package/dist/divider-sides-BzB6rphT.d.ts +6 -0
- package/dist/empty-state.d.ts +3 -2
- package/dist/empty-state.js +1 -1
- package/dist/flex-alignment-CF8NLj7i.d.ts +4 -0
- package/dist/floating-toolbar.d.ts +29 -0
- package/dist/floating-toolbar.js +3 -0
- package/dist/floating-toolbar.js.map +1 -0
- package/dist/index.d.ts +28 -14
- package/dist/index.js +34 -23
- package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +19 -8
- package/dist/list-action-row.js +7 -0
- package/dist/list-action-row.js.map +1 -0
- package/dist/list-header.d.ts +80 -0
- package/dist/list-header.js +9 -0
- package/dist/list-header.js.map +1 -0
- package/dist/list-inset-control.d.ts +20 -0
- package/dist/list-inset-control.js +3 -0
- package/dist/list-inset-control.js.map +1 -0
- package/dist/list-inset-text.d.ts +29 -0
- package/dist/list-inset-text.js +3 -0
- package/dist/list-inset-text.js.map +1 -0
- package/dist/list-item.d.ts +45 -0
- package/dist/list-item.js +7 -0
- package/dist/list-item.js.map +1 -0
- package/dist/list.d.ts +30 -0
- package/dist/list.js +5 -0
- package/dist/list.js.map +1 -0
- package/dist/loading-spinner.js +1 -1
- package/dist/nav-stack.d.ts +41 -0
- package/dist/nav-stack.js +6 -0
- package/dist/nav-stack.js.map +1 -0
- package/dist/pane.d.ts +50 -0
- package/dist/pane.js +4 -0
- package/dist/pane.js.map +1 -0
- package/dist/resizable-region.d.ts +21 -3
- package/dist/resizable-region.js +1 -1
- package/dist/row.d.ts +28 -0
- package/dist/row.js +5 -0
- package/dist/row.js.map +1 -0
- package/dist/segmented-control.d.ts +11 -8
- package/dist/segmented-control.js +3 -1
- package/dist/select-register.d.ts +5 -1
- package/dist/select-register.js +129 -1
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +34 -8
- package/dist/select.js +3 -1
- package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
- package/dist/skeleton.d.ts +25 -0
- package/dist/skeleton.js +4 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/spacer.d.ts +16 -0
- package/dist/spacer.js +4 -0
- package/dist/spacer.js.map +1 -0
- package/dist/split-view.d.ts +43 -0
- package/dist/split-view.js +82 -0
- package/dist/split-view.js.map +1 -0
- package/dist/state-banner.d.ts +11 -5
- package/dist/state-banner.js +3 -1
- package/dist/styles/app-tab.css +26 -0
- package/dist/styles/catalog.css +582 -0
- package/dist/styles/collapsible-panel.css +212 -0
- package/dist/styles/floating-toolbar.css +38 -0
- package/dist/styles/foundation.css +80 -0
- package/dist/styles/layout.css +2 -20
- package/dist/styles/list-action-row.css +224 -0
- package/dist/styles/list-header.css +224 -0
- package/dist/styles/list-inset-control.css +23 -0
- package/dist/styles/list-inset-text.css +30 -0
- package/dist/styles/list-item.css +171 -0
- package/dist/styles/list.css +118 -0
- package/dist/styles/nav-stack.css +141 -0
- package/dist/styles/pane.css +62 -0
- package/dist/styles/resizable-region.css +158 -0
- package/dist/styles/row.css +92 -0
- package/dist/styles/segmented-control.css +10 -7
- package/dist/styles/select.css +115 -2
- package/dist/styles/skeleton.css +31 -0
- package/dist/styles/spacer.css +11 -0
- package/dist/styles/split-view.css +35 -0
- package/dist/styles/state-banner.css +49 -10
- package/dist/styles/styles.css +10 -5
- package/dist/styles/sunken-panel.css +22 -0
- package/dist/styles/surface-scaffold.css +51 -0
- package/dist/styles/tab-bar.css +24 -0
- package/dist/styles/tab-scaffold.css +85 -0
- package/dist/styles/text.css +6 -0
- package/dist/styles/token-search-field.css +14 -2
- package/dist/styles/toolbar-control-group.css +235 -8
- package/dist/styles/toolbar-text.css +65 -2
- package/dist/styles/toolbar.css +47 -2
- package/dist/styles/webawesome.css +171 -0
- package/dist/styles/workbench.css +187 -0
- package/dist/sunken-panel.d.ts +20 -0
- package/dist/sunken-panel.js +3 -0
- package/dist/sunken-panel.js.map +1 -0
- package/dist/surface-scaffold.d.ts +26 -0
- package/dist/surface-scaffold.js +3 -0
- package/dist/surface-scaffold.js.map +1 -0
- package/dist/tab-bar.d.ts +24 -6
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +31 -0
- package/dist/tab-scaffold.js +51 -0
- package/dist/tab-scaffold.js.map +1 -0
- package/dist/text.d.ts +20 -0
- package/dist/text.js +3 -0
- package/dist/text.js.map +1 -0
- package/dist/token-search-field.d.ts +30 -13
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-control-group.d.ts +33 -7
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.d.ts +31 -4
- package/dist/toolbar-text.js +3 -1
- package/dist/toolbar.d.ts +10 -7
- package/dist/toolbar.js +1 -1
- package/dist/value-table.d.ts +7 -3
- package/dist/value-table.js +3 -1
- package/dist/webawesome.d.ts +1 -0
- package/dist/wire-catalog.d.ts +57 -0
- package/dist/wire-catalog.js +302 -0
- package/dist/wire-catalog.js.map +1 -0
- package/dist/wire-nav-stack.d.ts +18 -0
- package/dist/wire-nav-stack.js +228 -0
- package/dist/wire-nav-stack.js.map +1 -0
- package/dist/wire-resizable-regions.d.ts +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.d.ts +48 -0
- package/dist/wire-sidebar.js +147 -0
- package/dist/wire-sidebar.js.map +1 -0
- package/dist/wire-tab-bars.d.ts +19 -2
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-scaffold.d.ts +11 -0
- package/dist/wire-tab-scaffold.js +21 -0
- package/dist/wire-tab-scaffold.js.map +1 -0
- package/dist/wire-token-search-fields.d.ts +104 -4
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +44 -0
- package/dist/workbench.js +106 -0
- package/dist/workbench.js.map +1 -0
- package/docs/accessibility.md +155 -20
- package/docs/app-layouts.md +61 -0
- package/docs/catalog.md +364 -0
- package/docs/collapsible-panel.md +142 -0
- package/docs/component-contract.md +258 -28
- package/docs/component-integration.md +63 -0
- package/docs/component-selection.md +219 -57
- package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
- package/docs/design/templates/empty-state/filtered.svg +1 -0
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
- package/docs/design/templates/empty-state/with-action.svg +1 -0
- package/docs/design/templates/empty-state-dark.svg +1 -0
- package/docs/design/templates/empty-state.svg +1 -0
- package/docs/design/templates/list/compact-dark.svg +1 -0
- package/docs/design/templates/list/compact.svg +1 -0
- package/docs/design/templates/list/stack-dark.svg +1 -0
- package/docs/design/templates/list/stack.svg +1 -0
- package/docs/design/templates/list-action-row/default-dark.svg +1 -0
- package/docs/design/templates/list-action-row/default.svg +1 -0
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
- package/docs/design/templates/list-action-row/selected.svg +1 -0
- package/docs/design/templates/list-action-row-dark.svg +1 -0
- package/docs/design/templates/list-action-row.svg +1 -0
- package/docs/design/templates/list-dark.svg +1 -0
- package/docs/design/templates/list-header/action-dark.svg +1 -0
- package/docs/design/templates/list-header/action.svg +1 -0
- package/docs/design/templates/list-header/count-dark.svg +1 -0
- package/docs/design/templates/list-header/count.svg +1 -0
- package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
- package/docs/design/templates/list-header/inline-action.svg +1 -0
- package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
- package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
- package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
- package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
- package/docs/design/templates/list-header-dark.svg +1 -0
- package/docs/design/templates/list-header.svg +1 -0
- package/docs/design/templates/list-item/default-dark.svg +1 -0
- package/docs/design/templates/list-item/default.svg +1 -0
- package/docs/design/templates/list-item/multiline-dark.svg +1 -0
- package/docs/design/templates/list-item/multiline.svg +1 -0
- package/docs/design/templates/list-item/selected-dark.svg +1 -0
- package/docs/design/templates/list-item/selected.svg +1 -0
- package/docs/design/templates/list-item/trailing-dark.svg +1 -0
- package/docs/design/templates/list-item/trailing.svg +1 -0
- package/docs/design/templates/list-item-dark.svg +1 -0
- package/docs/design/templates/list-item.svg +1 -0
- package/docs/design/templates/list.svg +1 -0
- package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
- package/docs/design/templates/segmented-control/equal.svg +1 -0
- package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
- package/docs/design/templates/segmented-control/pill-small.svg +1 -0
- package/docs/design/templates/segmented-control-dark.svg +1 -0
- package/docs/design/templates/segmented-control.svg +1 -0
- package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
- package/docs/design/templates/skeleton/avatar.svg +1 -0
- package/docs/design/templates/skeleton/block-dark.svg +1 -0
- package/docs/design/templates/skeleton/block.svg +1 -0
- package/docs/design/templates/skeleton/lines-dark.svg +1 -0
- package/docs/design/templates/skeleton/lines.svg +1 -0
- package/docs/design/templates/skeleton-dark.svg +1 -0
- package/docs/design/templates/skeleton.svg +1 -0
- package/docs/design/templates/state-banner/danger-dark.svg +1 -0
- package/docs/design/templates/state-banner/danger.svg +1 -0
- package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
- package/docs/design/templates/state-banner/info-badge.svg +1 -0
- package/docs/design/templates/state-banner/info-dark.svg +1 -0
- package/docs/design/templates/state-banner/info.svg +1 -0
- package/docs/design/templates/state-banner/success-dark.svg +1 -0
- package/docs/design/templates/state-banner/success.svg +1 -0
- package/docs/design/templates/state-banner/warning-dark.svg +1 -0
- package/docs/design/templates/state-banner/warning.svg +1 -0
- package/docs/design/templates/state-banner-dark.svg +1 -0
- package/docs/design/templates/state-banner.svg +1 -0
- package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
- package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
- package/docs/design/templates/tab-bar-dark.svg +1 -0
- package/docs/design/templates/tab-bar.svg +1 -0
- package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
- package/docs/design/templates/token-search-field/empty.svg +1 -0
- package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
- package/docs/design/templates/token-search-field/tokens.svg +1 -0
- package/docs/design/templates/token-search-field-dark.svg +1 -0
- package/docs/design/templates/token-search-field.svg +1 -0
- package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
- package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
- package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
- package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
- package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
- package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group.svg +1 -0
- package/docs/design/templates/toolbar-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/default.svg +1 -0
- package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/large.svg +1 -0
- package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/small.svg +1 -0
- package/docs/design/templates/toolbar-text-dark.svg +1 -0
- package/docs/design/templates/toolbar-text.svg +1 -0
- package/docs/design/templates/toolbar.svg +1 -0
- package/docs/design/templates/value-table/details-dark.svg +1 -0
- package/docs/design/templates/value-table/details.svg +1 -0
- package/docs/design/templates/value-table-dark.svg +1 -0
- package/docs/design/templates/value-table.svg +1 -0
- package/docs/design/templates.md +128 -0
- package/docs/design-philosophy.md +33 -11
- package/docs/device-class.md +54 -0
- package/docs/examples/application-ui-profile.json +60 -0
- package/docs/examples/command-palette-adapter.tsx +68 -17
- package/docs/examples/component-catalog-extension-v2.json +80 -0
- package/docs/examples/component-catalog-extension.json +45 -0
- package/docs/layout.md +169 -38
- package/docs/nav-stack.md +77 -0
- package/docs/recipes.md +64 -16
- package/docs/split-view.md +55 -0
- package/docs/sunken-panel.md +53 -0
- package/docs/surface-scaffold.md +25 -0
- package/docs/tab-scaffold.md +52 -0
- package/docs/type-contracts.md +127 -0
- package/docs/ui-analyzer.md +118 -0
- package/docs/ui-doctor.md +91 -0
- package/docs/ui-evaluator.md +122 -0
- package/docs/ux-demo.md +29 -10
- package/docs/webawesome-theme.md +82 -8
- package/docs/workbench.md +123 -0
- package/doctor/cli.mjs +115 -0
- package/doctor/config.schema.json +68 -0
- package/doctor/eslint-diagnostics.d.mts +24 -0
- package/doctor/eslint-diagnostics.mjs +24 -0
- package/doctor/index.d.mts +116 -0
- package/doctor/index.mjs +1272 -0
- package/doctor/report.schema.json +118 -0
- package/evaluator/cli.mjs +89 -0
- package/evaluator/index.d.mts +90 -0
- package/evaluator/index.mjs +1138 -0
- package/evaluator/report.schema.json +152 -0
- package/llms.txt +260 -32
- package/package.json +205 -38
- package/traversal-exclusions.mjs +27 -0
- package/ux-demo/recipes/app-shell.tsx +223 -13
- package/ux-demo/recipes/collapsible-sidebar.tsx +230 -0
- package/ux-demo/recipes/compact-toolbar.tsx +116 -12
- package/ux-demo/recipes/composer-form.tsx +120 -19
- package/ux-demo/recipes/list-detail-dialog.tsx +205 -0
- package/ux-demo/recipes/list-workspace-states.tsx +176 -9
- package/ux-demo/recipes/loaders.ts +13 -4
- package/ux-demo/recipes/loading-inspector.tsx +191 -0
- package/ux-demo/recipes/mount-recipe.ts +31 -5
- package/ux-demo/recipes/navigation-sidebar.tsx +123 -11
- package/ux-demo/recipes/navigation-stack.tsx +121 -0
- package/ux-demo/recipes/recipes.css +125 -16
- package/ux-demo/recipes/types.ts +9 -1
- package/ux-demo/recipes/workspace-header.tsx +72 -3
- package/dist/browser/dialog-header.js +0 -5
- package/dist/browser/menu-action-row.js +0 -3
- package/dist/browser/menu-header.js +0 -5
- package/dist/browser/menu-item.js +0 -3
- package/dist/browser/page-header.js +0 -3
- package/dist/chunk-2PES33HS.js +0 -13
- package/dist/chunk-2PES33HS.js.map +0 -1
- package/dist/chunk-55DATV3A.js +0 -10
- package/dist/chunk-55DATV3A.js.map +0 -1
- package/dist/chunk-7BR3DO2A.js.map +0 -1
- package/dist/chunk-7LDCTU7D.js +0 -134
- package/dist/chunk-7LDCTU7D.js.map +0 -1
- package/dist/chunk-AQNKJRFH.js +0 -79
- package/dist/chunk-AQNKJRFH.js.map +0 -1
- package/dist/chunk-CTQKI2XL.js +0 -28
- package/dist/chunk-CTQKI2XL.js.map +0 -1
- package/dist/chunk-DAFFDO33.js +0 -14
- package/dist/chunk-DAFFDO33.js.map +0 -1
- package/dist/chunk-EGHL5S4P.js +0 -33
- package/dist/chunk-EGHL5S4P.js.map +0 -1
- package/dist/chunk-GY5WH7TO.js +0 -10
- package/dist/chunk-GY5WH7TO.js.map +0 -1
- package/dist/chunk-H5AGGVU5.js +0 -75
- package/dist/chunk-H5AGGVU5.js.map +0 -1
- package/dist/chunk-K3G72I6D.js +0 -24
- package/dist/chunk-K3G72I6D.js.map +0 -1
- package/dist/chunk-M5JRI6MN.js +0 -27
- package/dist/chunk-M5JRI6MN.js.map +0 -1
- package/dist/chunk-MBR3TYNL.js +0 -14
- package/dist/chunk-MBR3TYNL.js.map +0 -1
- package/dist/chunk-MFKMHK5W.js +0 -10
- package/dist/chunk-MFKMHK5W.js.map +0 -1
- package/dist/chunk-MQIZAD4A.js.map +0 -1
- package/dist/chunk-NPPD2A6O.js +0 -40
- package/dist/chunk-NPPD2A6O.js.map +0 -1
- package/dist/chunk-R6JHHBKQ.js +0 -19
- package/dist/chunk-R6JHHBKQ.js.map +0 -1
- package/dist/chunk-S3TPM2LP.js +0 -23
- package/dist/chunk-S3TPM2LP.js.map +0 -1
- package/dist/chunk-TRNBHPNW.js.map +0 -1
- package/dist/chunk-VHW5YNIB.js +0 -17
- package/dist/chunk-VHW5YNIB.js.map +0 -1
- package/dist/chunk-WVPYVDXY.js +0 -15
- package/dist/chunk-WVPYVDXY.js.map +0 -1
- package/dist/chunk-XZXRLY5Q.js +0 -33
- package/dist/chunk-XZXRLY5Q.js.map +0 -1
- package/dist/dialog-header.d.ts +0 -15
- package/dist/dialog-header.js +0 -5
- package/dist/dialog-header.js.map +0 -1
- package/dist/menu-action-row.js +0 -4
- package/dist/menu-action-row.js.map +0 -1
- package/dist/menu-header.d.ts +0 -41
- package/dist/menu-header.js +0 -6
- package/dist/menu-header.js.map +0 -1
- package/dist/menu-item.d.ts +0 -31
- package/dist/menu-item.js +0 -4
- package/dist/menu-item.js.map +0 -1
- package/dist/page-header.d.ts +0 -9
- package/dist/page-header.js +0 -3
- package/dist/page-header.js.map +0 -1
- package/dist/styles/dialog-header.css +0 -87
- package/dist/styles/menu-action-row.css +0 -160
- package/dist/styles/menu-header.css +0 -143
- package/dist/styles/menu-item.css +0 -123
- package/dist/styles/page-header.css +0 -33
- package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
package/docs/webawesome-theme.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
free components and the Kerf/Hot Sheet 2 design system.
|
|
5
5
|
|
|
6
6
|
```ts
|
|
7
|
-
import type {} from
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
7
|
+
import type {} from "@kerfjs/ui/webawesome";
|
|
8
|
+
import "@kerfjs/ui/webawesome.css";
|
|
9
|
+
import "@awesome.me/webawesome/dist/components/button/button.js";
|
|
10
|
+
import "@awesome.me/webawesome/dist/components/input/input.js";
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The type-only package import augments `kerfjs/jsx-runtime` with the 70
|
|
@@ -54,6 +54,80 @@ pointer targets. Override `--kui-wa-carousel-icon-size`,
|
|
|
54
54
|
`--kui-wa-carousel-dot-hit-size` on a carousel or containing scope when a
|
|
55
55
|
product needs different geometry.
|
|
56
56
|
|
|
57
|
+
Form fields carry the same content-item inset as the Kerf primitives: a 1px
|
|
58
|
+
border with 8px inside it (`--wa-form-control-border-width`,
|
|
59
|
+
`--wa-form-control-padding-block`, and `--wa-form-control-padding-inline` are set
|
|
60
|
+
to the `--kui-layout-item-border-width` / `--kui-layout-item-padding` values), so
|
|
61
|
+
a single-line control lands at the standard ~40px height and the value sits 9px
|
|
62
|
+
in from the field edge. Each field's top label is inset by that same border +
|
|
63
|
+
padding (9px) so it lines up with the value inside the field, and is styled
|
|
64
|
+
exactly like a `ListHeader` label — uppercase, `--kui-font-xs`, weight 650, quiet
|
|
65
|
+
foreground. This applies to every free field that exposes a top label
|
|
66
|
+
(`::part(form-control-label)` plus the Slider's `::part(label)`). OTP Input
|
|
67
|
+
exposes `label` instead of `form-control-label`; the theme gives it the same
|
|
68
|
+
uppercase 12px/650 treatment. Inline control labels (Checkbox, Switch) keep
|
|
69
|
+
their natural sentence case.
|
|
70
|
+
|
|
71
|
+
Known Date's field captions and bordered text-like field hints use the same 9px
|
|
72
|
+
inline inset, keeping secondary text aligned with the value rather than the
|
|
73
|
+
field's outer border. This covers Input, Known Date, Number Input, OTP Input,
|
|
74
|
+
Select, Textarea, and Time Input hints; unbordered group hints retain their own
|
|
75
|
+
natural geometry. OTP Input's label and hint both use the 9px field-text inset.
|
|
76
|
+
|
|
77
|
+
Checkbox Group and Radio Group option regions receive the shared 8px inline
|
|
78
|
+
outer inset through `::part(form-control-input)`. Unlike bordered fields, these
|
|
79
|
+
groups have no shell of their own, so the explicit margin places their controls
|
|
80
|
+
on the same content-item geometry without adding padding to each option. The
|
|
81
|
+
Color Picker trigger receives the same 8px inline outer inset because it also
|
|
82
|
+
has no bordered field shell. Slider's complete interactive region receives the
|
|
83
|
+
shared 8px logical inline outer inset through `::part(slider)`, keeping its
|
|
84
|
+
track, markers, references, and hint together without moving the label.
|
|
85
|
+
|
|
86
|
+
Non-field chrome follows explicit, overridable control, surface, and container
|
|
87
|
+
tiers:
|
|
88
|
+
|
|
89
|
+
- `--kui-wa-control-inset` defaults to the 8px content-item padding. It applies
|
|
90
|
+
to tabs, tree-item trailing content, tags, and dropdown items. Tree selection
|
|
91
|
+
also uses Kerf's 8px inline outer margin, so its background reads as an inset
|
|
92
|
+
list item instead of an edge-to-edge stripe. Buttons already consume the same
|
|
93
|
+
`--wa-form-control-padding-inline` 8px value at every size, so no extra part
|
|
94
|
+
override is needed.
|
|
95
|
+
- `--kui-wa-surface-margin` and `--kui-wa-surface-inset` default to 8px.
|
|
96
|
+
Accordion, Card, Details, Callout, and Include use the margin around their
|
|
97
|
+
complete surface and the inset within it. Accordion applies the outer margin
|
|
98
|
+
once to the group rather than separating connected items; Card's header,
|
|
99
|
+
body, and footer all receive the full inset.
|
|
100
|
+
- `--kui-wa-container-inset` defaults to the 16px homogeneous-group step. Tab
|
|
101
|
+
Panel retains this roomier tier for unframed panel content. Dialog body uses
|
|
102
|
+
the 8px surface inset, while its footer uses the 16px container inset so
|
|
103
|
+
content stays compact and the action group has a clearer boundary. These two
|
|
104
|
+
parts do not inherit the dialog's shared `--spacing` value.
|
|
105
|
+
|
|
106
|
+
Add `class="hide-actions"` to a `wa-dialog` when the dialog supplies its own
|
|
107
|
+
dismissal affordance and should omit Web Awesome's header action region. The
|
|
108
|
+
theme sets `display: none` on the directly exported `header-actions` part; it
|
|
109
|
+
does not attempt to chain `::part()` through the internal `dialog` and `header`
|
|
110
|
+
parts, which CSS shadow parts do not support.
|
|
111
|
+
|
|
112
|
+
Badge remains intentionally compact at Web Awesome's intrinsic `0.375em` block /
|
|
113
|
+
`0.625em` inline padding (4.5px / 7.5px at its default 12px text size): it is a
|
|
114
|
+
short status or count, not a content item. Breadcrumb has no bordered or filled
|
|
115
|
+
container, and Scroller delegates item chrome to its slotted children, so both
|
|
116
|
+
retain their upstream geometry. Web Awesome 3.12's free catalog has
|
|
117
|
+
`wa-dropdown-item`, but no `wa-menu-item`; the theme therefore styles the
|
|
118
|
+
supported dropdown item rather than carrying a dead selector.
|
|
119
|
+
|
|
120
|
+
Override a tier for a product scope after importing the theme:
|
|
121
|
+
|
|
122
|
+
```css
|
|
123
|
+
.roomy-editor {
|
|
124
|
+
--kui-wa-control-inset: 0.75rem;
|
|
125
|
+
--kui-wa-surface-margin: 0.75rem;
|
|
126
|
+
--kui-wa-surface-inset: 0.75rem;
|
|
127
|
+
--kui-wa-container-inset: 1.5rem;
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
57
131
|
Accordion, Details, Breadcrumb, and Kerf Select share
|
|
58
132
|
`--kui-disclosure-icon-scale` (default `.5`) so disclosure and traversal
|
|
59
133
|
chevrons keep the same visual weight. The Accordion and Details components
|
|
@@ -73,12 +147,12 @@ subtree, or for one instance after the theme import:
|
|
|
73
147
|
|
|
74
148
|
```css
|
|
75
149
|
:root {
|
|
76
|
-
--wa-tooltip-arrow-size: .375rem;
|
|
77
|
-
--kui-wa-popover-arrow-size: .375rem;
|
|
150
|
+
--wa-tooltip-arrow-size: 0.375rem;
|
|
151
|
+
--kui-wa-popover-arrow-size: 0.375rem;
|
|
78
152
|
}
|
|
79
153
|
|
|
80
154
|
.pointed-popover {
|
|
81
|
-
--arrow-size: .5rem;
|
|
155
|
+
--arrow-size: 0.5rem;
|
|
82
156
|
}
|
|
83
157
|
```
|
|
84
158
|
|
|
@@ -179,7 +253,7 @@ smallest subtree that needs a different identity:
|
|
|
179
253
|
:root {
|
|
180
254
|
--wa-color-brand-fill-loud: #7540a8;
|
|
181
255
|
--wa-color-focus: #7540a8;
|
|
182
|
-
--wa-form-control-border-radius: .5rem;
|
|
256
|
+
--wa-form-control-border-radius: 0.5rem;
|
|
183
257
|
}
|
|
184
258
|
|
|
185
259
|
.billing-workspace {
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Workbench
|
|
2
|
+
|
|
3
|
+
`@kerfjs/ui/workbench` is the Xcode-like multi-panel workspace: a collapsible
|
|
4
|
+
left rail, right rail, and bottom drawer around a central work area (any absent).
|
|
5
|
+
It generalizes the instant-width / sliding-content collapse used by the catalog
|
|
6
|
+
sidebar. One of the opt-in app layouts (see
|
|
7
|
+
[`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)); best on
|
|
8
|
+
desktop-class devices.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { Workbench } from "@kerfjs/ui/workbench";
|
|
12
|
+
import "@kerfjs/ui/workbench.css";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## State lives in the app
|
|
16
|
+
|
|
17
|
+
`Workbench` is declarative and the collapse is **pure CSS** — no wire. The app
|
|
18
|
+
owns each panel's `collapsed` flag (usually a signal) and toggles it; the panel
|
|
19
|
+
animates itself.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
const navCollapsed = signal(false);
|
|
23
|
+
|
|
24
|
+
<Workbench
|
|
25
|
+
id="studio"
|
|
26
|
+
label="Studio"
|
|
27
|
+
main={<Editor />}
|
|
28
|
+
leftRail={{
|
|
29
|
+
content: <Navigator />,
|
|
30
|
+
label: "Navigator",
|
|
31
|
+
collapsed: navCollapsed.value,
|
|
32
|
+
size: 280,
|
|
33
|
+
}}
|
|
34
|
+
rightRail={{
|
|
35
|
+
content: <Inspector />,
|
|
36
|
+
label: "Inspector",
|
|
37
|
+
collapsed: inspectorCollapsed.value,
|
|
38
|
+
}}
|
|
39
|
+
bottomDrawer={{
|
|
40
|
+
content: <Console />,
|
|
41
|
+
label: "Console",
|
|
42
|
+
collapsed: consoleCollapsed.value,
|
|
43
|
+
}}
|
|
44
|
+
/>;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Each `WorkbenchPanel` takes `content`, an optional `collapsed`, an optional
|
|
48
|
+
`size` (rail width or drawer height in px, overriding the CSS default —
|
|
49
|
+
`--kui-workbench-rail-width` 280px, `--kui-workbench-drawer-height` 220px), and
|
|
50
|
+
an optional `label`. Common shell behavior is configured rather than restyled:
|
|
51
|
+
|
|
52
|
+
- `separator: "auto" | "hidden"` controls the owned dock-edge separator;
|
|
53
|
+
- `collapseMotion: "slide" | "fade-slide" | "none"` keeps the track change
|
|
54
|
+
instant while choosing composited content motion;
|
|
55
|
+
- `contentOverflow: "clip" | "auto" | "visible"` lets a drawer temporarily
|
|
56
|
+
expose an open popup without a descendant override;
|
|
57
|
+
- `presentation: "inline" | "overlay" | "hidden"` supports compact overlays
|
|
58
|
+
or a responsive replacement. Overlay panels clamp both their track and fixed-size
|
|
59
|
+
animated content to the configured viewport-relative maximum;
|
|
60
|
+
- `restoreControl` places an application-owned restore affordance in a
|
|
61
|
+
safe-area-aware viewport corner (`restorePosition` chooses the corner).
|
|
62
|
+
|
|
63
|
+
The same policy props are available on `ResizableRegion` and
|
|
64
|
+
`CollapsiblePanel`, so a resizable application shell does not need to reach
|
|
65
|
+
into `.kui-resizable-region__content`.
|
|
66
|
+
|
|
67
|
+
## Resizable application-shell migration
|
|
68
|
+
|
|
69
|
+
An application such as Hot Sheet can replace its shell descendant overrides
|
|
70
|
+
with state-derived props:
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<ResizableRegion
|
|
74
|
+
id="terminal-drawer"
|
|
75
|
+
label="Terminal drawer"
|
|
76
|
+
axis="vertical"
|
|
77
|
+
edge="start"
|
|
78
|
+
size={drawerSize.value}
|
|
79
|
+
min={180}
|
|
80
|
+
max={520}
|
|
81
|
+
collapsed={!drawerVisible.value}
|
|
82
|
+
separator={magnified.value ? "hidden" : "auto"}
|
|
83
|
+
collapseMotion="fade-slide"
|
|
84
|
+
contentOverflow={createMenuOpen.value ? "visible" : "clip"}
|
|
85
|
+
presentation={mobile.value ? "overlay" : "inline"}
|
|
86
|
+
restoreControl={<button data-action="show-drawer">Show terminals</button>}
|
|
87
|
+
>
|
|
88
|
+
<TerminalDrawer />
|
|
89
|
+
</ResizableRegion>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`wireResizableRegions` marks the active region with `data-resizing` and the
|
|
93
|
+
package CSS suppresses content motion during pointer resize. A collapsed,
|
|
94
|
+
overlay, or hidden region is not resizeable. Together these policies replace
|
|
95
|
+
app CSS for separator suppression, instant-track/composited-content collapse,
|
|
96
|
+
popup overflow, mobile overlay/hidden replacement, resize-transition guards,
|
|
97
|
+
and safe-area restore placement. The app still owns the signals and decides
|
|
98
|
+
when each policy applies.
|
|
99
|
+
|
|
100
|
+
## Public styling boundary
|
|
101
|
+
|
|
102
|
+
Import `@kerfjs/ui/workbench.css` after the component subpath. Applications may
|
|
103
|
+
set `--kui-workbench-rail-width` and `--kui-workbench-drawer-height` on a
|
|
104
|
+
Workbench instance. The supported composition classes are `.kui-workbench`,
|
|
105
|
+
`.kui-workbench__rail`, `.kui-workbench__rail--left`,
|
|
106
|
+
`.kui-workbench__rail--right`, `.kui-workbench__center`,
|
|
107
|
+
`.kui-workbench__main`, `.kui-workbench__drawer`, and
|
|
108
|
+
`.kui-workbench__panel-content`, and `.kui-workbench__restore`; these exact hooks are cataloged for tools that
|
|
109
|
+
must classify public application selectors. Prefer the component props and two
|
|
110
|
+
size tokens before selecting internal anatomy, and do not target its data
|
|
111
|
+
attributes or descendant tags as styling contracts.
|
|
112
|
+
|
|
113
|
+
## How the collapse animates
|
|
114
|
+
|
|
115
|
+
Collapsing snaps the panel's flex track to zero in a single reflow (so the work
|
|
116
|
+
area relayouts once, not per frame) while the panel's fixed-size content slides
|
|
117
|
+
out via a composited `transform` — a rail slides horizontally, the drawer
|
|
118
|
+
vertically — clipped by the shell's overflow. The drawer content is positioned
|
|
119
|
+
against the shell's stable bottom edge, so opening and closing move monotonically
|
|
120
|
+
through the transform rather than inheriting a changing normal-flow origin. It
|
|
121
|
+
honors `prefers-reduced-motion` (the slide collapses to instant). On smaller
|
|
122
|
+
device classes, present the rails' contents through a `NavStack` or overlay
|
|
123
|
+
drawers rather than shrinking the three-panel shell.
|
package/doctor/cli.mjs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import console from 'node:console';
|
|
4
|
+
import { execFile } from 'node:child_process';
|
|
5
|
+
import { writeFile } from 'node:fs/promises';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
import process from 'node:process';
|
|
8
|
+
import { promisify } from 'node:util';
|
|
9
|
+
|
|
10
|
+
import { formatUiDoctorText, runUiDoctor, UI_DOCTOR_EXIT } from './index.mjs';
|
|
11
|
+
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const take = (name, repeat = false) => {
|
|
15
|
+
const values = [];
|
|
16
|
+
while (args.includes(name)) {
|
|
17
|
+
const index = args.indexOf(name);
|
|
18
|
+
const value = args[index + 1];
|
|
19
|
+
if (!value || value.startsWith('--'))
|
|
20
|
+
throw new Error(`${name} requires a value.`);
|
|
21
|
+
args.splice(index, 2);
|
|
22
|
+
values.push(value);
|
|
23
|
+
if (!repeat) break;
|
|
24
|
+
}
|
|
25
|
+
return repeat ? values : values[0];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
async function changedPaths(root) {
|
|
29
|
+
const { stdout: tracked } = await execFileAsync(
|
|
30
|
+
'git',
|
|
31
|
+
['diff', '--name-only', '--diff-filter=ACMR', 'HEAD', '--'],
|
|
32
|
+
{ cwd: root },
|
|
33
|
+
);
|
|
34
|
+
const { stdout: untracked } = await execFileAsync(
|
|
35
|
+
'git',
|
|
36
|
+
['ls-files', '--others', '--exclude-standard'],
|
|
37
|
+
{ cwd: root },
|
|
38
|
+
);
|
|
39
|
+
return [
|
|
40
|
+
...new Set(`${tracked}\n${untracked}`.split(/\r?\n/).filter(Boolean)),
|
|
41
|
+
].sort();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
46
|
+
console.log(`Usage: kerf-ui-doctor [--full | --changed] [options]
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
--root <path> Workspace root (default: current directory)
|
|
50
|
+
--package <name|path> Select one workspace package
|
|
51
|
+
--path <path> Restrict changed mode (repeatable)
|
|
52
|
+
--config <path> Doctor config (default: .kerf-ui-doctor.json)
|
|
53
|
+
--browser-url <url> Explicitly enable browser evaluation
|
|
54
|
+
--browser <list> Comma-separated chromium,firefox,webkit
|
|
55
|
+
--eslint <preset> recommended-ui or strict-ui
|
|
56
|
+
--format <format> text or json (default: text)
|
|
57
|
+
--output <path> Also write the merged report
|
|
58
|
+
--no-cache Disable the content-addressed cache
|
|
59
|
+
|
|
60
|
+
Exit codes: 0 clean, 1 findings, 2 configuration/tool failure, 130 cancelled.`);
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
const root = resolve(take('--root') ?? process.cwd());
|
|
64
|
+
const packageSelector = take('--package');
|
|
65
|
+
const explicitPaths = take('--path', true);
|
|
66
|
+
const configPath = take('--config');
|
|
67
|
+
const url = take('--browser-url');
|
|
68
|
+
const browserList = take('--browser');
|
|
69
|
+
const eslintConfig = take('--eslint') ?? 'recommended-ui';
|
|
70
|
+
const format = take('--format') ?? 'text';
|
|
71
|
+
const output = take('--output');
|
|
72
|
+
const full = args.includes('--full');
|
|
73
|
+
const changed = args.includes('--changed');
|
|
74
|
+
const noCache = args.includes('--no-cache');
|
|
75
|
+
const known = new Set(['--full', '--changed', '--no-cache']);
|
|
76
|
+
const unknown = args.filter((item) => !known.has(item));
|
|
77
|
+
if (unknown.length)
|
|
78
|
+
throw new Error(`Unknown arguments: ${unknown.join(' ')}`);
|
|
79
|
+
if (full && changed)
|
|
80
|
+
throw new Error('--full and --changed are mutually exclusive.');
|
|
81
|
+
if (!['text', 'json'].includes(format))
|
|
82
|
+
throw new Error('--format must be text or json.');
|
|
83
|
+
if (!['recommended-ui', 'strict-ui'].includes(eslintConfig))
|
|
84
|
+
throw new Error('--eslint must be recommended-ui or strict-ui.');
|
|
85
|
+
const abort = new globalThis.AbortController();
|
|
86
|
+
process.once('SIGINT', () => abort.abort());
|
|
87
|
+
const paths =
|
|
88
|
+
changed && !explicitPaths.length ? await changedPaths(root) : explicitPaths;
|
|
89
|
+
const report = await runUiDoctor({
|
|
90
|
+
root,
|
|
91
|
+
package: packageSelector,
|
|
92
|
+
mode: changed ? 'changed' : full ? 'full' : undefined,
|
|
93
|
+
paths,
|
|
94
|
+
configPath,
|
|
95
|
+
cache: !noCache,
|
|
96
|
+
signal: abort.signal,
|
|
97
|
+
eslintConfig,
|
|
98
|
+
browser: url
|
|
99
|
+
? { url, browsers: browserList?.split(',').map((item) => item.trim()) }
|
|
100
|
+
: undefined,
|
|
101
|
+
});
|
|
102
|
+
const rendered =
|
|
103
|
+
format === 'json'
|
|
104
|
+
? JSON.stringify(report, null, 2)
|
|
105
|
+
: formatUiDoctorText(report);
|
|
106
|
+
if (output) await writeFile(resolve(root, output), `${rendered}\n`);
|
|
107
|
+
else console.log(rendered);
|
|
108
|
+
process.exitCode = report.exitCode;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(`kerf-ui-doctor: ${error.message}`);
|
|
111
|
+
process.exitCode =
|
|
112
|
+
process.exitCode === UI_DOCTOR_EXIT.cancelled
|
|
113
|
+
? process.exitCode
|
|
114
|
+
: UI_DOCTOR_EXIT.configuration;
|
|
115
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/brianwestphal/kerf/main/ui/doctor/config.schema.json",
|
|
4
|
+
"title": "Kerf UI doctor configuration",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schemaVersion"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": { "type": "string" },
|
|
9
|
+
"schemaVersion": { "const": 1 },
|
|
10
|
+
"mode": { "enum": ["full", "changed"] },
|
|
11
|
+
"package": { "type": "string", "minLength": 1 },
|
|
12
|
+
"stages": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"catalog": { "type": "boolean" },
|
|
16
|
+
"typescript": { "type": "boolean" },
|
|
17
|
+
"eslint": { "type": "boolean" },
|
|
18
|
+
"analyzer": { "type": "boolean" },
|
|
19
|
+
"browser": { "type": "boolean" }
|
|
20
|
+
},
|
|
21
|
+
"additionalProperties": false
|
|
22
|
+
},
|
|
23
|
+
"browser": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": ["url"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"url": { "type": "string", "pattern": "^https?://" },
|
|
28
|
+
"browsers": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": { "enum": ["chromium", "firefox", "webkit"] },
|
|
31
|
+
"uniqueItems": true
|
|
32
|
+
},
|
|
33
|
+
"retention": { "enum": ["always", "on-failure", "never"] },
|
|
34
|
+
"outputDirectory": { "$ref": "#/$defs/path" },
|
|
35
|
+
"reportPath": { "$ref": "#/$defs/path" }
|
|
36
|
+
},
|
|
37
|
+
"additionalProperties": false
|
|
38
|
+
},
|
|
39
|
+
"cache": { "type": "boolean" },
|
|
40
|
+
"suppressions": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"required": ["id", "rules", "target", "rationale"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
|
|
47
|
+
"rules": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"items": { "type": "string", "minLength": 1 },
|
|
50
|
+
"minItems": 1,
|
|
51
|
+
"uniqueItems": true
|
|
52
|
+
},
|
|
53
|
+
"target": { "$ref": "#/$defs/path" },
|
|
54
|
+
"rationale": { "type": "string", "minLength": 12 }
|
|
55
|
+
},
|
|
56
|
+
"additionalProperties": false
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"additionalProperties": false,
|
|
61
|
+
"$defs": {
|
|
62
|
+
"path": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"minLength": 1,
|
|
65
|
+
"pattern": "^(?!/)(?!.*(^|/)\\.\\.(/|$))(?!.*[?*]).+"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface EslintDiagnosticLike {
|
|
2
|
+
ruleId?: string | null;
|
|
3
|
+
message: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function isForeignRuleDefinitionDiagnostic(
|
|
7
|
+
item: EslintDiagnosticLike,
|
|
8
|
+
): boolean;
|
|
9
|
+
|
|
10
|
+
export interface ConsumerEslintConfigLike {
|
|
11
|
+
rules?: Record<string, unknown>;
|
|
12
|
+
linterOptions?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ProjectedConsumerCoreConfig {
|
|
16
|
+
files: string[];
|
|
17
|
+
rules?: Record<string, unknown>;
|
|
18
|
+
linterOptions?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function projectConsumerCoreConfig(
|
|
22
|
+
config: ConsumerEslintConfigLike | undefined,
|
|
23
|
+
file: string,
|
|
24
|
+
): ProjectedConsumerCoreConfig | undefined;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function isForeignRuleDefinitionDiagnostic(item) {
|
|
2
|
+
return (
|
|
3
|
+
typeof item.ruleId === 'string' &&
|
|
4
|
+
!item.ruleId.startsWith('kerfjs/') &&
|
|
5
|
+
item.message === `Definition for rule '${item.ruleId}' was not found.`
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function projectConsumerCoreConfig(config, file) {
|
|
10
|
+
const rules = Object.fromEntries(
|
|
11
|
+
Object.entries(config?.rules ?? {}).filter(
|
|
12
|
+
([ruleId]) => !ruleId.includes('/'),
|
|
13
|
+
),
|
|
14
|
+
);
|
|
15
|
+
const linterOptions = config?.linterOptions
|
|
16
|
+
? { ...config.linterOptions }
|
|
17
|
+
: undefined;
|
|
18
|
+
if (Object.keys(rules).length === 0 && !linterOptions) return undefined;
|
|
19
|
+
return {
|
|
20
|
+
files: [file],
|
|
21
|
+
...(Object.keys(rules).length > 0 ? { rules } : {}),
|
|
22
|
+
...(linterOptions ? { linterOptions } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export type UiDoctorSeverity = 'error' | 'warning' | 'review' | 'info';
|
|
2
|
+
export type UiDoctorStageId =
|
|
3
|
+
| 'catalog'
|
|
4
|
+
| 'typescript'
|
|
5
|
+
| 'eslint'
|
|
6
|
+
| 'analyzer'
|
|
7
|
+
| 'browser'
|
|
8
|
+
| 'doctor'
|
|
9
|
+
| 'merged';
|
|
10
|
+
export type UiDoctorStageStatus =
|
|
11
|
+
'ran' | 'cached' | 'skipped' | 'unavailable' | 'failed' | 'cancelled';
|
|
12
|
+
|
|
13
|
+
export interface UiDoctorSuppression {
|
|
14
|
+
id: string;
|
|
15
|
+
rules: string[];
|
|
16
|
+
target: string;
|
|
17
|
+
rationale: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UiDoctorConfig {
|
|
21
|
+
$schema?: string;
|
|
22
|
+
schemaVersion: 1;
|
|
23
|
+
mode?: 'full' | 'changed';
|
|
24
|
+
package?: string;
|
|
25
|
+
stages?: Partial<
|
|
26
|
+
Record<
|
|
27
|
+
'catalog' | 'typescript' | 'eslint' | 'analyzer' | 'browser',
|
|
28
|
+
boolean
|
|
29
|
+
>
|
|
30
|
+
>;
|
|
31
|
+
browser?: {
|
|
32
|
+
url: string;
|
|
33
|
+
browsers?: Array<'chromium' | 'firefox' | 'webkit'>;
|
|
34
|
+
retention?: 'always' | 'on-failure' | 'never';
|
|
35
|
+
outputDirectory?: string;
|
|
36
|
+
reportPath?: string;
|
|
37
|
+
};
|
|
38
|
+
cache?: boolean;
|
|
39
|
+
suppressions?: UiDoctorSuppression[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface UiDoctorDiagnostic {
|
|
43
|
+
id: string;
|
|
44
|
+
severity: UiDoctorSeverity;
|
|
45
|
+
stage: UiDoctorStageId | string;
|
|
46
|
+
message: string;
|
|
47
|
+
location?: { file: string; line: number; column: number; path?: string };
|
|
48
|
+
dom?: { context?: string; selector: string };
|
|
49
|
+
evidence?: unknown;
|
|
50
|
+
catalogFacts?: unknown;
|
|
51
|
+
documentation?: string;
|
|
52
|
+
action?: string;
|
|
53
|
+
sources?: string[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface UiDoctorReport {
|
|
57
|
+
schemaVersion: 1;
|
|
58
|
+
tool: { name: '@kerfjs/ui/doctor'; reportVersion: 1 };
|
|
59
|
+
mode: 'full' | 'changed';
|
|
60
|
+
root: '.';
|
|
61
|
+
package: string;
|
|
62
|
+
paths: string[];
|
|
63
|
+
stages: Array<{ id: string; status: UiDoctorStageStatus; detail?: string }>;
|
|
64
|
+
diagnostics: UiDoctorDiagnostic[];
|
|
65
|
+
suppressions: Array<
|
|
66
|
+
UiDoctorDiagnostic & { suppression: { id: string; rationale: string } }
|
|
67
|
+
>;
|
|
68
|
+
summary: {
|
|
69
|
+
errors: number;
|
|
70
|
+
warnings: number;
|
|
71
|
+
review: number;
|
|
72
|
+
suppressed: number;
|
|
73
|
+
};
|
|
74
|
+
exitCode: 0 | 1 | 2 | 130;
|
|
75
|
+
cache: { hit: boolean; key: string };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const UI_DOCTOR_SCHEMA_VERSION: 1;
|
|
79
|
+
export const UI_DOCTOR_EXIT: Readonly<{
|
|
80
|
+
clean: 0;
|
|
81
|
+
findings: 1;
|
|
82
|
+
configuration: 2;
|
|
83
|
+
cancelled: 130;
|
|
84
|
+
}>;
|
|
85
|
+
export const UI_DOCTOR_RULES: Readonly<
|
|
86
|
+
Record<string, { severity: UiDoctorSeverity; title: string }>
|
|
87
|
+
>;
|
|
88
|
+
export function validateUiDoctorConfig(
|
|
89
|
+
config: unknown,
|
|
90
|
+
source?: string,
|
|
91
|
+
): UiDoctorDiagnostic[];
|
|
92
|
+
export function readUiDoctorConfig(
|
|
93
|
+
root: string,
|
|
94
|
+
path?: string,
|
|
95
|
+
): Promise<{
|
|
96
|
+
path: string;
|
|
97
|
+
config: UiDoctorConfig;
|
|
98
|
+
diagnostics: UiDoctorDiagnostic[];
|
|
99
|
+
}>;
|
|
100
|
+
export function resolveUiDoctorPackage(
|
|
101
|
+
root: string,
|
|
102
|
+
selector?: string,
|
|
103
|
+
): Promise<string>;
|
|
104
|
+
export function runUiDoctor(options?: {
|
|
105
|
+
root?: string;
|
|
106
|
+
package?: string;
|
|
107
|
+
mode?: 'full' | 'changed';
|
|
108
|
+
paths?: string[];
|
|
109
|
+
config?: UiDoctorConfig;
|
|
110
|
+
configPath?: string;
|
|
111
|
+
cache?: boolean;
|
|
112
|
+
signal?: AbortSignal;
|
|
113
|
+
browser?: UiDoctorConfig['browser'];
|
|
114
|
+
eslintConfig?: 'recommended-ui' | 'strict-ui';
|
|
115
|
+
}): Promise<UiDoctorReport>;
|
|
116
|
+
export function formatUiDoctorText(report: UiDoctorReport): string;
|