@kerfjs/ui 5.0.0-beta.97 → 5.0.0-beta.99
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 +42 -1
- package/ai/application-ui-diagnostic-ids-v1.json +1 -0
- package/ai/component-catalog.json +487 -66
- package/ai/component-catalog.schema.json +1 -1
- package/ai/component-composition-rules.json +22 -2
- package/ai/component-composition.json +360 -33
- package/ai/component-composition.schema.json +1 -1
- package/ai/components/README.md +18 -17
- package/ai/components/anchored-surface.md +13 -0
- package/ai/components/application-tabs.md +1 -1
- package/ai/components/chip.md +9 -5
- package/ai/components/choice-chips.md +15 -8
- package/ai/components/collapsible-panel.md +3 -2
- package/ai/components/composer.md +83 -0
- package/ai/components/content-item.md +2 -2
- package/ai/components/corner-status.md +1 -1
- package/ai/components/document-baseline.md +3 -3
- package/ai/components/foundation.md +2 -2
- package/ai/components/layout.md +1 -1
- package/ai/components/list-action-row.md +5 -1
- package/ai/components/list-item.md +5 -1
- package/ai/components/list.md +19 -3
- package/ai/components/nav-stack.md +11 -2
- package/ai/components/pane.md +13 -4
- package/ai/components/popup-menu.md +4 -4
- package/ai/components/recipe-app-shell.md +3 -3
- package/ai/components/recipe-collapsible-sidebar.md +3 -3
- package/ai/components/recipe-compact-toolbar.md +1 -1
- package/ai/components/recipe-composer-form.md +3 -3
- package/ai/components/recipe-list-detail-dialog.md +2 -2
- package/ai/components/recipe-list-workspace-states.md +3 -3
- package/ai/components/recipe-loading-inspector.md +1 -1
- package/ai/components/recipe-navigation-sidebar.md +3 -3
- package/ai/components/recipe-navigation-stack.md +3 -3
- package/ai/components/recipe-workspace-header.md +3 -3
- package/ai/components/resize.md +2 -2
- package/ai/components/split-view.md +4 -2
- package/ai/components/sunken-panel.md +2 -2
- package/ai/components/surface-scaffold.md +15 -3
- package/ai/components/tab-bar.md +1 -0
- package/ai/components/tab-navigator.md +4 -0
- package/ai/components/toolbar-control-group.md +2 -0
- package/ai/components/toolbar-text.md +1 -0
- package/ai/components/toolbar.md +1 -0
- package/ai/components/workbench.md +1 -0
- package/ai/public-api-signatures-v1.md +504 -80
- package/ai/skill.md +41 -14
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/component-ownership.mjs +1 -1
- package/analyzer/index.mjs +41 -14
- package/dist/anchored-surface.d.ts +30 -2
- package/dist/anchored-surface.js +1 -1
- package/dist/app-tab.js +1 -1
- package/dist/browser/composer.js +4 -0
- package/dist/catalog-resources.d.ts +3 -2
- package/dist/catalog-resources.js +4 -4
- package/dist/catalog-resources.js.map +1 -1
- package/dist/catalog.d.ts +39 -8
- package/dist/catalog.js +55 -32
- package/dist/catalog.js.map +1 -1
- package/dist/chip.d.ts +41 -9
- package/dist/chip.js +1 -1
- package/dist/choice-chips.d.ts +40 -16
- package/dist/choice-chips.js +1 -1
- package/dist/chunk-34U4ANDJ.js +119 -0
- package/dist/chunk-34U4ANDJ.js.map +1 -0
- package/dist/{chunk-36TL6BCR.js → chunk-3GLYIIFR.js} +34 -6
- package/dist/chunk-3GLYIIFR.js.map +1 -0
- package/dist/{chunk-HWY4BSLS.js → chunk-3VXDSIBJ.js} +2 -2
- package/dist/{chunk-HWY4BSLS.js.map → chunk-3VXDSIBJ.js.map} +1 -1
- package/dist/chunk-3WYREXW4.js +120 -0
- package/dist/chunk-3WYREXW4.js.map +1 -0
- package/dist/chunk-AV7CPAPT.js +82 -0
- package/dist/chunk-AV7CPAPT.js.map +1 -0
- package/dist/{chunk-XK4E225T.js → chunk-B53PS2LE.js} +2 -2
- package/dist/{chunk-XK4E225T.js.map → chunk-B53PS2LE.js.map} +1 -1
- package/dist/{chunk-R42D2BAO.js → chunk-CA7LNX3J.js} +2 -2
- package/dist/{chunk-R42D2BAO.js.map → chunk-CA7LNX3J.js.map} +1 -1
- package/dist/{chunk-AYHC62OZ.js → chunk-CMETHPKR.js} +26 -29
- package/dist/chunk-CMETHPKR.js.map +1 -0
- package/dist/{chunk-Y43B6DS3.js → chunk-CVD5IZGB.js} +2 -2
- package/dist/{chunk-Y43B6DS3.js.map → chunk-CVD5IZGB.js.map} +1 -1
- package/dist/{chunk-6STQXRT4.js → chunk-CXZXHZTR.js} +121 -12
- package/dist/chunk-CXZXHZTR.js.map +1 -0
- package/dist/{chunk-GZE2XVKC.js → chunk-DZJ4GBSP.js} +3 -3
- package/dist/{chunk-GZE2XVKC.js.map → chunk-DZJ4GBSP.js.map} +1 -1
- package/dist/chunk-ELCMSQNJ.js +49 -0
- package/dist/chunk-ELCMSQNJ.js.map +1 -0
- package/dist/{chunk-P74VXMB6.js → chunk-EOO6PYGF.js} +7 -14
- package/dist/chunk-EOO6PYGF.js.map +1 -0
- package/dist/{chunk-PRG4CL3Q.js → chunk-FR76ZJQC.js} +21 -19
- package/dist/chunk-FR76ZJQC.js.map +1 -0
- package/dist/{chunk-QQ3TTWFH.js → chunk-G3J7JDP6.js} +1 -1
- package/dist/{chunk-QQ3TTWFH.js.map → chunk-G3J7JDP6.js.map} +1 -1
- package/dist/{chunk-IGTWXPTN.js → chunk-HGV7J4T6.js} +3 -3
- package/dist/{chunk-IGTWXPTN.js.map → chunk-HGV7J4T6.js.map} +1 -1
- package/dist/{chunk-YWQGSUF2.js → chunk-HLDRH23D.js} +3 -3
- package/dist/{chunk-YWQGSUF2.js.map → chunk-HLDRH23D.js.map} +1 -1
- package/dist/{chunk-PBT3CPPY.js → chunk-HQZYKJ56.js} +24 -4
- package/dist/chunk-HQZYKJ56.js.map +1 -0
- package/dist/{chunk-V6W56V3N.js → chunk-HZPHCSCS.js} +16 -3
- package/dist/chunk-HZPHCSCS.js.map +1 -0
- package/dist/{chunk-GJYQ27C2.js → chunk-INI4WDWC.js} +8 -1
- package/dist/chunk-INI4WDWC.js.map +1 -0
- package/dist/{chunk-U657IHFB.js → chunk-IQSRHXZR.js} +10 -4
- package/dist/chunk-IQSRHXZR.js.map +1 -0
- package/dist/{chunk-KQDU7Z7P.js → chunk-K4AT3V3J.js} +2 -1
- package/dist/chunk-K4AT3V3J.js.map +1 -0
- package/dist/{chunk-QIAPOWHH.js → chunk-KCS6NJ3O.js} +2 -2
- package/dist/{chunk-QIAPOWHH.js.map → chunk-KCS6NJ3O.js.map} +1 -1
- package/dist/{chunk-UKKRPP56.js → chunk-LOSRXZAH.js} +2 -2
- package/dist/{chunk-UKKRPP56.js.map → chunk-LOSRXZAH.js.map} +1 -1
- package/dist/{chunk-ROZLJULF.js → chunk-MF6ZUUJZ.js} +8 -3
- package/dist/chunk-MF6ZUUJZ.js.map +1 -0
- package/dist/{chunk-6IVNMC6R.js → chunk-MHMWQ7RB.js} +2 -2
- package/dist/{chunk-6IVNMC6R.js.map → chunk-MHMWQ7RB.js.map} +1 -1
- package/dist/{chunk-JYD7G4RG.js → chunk-PIVY32AE.js} +15 -5
- package/dist/chunk-PIVY32AE.js.map +1 -0
- package/dist/{chunk-BU23Z5HZ.js → chunk-PYBBYSZ3.js} +13 -18
- package/dist/chunk-PYBBYSZ3.js.map +1 -0
- package/dist/chunk-QDSZTQXL.js +28 -0
- package/dist/chunk-QDSZTQXL.js.map +1 -0
- package/dist/{chunk-YXOMI7ES.js → chunk-QIG4IGUP.js} +2 -2
- package/dist/{chunk-YXOMI7ES.js.map → chunk-QIG4IGUP.js.map} +1 -1
- package/dist/{chunk-6BRRUPJY.js → chunk-QROYYGWU.js} +3 -3
- package/dist/chunk-QROYYGWU.js.map +1 -0
- package/dist/{chunk-FOQK4F3L.js → chunk-RHD7RKGI.js} +28 -7
- package/dist/chunk-RHD7RKGI.js.map +1 -0
- package/dist/{chunk-BBU2SPRE.js → chunk-T4WJ5VGP.js} +4 -4
- package/dist/{chunk-BBU2SPRE.js.map → chunk-T4WJ5VGP.js.map} +1 -1
- package/dist/{chunk-6NOLL5KG.js → chunk-TGLUDQP2.js} +3 -3
- package/dist/{chunk-6NOLL5KG.js.map → chunk-TGLUDQP2.js.map} +1 -1
- package/dist/{chunk-HO6FU3G7.js → chunk-TLMMFQWM.js} +4 -4
- package/dist/{chunk-HO6FU3G7.js.map → chunk-TLMMFQWM.js.map} +1 -1
- package/dist/chunk-UMKV7YVQ.js +20 -0
- package/dist/chunk-UMKV7YVQ.js.map +1 -0
- package/dist/{chunk-M2NRCFRO.js → chunk-VFYO3UGZ.js} +2 -2
- package/dist/{chunk-M2NRCFRO.js.map → chunk-VFYO3UGZ.js.map} +1 -1
- package/dist/{chunk-YOKEL75M.js → chunk-WVS6CUCT.js} +2 -2
- package/dist/{chunk-YOKEL75M.js.map → chunk-WVS6CUCT.js.map} +1 -1
- package/dist/{chunk-MN3POJFN.js → chunk-YMUIQRWK.js} +2 -2
- package/dist/{chunk-MN3POJFN.js.map → chunk-YMUIQRWK.js.map} +1 -1
- package/dist/{chunk-Y3LC7JQO.js → chunk-YOA5W5ZH.js} +2 -2
- package/dist/{chunk-Y3LC7JQO.js.map → chunk-YOA5W5ZH.js.map} +1 -1
- package/dist/{chunk-44A6LP54.js → chunk-YQ2AC4E2.js} +2 -2
- package/dist/{chunk-44A6LP54.js.map → chunk-YQ2AC4E2.js.map} +1 -1
- package/dist/chunk-ZNROKDSZ.js +54 -0
- package/dist/chunk-ZNROKDSZ.js.map +1 -0
- package/dist/collapsible-panel.d.ts +3 -2
- package/dist/collapsible-panel.js +4 -3
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/composer.d.ts +62 -0
- package/dist/composer.js +5 -0
- package/dist/composer.js.map +1 -0
- package/dist/corner-status.d.ts +1 -1
- package/dist/corner-status.js +1 -1
- package/dist/css-values.d.ts +9 -1
- package/dist/css-values.js +1 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/empty-state.js +1 -1
- package/dist/grid.js +1 -1
- package/dist/icon-button.js +1 -1
- package/dist/icon-toggle-button.js +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.js +40 -37
- package/dist/list-action-row.d.ts +10 -2
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.js +1 -1
- package/dist/list-icon-tile-B8dr97OW.d.ts +18 -0
- package/dist/list-item.d.ts +10 -3
- package/dist/list-item.js +1 -1
- package/dist/list.d.ts +36 -4
- package/dist/list.js +1 -1
- package/dist/loading-spinner.js +1 -1
- package/dist/lucide-icon.js +1 -1
- package/dist/{nav-stack-BvSKY448.d.ts → nav-stack-VXTumzKa.d.ts} +53 -4
- package/dist/nav-stack.d.ts +3 -2
- package/dist/nav-stack.js +2 -1
- package/dist/pane.d.ts +40 -3
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-CL9tYOkh.d.ts → panel-toolbar-vg6Ir5Dy.d.ts} +6 -1
- package/dist/popup-menu-register.d.ts +2 -1
- package/dist/popup-menu-register.js +97 -22
- package/dist/popup-menu-register.js.map +1 -1
- package/dist/popup-menu.js +1 -1
- package/dist/row.js +1 -1
- package/dist/scroll-clearance-BikHljTc.d.ts +14 -0
- package/dist/select-register.js +11 -0
- package/dist/select-register.js.map +1 -1
- package/dist/select.js +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-button.js +1 -1
- package/dist/split-view.d.ts +7 -5
- package/dist/split-view.js +6 -3
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.d.ts +6 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/anchored-surface.css +27 -1
- package/dist/styles/catalog/components/catalog-example-stack.css +5 -0
- package/dist/styles/catalog/components/catalog-example.css +33 -0
- package/dist/styles/catalog/components/catalog-stage.css +7 -0
- package/dist/styles/chip.css +70 -0
- package/dist/styles/components/actions/popup-menu/popup-menu.css +21 -4
- package/dist/styles/components/actions/toolbar/toolbar.css +19 -0
- package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +75 -1
- package/dist/styles/components/actions/toolbar-text/toolbar-text.css +75 -0
- package/dist/styles/components/collections/list/list.css +77 -7
- package/dist/styles/components/collections/list-action-row/list-action-row.css +177 -22
- package/dist/styles/components/collections/list-item/list-item.css +158 -11
- package/dist/styles/components/feedback/anchored-surface/anchored-surface.css +27 -1
- package/dist/styles/components/feedback/chip/chip.css +70 -0
- package/dist/styles/components/feedback/state-banner/state-banner.css +24 -13
- package/dist/styles/components/forms/composer/composer.css +100 -0
- package/dist/styles/components/forms/select/select.css +1 -0
- package/dist/styles/components/forms/token-search-field/token-search-field.css +13 -2
- package/dist/styles/components/layout/pane/pane.css +81 -2
- package/dist/styles/components/navigation/nav-stack/nav-stack.css +84 -0
- package/dist/styles/components/navigation/tab-bar/tab-bar.css +15 -4
- package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +79 -4
- package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +195 -0
- package/dist/styles/composer.css +100 -0
- package/dist/styles/foundation.css +66 -0
- package/dist/styles/list-action-row.css +177 -22
- package/dist/styles/list-item.css +158 -11
- package/dist/styles/list.css +77 -7
- package/dist/styles/nav-stack.css +84 -0
- package/dist/styles/pane.css +81 -2
- package/dist/styles/popup-menu.css +21 -4
- package/dist/styles/select.css +1 -0
- package/dist/styles/state-banner.css +24 -13
- package/dist/styles/styles.css +1 -0
- package/dist/styles/surface-scaffold.css +195 -0
- package/dist/styles/tab-bar.css +15 -4
- package/dist/styles/tab-navigator.css +79 -4
- package/dist/styles/token-search-field.css +13 -2
- package/dist/styles/toolbar-control-group.css +75 -1
- package/dist/styles/toolbar-text.css +75 -0
- package/dist/styles/toolbar.css +19 -0
- package/dist/styles/webawesome.css +18 -0
- package/dist/surface-scaffold-register.d.ts +6 -1
- package/dist/surface-scaffold-register.js +89 -3
- package/dist/surface-scaffold-register.js.map +1 -1
- package/dist/surface-scaffold.d.ts +66 -7
- package/dist/surface-scaffold.js +1 -1
- package/dist/tab-navigator.d.ts +23 -2
- package/dist/tab-navigator.js +2 -0
- package/dist/tab-navigator.js.map +1 -1
- package/dist/token-search-field.d.ts +1 -1
- package/dist/token-search-field.js +1 -1
- package/dist/{token-search-model-DTcTXWMS.d.ts → token-search-model-aYR0YAei.d.ts} +32 -2
- package/dist/token-search-model.d.ts +1 -1
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +1 -0
- package/dist/value-table.js +1 -1
- package/dist/wire-catalog.d.ts +3 -2
- package/dist/wire-catalog.js +2 -2
- package/dist/wire-composers.d.ts +16 -0
- package/dist/wire-composers.js +3 -0
- package/dist/wire-composers.js.map +1 -0
- package/dist/wire-list-focus-scroll.d.ts +16 -0
- package/dist/wire-list-focus-scroll.js +3 -0
- package/dist/wire-list-focus-scroll.js.map +1 -0
- package/dist/wire-nav-stack.js +135 -0
- package/dist/wire-nav-stack.js.map +1 -1
- package/dist/wire-scroll-dividers.d.ts +9 -0
- package/dist/wire-scroll-dividers.js +1 -1
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-navigator.d.ts +3 -1
- package/dist/wire-tab-navigator.js +133 -1
- package/dist/wire-tab-navigator.js.map +1 -1
- package/dist/wire-token-search-fields.d.ts +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +8 -3
- package/dist/workbench.js +2 -1
- package/docs/accessibility.md +132 -3
- package/docs/anchored-surface.md +46 -4
- package/docs/app-layouts.md +23 -2
- package/docs/apple-hig.md +1 -0
- package/docs/catalog.md +61 -9
- package/docs/collapsible-panel.md +9 -6
- package/docs/component-contract.md +46 -13
- package/docs/component-selection.md +147 -20
- package/docs/composer.md +143 -0
- package/docs/design/templates/choice-chips/multiple-dark.svg +1 -0
- package/docs/design/templates/choice-chips/multiple.svg +1 -0
- package/docs/design/templates/choice-chips-dark.svg +1 -1
- package/docs/design/templates/choice-chips.svg +1 -1
- package/docs/design/templates/composer/chat-dark.svg +1 -0
- package/docs/design/templates/composer/chat.svg +1 -0
- package/docs/design/templates/composer/prompt-dark.svg +1 -0
- package/docs/design/templates/composer/prompt.svg +1 -0
- package/docs/design/templates/composer-dark.svg +1 -0
- package/docs/design/templates/composer.svg +1 -0
- package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
- package/docs/design/templates/empty-state/filtered.svg +1 -1
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
- package/docs/design/templates/empty-state/with-action.svg +1 -1
- package/docs/design/templates/empty-state-dark.svg +1 -1
- package/docs/design/templates/empty-state.svg +1 -1
- package/docs/design/templates/list/compact-dark.svg +1 -1
- package/docs/design/templates/list/compact.svg +1 -1
- package/docs/design/templates/list-action-row/default-dark.svg +1 -1
- package/docs/design/templates/list-action-row/default.svg +1 -1
- package/docs/design/templates/list-action-row/icon-tile-dark.svg +1 -0
- package/docs/design/templates/list-action-row/icon-tile.svg +1 -0
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
- package/docs/design/templates/list-action-row/selected.svg +1 -1
- package/docs/design/templates/list-action-row/trailing-menu-dark.svg +1 -1
- package/docs/design/templates/list-action-row/trailing-menu.svg +1 -1
- package/docs/design/templates/list-action-row-dark.svg +1 -1
- package/docs/design/templates/list-action-row.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-header/size-l-dark.svg +1 -1
- package/docs/design/templates/list-header/size-l.svg +1 -1
- package/docs/design/templates/list-header/size-m-dark.svg +1 -1
- package/docs/design/templates/list-header/size-m.svg +1 -1
- package/docs/design/templates/list-header/size-xl-dark.svg +1 -1
- package/docs/design/templates/list-header/size-xl.svg +1 -1
- package/docs/design/templates/list-header-dark.svg +1 -1
- package/docs/design/templates/list-header.svg +1 -1
- package/docs/design/templates/list-item/icon-tile-dark.svg +1 -0
- package/docs/design/templates/list-item/icon-tile.svg +1 -0
- package/docs/design/templates/list-item/selected-dark.svg +1 -1
- package/docs/design/templates/list-item/selected.svg +1 -1
- package/docs/design/templates/list-item-dark.svg +1 -1
- package/docs/design/templates/list-item.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/segmented-control-dark.svg +1 -1
- package/docs/design/templates/segmented-control.svg +1 -1
- package/docs/design/templates/skeleton-dark.svg +1 -1
- package/docs/design/templates/skeleton.svg +1 -1
- package/docs/design/templates/state-banner/danger-dark.svg +1 -1
- package/docs/design/templates/state-banner/danger.svg +1 -1
- package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
- package/docs/design/templates/state-banner/info-badge.svg +1 -1
- package/docs/design/templates/state-banner/info-dark.svg +1 -1
- package/docs/design/templates/state-banner/info.svg +1 -1
- package/docs/design/templates/state-banner/strip-dark.svg +1 -1
- package/docs/design/templates/state-banner/strip.svg +1 -1
- package/docs/design/templates/state-banner/success-dark.svg +1 -1
- package/docs/design/templates/state-banner/success.svg +1 -1
- package/docs/design/templates/state-banner/warning-dark.svg +1 -1
- package/docs/design/templates/state-banner/warning.svg +1 -1
- package/docs/design/templates/state-banner-dark.svg +1 -1
- package/docs/design/templates/state-banner.svg +1 -1
- package/docs/design/templates/tab-bar-dark.svg +1 -1
- package/docs/design/templates/tab-bar.svg +1 -1
- package/docs/design/templates/token-search-field-dark.svg +1 -1
- package/docs/design/templates/token-search-field.svg +1 -1
- package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group.svg +1 -1
- package/docs/design/templates/toolbar-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/default.svg +1 -1
- package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/large.svg +1 -1
- package/docs/design/templates/toolbar-text-dark.svg +1 -1
- package/docs/design/templates/toolbar-text.svg +1 -1
- package/docs/design/templates/toolbar.svg +1 -1
- package/docs/design/templates/value-table/details-dark.svg +1 -1
- package/docs/design/templates/value-table/details.svg +1 -1
- package/docs/design/templates/value-table-dark.svg +1 -1
- package/docs/design/templates/value-table.svg +1 -1
- package/docs/design-philosophy.md +9 -1
- package/docs/examples/command-palette-adapter.tsx +3 -3
- package/docs/layout.md +147 -14
- package/docs/nav-stack.md +132 -8
- package/docs/recipes.md +9 -9
- package/docs/split-view.md +3 -3
- package/docs/sunken-panel.md +2 -2
- package/docs/surface-scaffold.md +138 -7
- package/docs/tab-navigator.md +38 -1
- package/docs/type-contracts.md +16 -16
- package/docs/ui-analyzer.md +3 -1
- package/docs/ui-doctor.md +71 -0
- package/docs/ux-demo.md +6 -6
- package/docs/webawesome-theme.md +7 -0
- package/docs/workbench.md +10 -6
- package/docs/writing.md +152 -0
- package/doctor/copy-capitalization-checks.mjs +591 -0
- package/doctor/index.mjs +17 -8
- package/llms.txt +105 -11
- package/package.json +15 -1
- package/ux-demo/recipes/app-shell.tsx +11 -11
- package/ux-demo/recipes/collapsible-sidebar.tsx +12 -11
- package/ux-demo/recipes/compact-toolbar.tsx +10 -10
- package/ux-demo/recipes/composer-form.tsx +8 -8
- package/ux-demo/recipes/list-detail-dialog.tsx +13 -13
- package/ux-demo/recipes/list-workspace-states.tsx +13 -13
- package/ux-demo/recipes/loading-inspector.tsx +10 -10
- package/ux-demo/recipes/navigation-sidebar.tsx +7 -7
- package/ux-demo/recipes/navigation-stack.tsx +5 -5
- package/ux-demo/recipes/workspace-header.tsx +5 -5
- package/dist/chunk-36TL6BCR.js.map +0 -1
- package/dist/chunk-4LOK4634.js +0 -21
- package/dist/chunk-4LOK4634.js.map +0 -1
- package/dist/chunk-6BRRUPJY.js.map +0 -1
- package/dist/chunk-6STQXRT4.js.map +0 -1
- package/dist/chunk-76PWEN5Y.js +0 -64
- package/dist/chunk-76PWEN5Y.js.map +0 -1
- package/dist/chunk-AYHC62OZ.js.map +0 -1
- package/dist/chunk-BU23Z5HZ.js.map +0 -1
- package/dist/chunk-DQDTZE4W.js +0 -70
- package/dist/chunk-DQDTZE4W.js.map +0 -1
- package/dist/chunk-FOQK4F3L.js.map +0 -1
- package/dist/chunk-GJYQ27C2.js.map +0 -1
- package/dist/chunk-JYD7G4RG.js.map +0 -1
- package/dist/chunk-KQDU7Z7P.js.map +0 -1
- package/dist/chunk-P74VXMB6.js.map +0 -1
- package/dist/chunk-PBT3CPPY.js.map +0 -1
- package/dist/chunk-PRG4CL3Q.js.map +0 -1
- package/dist/chunk-ROZLJULF.js.map +0 -1
- package/dist/chunk-U657IHFB.js.map +0 -1
- package/dist/chunk-V6W56V3N.js.map +0 -1
package/docs/layout.md
CHANGED
|
@@ -185,6 +185,62 @@ Firefox, scroll-state container queries only in Chromium, and neither lets
|
|
|
185
185
|
the pinned chrome — a sibling of the scroller — read the scroller's state on
|
|
186
186
|
its own. One wiring keeps the behavior identical in every engine.
|
|
187
187
|
|
|
188
|
+
### Overlay header
|
|
189
|
+
|
|
190
|
+
`headerPresentation="overlay"` lays a Pane's header over the top of its
|
|
191
|
+
scrolling content instead of giving it its own row, the way platform
|
|
192
|
+
navigation bars let content scroll visibly beneath a translucent bar:
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
<Pane
|
|
196
|
+
label="Inbox"
|
|
197
|
+
headerPresentation="overlay"
|
|
198
|
+
header={<Toolbar label="Inbox" leading={<ToolbarText text="Inbox" size="xlarge" />} />}
|
|
199
|
+
>
|
|
200
|
+
{messages}
|
|
201
|
+
</Pane>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The header paints the shared chrome material, `--kui-chrome-material` (the
|
|
205
|
+
surface at 80% opacity) behind `--kui-chrome-material-filter` (a blur and
|
|
206
|
+
saturation backdrop filter), so content passing beneath it reads as softened
|
|
207
|
+
color, not as competing text. The material becomes the opaque surface under
|
|
208
|
+
`prefers-reduced-transparency: reduce` or `prefers-contrast: more`, and where
|
|
209
|
+
the browser lacks `backdrop-filter`. In forced colors the header paints
|
|
210
|
+
`Canvas` with a `CanvasText` bottom edge.
|
|
211
|
+
|
|
212
|
+
`wireScrollDividers` measures each overlay header (its border-box height,
|
|
213
|
+
safe-area padding included) with a `ResizeObserver` and publishes it on the
|
|
214
|
+
Pane as the `--kui-scroll-clearance-block-start` context (see
|
|
215
|
+
[Scroll clearance](#scroll-clearance)). The Pane's content clears it
|
|
216
|
+
automatically, with no `scrollClearance` prop. At rest the first item sits just
|
|
217
|
+
below the header. Mid-scroll, content passes beneath it, and anything focused
|
|
218
|
+
or scrolled into view still comes to rest clear of it. The clearance follows
|
|
219
|
+
the header as its title wraps or its text grows. The header draws its scroll
|
|
220
|
+
divider as a docked header does, once content is scrolled beneath it. The
|
|
221
|
+
wiring also marks the Pane `data-header-overlay="measured"`, and only then
|
|
222
|
+
does the header move over the content. Until the wiring runs, the header stays
|
|
223
|
+
docked in its own row, so it can never cover content it has not measured. A
|
|
224
|
+
re-render that drops the measurement gets it back before paint.
|
|
225
|
+
|
|
226
|
+
The overlay needs pinned chrome. With `chromePlacement="auto"`, the header
|
|
227
|
+
stays docked. `PaneConfig` carries `headerPresentation`, so a Workbench
|
|
228
|
+
`mainPane` or panel `pane`, a `CollapsiblePanel` `pane`, or a `NavStack` view's
|
|
229
|
+
`pane` can lay its header over its content the same way. Overlay-header text
|
|
230
|
+
must stay at AA over whatever passes beneath: an untoned `ToolbarText` there
|
|
231
|
+
takes the normal text color for its title and lifts its `description` toward
|
|
232
|
+
it, and other quiet secondary copy belongs in the content (see
|
|
233
|
+
[Accessibility › Chrome material](accessibility.md#chrome-material)).
|
|
234
|
+
|
|
235
|
+
An overlay scrollbar (macOS by default) passes beneath the header like the
|
|
236
|
+
content. A classic, space-taking scrollbar (Windows and Linux, or macOS with
|
|
237
|
+
"always show scrollbars") stays uncovered: the wiring also measures the
|
|
238
|
+
content's vertical scrollbar (`offsetWidth` beyond `clientWidth`) and publishes
|
|
239
|
+
its inline size on the Pane as `--kui-pane-scrollbar-inline-size`, and the
|
|
240
|
+
header ends where the scrollbar's track begins, so its thumb and arrow buttons
|
|
241
|
+
remain visible and usable. The measurement follows the scrollbar as content
|
|
242
|
+
starts or stops overflowing.
|
|
243
|
+
|
|
188
244
|
A pane is safe-area aware. Its background and separators paint through a
|
|
189
245
|
device's unsafe areas while its header, content, and footer pad for each side
|
|
190
246
|
the pane still reaches; the content's block insets are scroll padding, so its
|
|
@@ -313,19 +369,24 @@ component's context stays allowed (see `KUI-L019`).
|
|
|
313
369
|
|
|
314
370
|
## Public roles and tokens
|
|
315
371
|
|
|
316
|
-
| Need | Class
|
|
317
|
-
| ---------------------------------------- |
|
|
318
|
-
| Unpadded header/content/footer structure | `Pane`, `.kui-pane`
|
|
319
|
-
| Scrolling pane content | `.kui-pane__content`
|
|
320
|
-
| Optional logical-edge separators | `Pane.separators`
|
|
321
|
-
| Safe-area sides a pane may pad | `Pane.safeAreaEdges`
|
|
322
|
-
|
|
|
323
|
-
|
|
|
324
|
-
|
|
|
325
|
-
|
|
|
326
|
-
|
|
|
327
|
-
|
|
|
328
|
-
|
|
|
372
|
+
| Need | Class | Token / default |
|
|
373
|
+
| ---------------------------------------- | ------------------------------------ | ------------------------------------------------------------------ |
|
|
374
|
+
| Unpadded header/content/footer structure | `Pane`, `.kui-pane` | — |
|
|
375
|
+
| Scrolling pane content | `.kui-pane__content` | — |
|
|
376
|
+
| Optional logical-edge separators | `Pane.separators` | `--kui-pane-separator-width: 1px` |
|
|
377
|
+
| Safe-area sides a pane may pad | `Pane.safeAreaEdges` | `--kui-safe-area-*: env(safe-area-inset-*)`, routed by each layout |
|
|
378
|
+
| Header laid over scrolling content | `Pane.headerPresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
|
|
379
|
+
| Dialog title bar laid over its body | `DialogSurface.headerPresentation` | `--kui-chrome-material-raised`, `--kui-chrome-material-filter` |
|
|
380
|
+
| Stack top bar laid over the active view | `NavStack.chromePresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
|
|
381
|
+
| Stack bottom toolbar laid over the view | `NavStack.bottomToolbarPresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
|
|
382
|
+
| Tab bar laid over the active scene | `TabNavigator.barPresentation` | `--kui-chrome-material`, `--kui-chrome-material-filter` |
|
|
383
|
+
| Major vertical rhythm | `.kui-content` | `--kui-layout-content-gap: 24px` |
|
|
384
|
+
| Self-contained child geometry | `ContentItem` | 8px margin + 1px border + 8px padding |
|
|
385
|
+
| Pill child | `ContentItem shape="pill"` | `--kui-layout-pill-radius: 22px` |
|
|
386
|
+
| Visibly framed child | `ContentItem frame="framed"` | neutral 1px border, same geometry |
|
|
387
|
+
| Related controls | `.kui-control-cluster` | `--kui-layout-control-gap: 8px` |
|
|
388
|
+
| Inline metadata | `.kui-inline-metadata` | `--kui-layout-metadata-gap: 4px` |
|
|
389
|
+
| Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
|
|
329
390
|
|
|
330
391
|
The component layer applies the same contract to `Toolbar`, `ListHeader`,
|
|
331
392
|
`ListItem`, `Toolbar`, `StateBanner`, `ValueTable`,
|
|
@@ -409,7 +470,7 @@ import { FieldLabel } from "@kerfjs/ui/text";
|
|
|
409
470
|
|
|
410
471
|
<div role="group" aria-labelledby="needed-by-label">
|
|
411
472
|
<ListInsetControl sides="trl">
|
|
412
|
-
<FieldLabel id="needed-by-label">Needed
|
|
473
|
+
<FieldLabel id="needed-by-label">Needed By</FieldLabel>
|
|
413
474
|
</ListInsetControl>
|
|
414
475
|
<ContentItem>October 16, 2026</ContentItem>
|
|
415
476
|
</div>;
|
|
@@ -646,6 +707,78 @@ When it has focus it draws the theme focus ring inset by the ring width and
|
|
|
646
707
|
rounded with `--kui-radius-m`, so a rounded or `overflow: hidden` parent
|
|
647
708
|
never clips it. Do not style `.kui-list` focus yourself.
|
|
648
709
|
|
|
710
|
+
### Scroll clearance
|
|
711
|
+
|
|
712
|
+
Chrome that lies over a scroll owner's block edge (a `DialogSurface` floating
|
|
713
|
+
footer over a transcript, or translucent chrome over a scrolling region)
|
|
714
|
+
publishes how far it covers that edge through an inherited context:
|
|
715
|
+
`--kui-scroll-clearance-block-start` and `--kui-scroll-clearance-block-end`.
|
|
716
|
+
A scroll owner opts in per edge with `scrollClearance` (`"block-start"`,
|
|
717
|
+
`"block-end"`, or `"both"`) on a `scrollable` `List` or a `Pane`. It adds the
|
|
718
|
+
published clearance to its own block padding and `scroll-padding`, so content
|
|
719
|
+
scrolls visibly beneath the chrome while the first and last items (and any
|
|
720
|
+
item focused or scrolled into view) still come to rest clear of it. Without
|
|
721
|
+
the prop the context is ignored. `PaneConfig` carries `scrollClearance` too,
|
|
722
|
+
so a composed Pane opts in the same way: a Workbench `mainPane` or panel
|
|
723
|
+
`pane`, a `CollapsiblePanel` `pane`, or a `NavStack` view's `pane` (for
|
|
724
|
+
example a NavStack view inside a dialog with a floating composer).
|
|
725
|
+
|
|
726
|
+
Opt in only the one scroller that reaches the covered edge; a nested scroller
|
|
727
|
+
must not opt in again. `DialogSurface` publishes block-end for its floating
|
|
728
|
+
footer and block-start for its floating header (see
|
|
729
|
+
`docs/surface-scaffold.md`), and clears the context in every dialog body. A `Pane` with `headerPresentation="overlay"` publishes block-start for
|
|
730
|
+
its own header, once `wireScrollDividers` has measured it, and its content
|
|
731
|
+
clears it without the prop (see [Overlay header](#overlay-header)). When an application overlays its own chrome on a region (for example a
|
|
732
|
+
translucent toolbar laid over the top of a scrolling list), it publishes the
|
|
733
|
+
chrome's block size on that region's container, the one place where an app
|
|
734
|
+
sets this context:
|
|
735
|
+
|
|
736
|
+
```tsx
|
|
737
|
+
<section style="position:relative;display:grid;--kui-scroll-clearance-block-start:48px">
|
|
738
|
+
<List scrollable scrollClearance="block-start">{rows}</List>
|
|
739
|
+
{translucentToolbar}
|
|
740
|
+
</section>;
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
### Framed result pickers
|
|
744
|
+
|
|
745
|
+
For a bounded, framed list of `ListItem` rows (search results, duplicate
|
|
746
|
+
candidates, a recent-items picker), configure the List instead of wrapping it
|
|
747
|
+
in an app-owned scroller:
|
|
748
|
+
|
|
749
|
+
```tsx
|
|
750
|
+
<List scrollable frame gap="2xs" minHeight={rem(4.25)} maxHeight={rem(14)}>
|
|
751
|
+
{candidates.map((candidate) => (
|
|
752
|
+
<ListItem action="pick-duplicate" itemId={candidate.id} label={candidate.title} description={candidate.detail} multiline />
|
|
753
|
+
))}
|
|
754
|
+
</List>;
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
`frame` draws a 1px `--kui-color-neutral-border-normal` border with the
|
|
758
|
+
`--kui-radius-m` control radius and a 4px inset on every side (replacing
|
|
759
|
+
`inset`, `textInsets`, and `controlInsets`). That inset is exactly a row's
|
|
760
|
+
focus-ring reach, so the first and last rows' rings stay inside the clip at
|
|
761
|
+
the scroll extremes. Every `scrollable` List, framed or not, carries block
|
|
762
|
+
scroll padding of that reach plus 2px of slack (6px; nothing moves at rest),
|
|
763
|
+
so a middle row focused or scrolled into view also stops with its ring inside
|
|
764
|
+
the clip, even where Chromium's focus scroll stops a pixel short of the padded
|
|
765
|
+
target. An unframed scrollable List has no inset, so its first and last rows
|
|
766
|
+
still meet the clip at the scroll extremes; use `frame` when those rows must
|
|
767
|
+
show a whole ring.
|
|
768
|
+
How far `focus()` scrolls a partly visible row is up to the engine: Chromium
|
|
769
|
+
brings it to the nearest edge, Firefox leaves it until about half of it is
|
|
770
|
+
hidden and then centers it, and WebKit leaves a partly visible row where it
|
|
771
|
+
is. Call `wireListFocusScroll(root)` from `@kerfjs/ui/wire-list-focus-scroll`
|
|
772
|
+
once at the app root (keep its disposer) to make keyboard focus consistent:
|
|
773
|
+
when a `:focus-visible` element inside a `scrollable` List has a ring that
|
|
774
|
+
crosses the clip, it calls `scrollIntoView({ block: 'nearest' })`, which
|
|
775
|
+
honors the List's scroll padding in every engine. It leaves pointer focus
|
|
776
|
+
alone, so a click never scrolls its row from under the pointer, and it is a
|
|
777
|
+
no-op where Chromium has already scrolled. `maxHeight` and `minHeight` take typed
|
|
778
|
+
`CssLength`s from `@kerfjs/ui/css-values` and bound the List directly, with no
|
|
779
|
+
flex-column ancestor; pair `maxHeight` with `scrollable`. A frame of settings
|
|
780
|
+
rows with dividers between them is a `FramedList`, not a framed List.
|
|
781
|
+
|
|
649
782
|
For long reading content, such as a reader view, pass `inset="document"`: 24px
|
|
650
783
|
block and 32px inline on all four sides, narrowing to 16px inline below 576px.
|
|
651
784
|
It replaces any `textInsets`/`controlInsets` on that List.
|
package/docs/nav-stack.md
CHANGED
|
@@ -66,7 +66,8 @@ the view renders a `Pane`: its header and footer stay pinned around the view's
|
|
|
66
66
|
scrolling content, and slide with that view during navigation. The header and
|
|
67
67
|
footer list configuration forwards to their `List`s; `pane` forwards
|
|
68
68
|
`contentElement`, `contentLabel`, `separators`, `safeAreaEdges`,
|
|
69
|
-
`chromeDividers`,
|
|
69
|
+
`chromeDividers`, `appearance`, `deepInset`, `scrollClearance`, `headerPresentation`, `tabIndex`,
|
|
70
|
+
and `outlined` to the Pane. Without those fields, the view
|
|
70
71
|
keeps its simple direct scroll area. Use `pane: { appearance: "sunken" }` for a
|
|
71
72
|
lowered scrolling work surface.
|
|
72
73
|
The back control appears automatically once the stack has more than one entry;
|
|
@@ -79,11 +80,23 @@ and layout content.
|
|
|
79
80
|
|
|
80
81
|
The top chrome is a real `Toolbar`, so it follows the same zone,
|
|
81
82
|
group, and responsive rules as every other toolbar. Its leading zone holds the
|
|
82
|
-
back control (a
|
|
83
|
-
depth), then `toolbar.leading
|
|
84
|
-
`
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
back control (a contained, bordered `ToolbarControlGroup`, shown once the stack has
|
|
84
|
+
depth), then `toolbar.leading`. `toolbar.trailing` fills the trailing zone.
|
|
85
|
+
Give each zone `ToolbarControlGroup`s or `ToolbarText`, as in any toolbar.
|
|
86
|
+
|
|
87
|
+
Where `toolbar.title` goes depends on the back control:
|
|
88
|
+
|
|
89
|
+
- **At the root** (no back control) the title is a filling `ToolbarText` at
|
|
90
|
+
the end of the leading zone, so it reads left-aligned.
|
|
91
|
+
- **Once the stack has depth**, the title is the center zone's only child and
|
|
92
|
+
the toolbar is `centerAlign="balanced"`, like a platform navigation bar. The
|
|
93
|
+
title sits on the bar's midpoint while the sides leave room, moves away from
|
|
94
|
+
a wider side when they do not, and truncates with an ellipsis before it
|
|
95
|
+
reaches the back control or a trailing group. It keeps the root title's
|
|
96
|
+
full-strength text color at its smaller size. This overrides a configured
|
|
97
|
+
`centerAlign`, which applies to view-owned center content.
|
|
98
|
+
- **A view that sets `toolbar.center`** owns the center zone, so its title
|
|
99
|
+
stays left-aligned in the leading zone at any depth.
|
|
87
100
|
|
|
88
101
|
Configure the toolbar with `toolbarConfig` instead of styling it:
|
|
89
102
|
|
|
@@ -110,7 +123,9 @@ Configure the toolbar with `toolbarConfig` instead of styling it:
|
|
|
110
123
|
- `toolbarConfig` supplies stack-wide defaults (`dividerSides`,
|
|
111
124
|
`centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`) and adds
|
|
112
125
|
`label` (the toolbar's accessible name), `titleSize` (the title's
|
|
113
|
-
`ToolbarText` size
|
|
126
|
+
`ToolbarText` size; default `xlarge` at the root, where the title is the page
|
|
127
|
+
heading, and `large` once a back control shares the bar; a Workbench panel's
|
|
128
|
+
stack keeps `large` at every depth), and `headingLevel` (expose the title as
|
|
114
129
|
a heading; default a plain span). The defaults keep the stack's own chrome:
|
|
115
130
|
no divider, the standard Toolbar height (a 44px control band with 8px above and below), and the top and side safe-area edges
|
|
116
131
|
claimed.
|
|
@@ -122,7 +137,7 @@ Configure the toolbar with `toolbarConfig` instead of styling it:
|
|
|
122
137
|
view's top toolbar. `Workbench` uses it for a navigation panel's standard
|
|
123
138
|
collapse toggle; the active view still owns the preceding toolbar groups.
|
|
124
139
|
|
|
125
|
-
The catalog's **Configured
|
|
140
|
+
The catalog's **Configured Toolbar** example shows these together: a level-2
|
|
126
141
|
heading title over a bottom divider, leading and center groups on the root
|
|
127
142
|
view, a trailing group on the pushed view, and `backText` set to the previous
|
|
128
143
|
view's title.
|
|
@@ -172,6 +187,115 @@ top Toolbar's own `dividerSides`.
|
|
|
172
187
|
<NavStack id="settings" label="Settings" views={views.value} chromeDividers="always" />
|
|
173
188
|
```
|
|
174
189
|
|
|
190
|
+
## Overlay chrome
|
|
191
|
+
|
|
192
|
+
`chromePresentation="overlay"` lays the top chrome over the active view's top
|
|
193
|
+
edge, like an iOS navigation bar, instead of docking it above the view
|
|
194
|
+
(`"docked"`, the default). The chrome paints the shared chrome material,
|
|
195
|
+
`--kui-chrome-material` behind `--kui-chrome-material-filter`, so content
|
|
196
|
+
scrolls visibly, blurred, beneath it.
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
<NavStack id="mail" label="Mail" views={views.value} chromePresentation="overlay" />
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- **`wireNavStack` measures it.** The helper you already call for transitions
|
|
203
|
+
reads the live chrome's border-box height with a `ResizeObserver`, publishes
|
|
204
|
+
it on the stack root, and marks the root `data-chrome-overlay="measured"`.
|
|
205
|
+
Only then does the chrome leave its band. Unwired, or with `hideToolbar`, the
|
|
206
|
+
chrome stays docked, so it never covers content it has not measured. The
|
|
207
|
+
measurement follows the chrome as its title wraps, text grows, or a pushed
|
|
208
|
+
view changes its toolbar. A re-render that strips the measurement gets it
|
|
209
|
+
back before paint.
|
|
210
|
+
- **Every view clears it automatically.** The measured height becomes the
|
|
211
|
+
viewport's block-start edge context (`--kui-edge-inset-block-start`), the
|
|
212
|
+
same context that carries safe areas. A plain view pads and scroll-pads by
|
|
213
|
+
it, a sole `Pane` adds it to its content's (or its header's) block-start
|
|
214
|
+
inset, and a nested layout hands it on. The first item rests just below the
|
|
215
|
+
chrome, and anything focused or scrolled into view stops clear of it. No
|
|
216
|
+
`scrollClearance` prop is involved, so a Pane that also opts into
|
|
217
|
+
`scrollClearance` does not clear the chrome twice.
|
|
218
|
+
- **Safe area.** The chrome keeps claiming the top safe area: its toolbar pads
|
|
219
|
+
for it while the material paints through it. The measured height already
|
|
220
|
+
includes that padding, so views clear the chrome and the safe area exactly
|
|
221
|
+
once.
|
|
222
|
+
- **Transitions.** Only the live chrome is measured, never a cross-fading
|
|
223
|
+
copy. The copy keeps painting over the top edge with the same material while
|
|
224
|
+
it fades, and the incoming view settles at the incoming chrome's clearance.
|
|
225
|
+
- **Classic scrollbars.** Where the active view's scroller (the view, or a
|
|
226
|
+
sole header-less Pane's content) shows a classic, space-taking scrollbar,
|
|
227
|
+
`wireNavStack` measures it and the chrome ends where its track begins, so
|
|
228
|
+
the thumb and arrows stay visible and usable. An overlay scrollbar takes no
|
|
229
|
+
space and passes beneath the material like the content.
|
|
230
|
+
- **Dividers.** With `wireScrollDividers`, the line under the chrome still
|
|
231
|
+
appears only while content is scrolled beneath it.
|
|
232
|
+
- **Contrast.** The material keeps normal text at AA over any content. An
|
|
233
|
+
untoned `ToolbarText` in the chrome lifts itself: its title takes the normal
|
|
234
|
+
text color at every size and its `description` mixes the quiet color halfway
|
|
235
|
+
toward it, and a default-tone `ToolbarControlGroup` takes the normal text
|
|
236
|
+
color for its controls. Other quiet copy you place in the chrome has no such
|
|
237
|
+
lift, so keep it in the view (see
|
|
238
|
+
[Accessibility › Chrome material](accessibility.md#chrome-material)). The
|
|
239
|
+
material turns opaque under `prefers-reduced-transparency`,
|
|
240
|
+
`prefers-contrast: more`, or without `backdrop-filter`, and forced colors
|
|
241
|
+
paint `Canvas` with a `CanvasText` bottom edge.
|
|
242
|
+
|
|
243
|
+
`SplitView`'s `compactStack.chromePresentation` and a Workbench navigation
|
|
244
|
+
panel's `navStack.chromePresentation` forward the same option.
|
|
245
|
+
`chromePresentation` governs only the top chrome; the bottom toolbar has its
|
|
246
|
+
own option below.
|
|
247
|
+
|
|
248
|
+
### Overlay bottom toolbar
|
|
249
|
+
|
|
250
|
+
`bottomToolbarPresentation="overlay"` does the same for the bottom toolbar,
|
|
251
|
+
like an iOS toolbar: it lies over the active view's bottom edge on the same
|
|
252
|
+
chrome material instead of docking below the view (`"docked"`, the default).
|
|
253
|
+
It is a separate prop, so either bar can be overlaid alone, and it mirrors
|
|
254
|
+
`Pane.headerPresentation` and `DialogSurface.footerPresentation` in naming one
|
|
255
|
+
edge.
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
<NavStack
|
|
259
|
+
id="mail"
|
|
260
|
+
label="Mail"
|
|
261
|
+
views={views.value}
|
|
262
|
+
chromePresentation="overlay"
|
|
263
|
+
bottomToolbarPresentation="overlay"
|
|
264
|
+
bottomToolbar={{ label: 'Mail Actions', trailing: composeGroup }}
|
|
265
|
+
/>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
- **`wireNavStack` measures it.** It reads the live bottom toolbar's
|
|
269
|
+
border-box height (never a cross-fading copy's), publishes it on the stack
|
|
270
|
+
root, and marks the root `data-bottom-toolbar-overlay="measured"`. Only then
|
|
271
|
+
does the toolbar leave its band. Unwired, or while no bottom toolbar is
|
|
272
|
+
shown (a view without one and no stack-level fallback), it stays docked. The
|
|
273
|
+
measurement follows a view-owned toolbar as views push and pop, and a
|
|
274
|
+
re-render that strips it gets it back before paint.
|
|
275
|
+
- **Every view clears it automatically.** The measured height becomes the
|
|
276
|
+
viewport's block-end edge context (`--kui-edge-inset-block-end`). A plain
|
|
277
|
+
view pads and scroll-pads by it, a sole `Pane` adds it to its content's
|
|
278
|
+
block-end inset (or its footer's, so the footer rests just above the
|
|
279
|
+
toolbar), and a nested layout hands it on. The last item rests just above
|
|
280
|
+
the toolbar, and anything focused or scrolled into view stops clear of it.
|
|
281
|
+
- **Safe area.** The toolbar keeps claiming the bottom safe area (the home
|
|
282
|
+
indicator), and the measured height includes it, so views clear both exactly
|
|
283
|
+
once. Inside a `TabNavigator` scene the tab bar owns that edge, so the
|
|
284
|
+
stack's toolbar sits just above the tab bar and counts no safe area.
|
|
285
|
+
- **Classic scrollbars and dividers.** The toolbar ends where a classic
|
|
286
|
+
scrollbar's track begins (a sole Pane with a footer ends its scroller above
|
|
287
|
+
the toolbar, so nothing needs leaving there). With `wireScrollDividers`, the
|
|
288
|
+
toolbar's top line still appears only while more content lies below.
|
|
289
|
+
- **Contrast.** An untoned `ToolbarText` lifts itself as in the top chrome,
|
|
290
|
+
and a default-tone `ToolbarControlGroup` in either overlaid bar takes the
|
|
291
|
+
normal text color for its controls, so labels and icons keep AA over the
|
|
292
|
+
content beneath. The material has the same opaque fallbacks; in forced
|
|
293
|
+
colors the toolbar paints `Canvas` and its always-present 1px top border
|
|
294
|
+
becomes a `CanvasText` edge, which the measurement includes.
|
|
295
|
+
|
|
296
|
+
`SplitView`'s `compactStack.bottomToolbarPresentation` and a Workbench
|
|
297
|
+
navigation panel's `navStack.bottomToolbarPresentation` forward it too.
|
|
298
|
+
|
|
175
299
|
## Safe areas
|
|
176
300
|
|
|
177
301
|
The stack paints through a device's unsafe areas. Its chrome pads for the top
|
package/docs/recipes.md
CHANGED
|
@@ -26,7 +26,7 @@ The adapter is delivered as reference source, not a new package runtime export.
|
|
|
26
26
|
`delegate()` remains a valid alternative when an application needs selector-
|
|
27
27
|
specific dispatch; either way, wire once at a stable root and retain disposal.
|
|
28
28
|
|
|
29
|
-
## Desktop
|
|
29
|
+
## Desktop Application Shell
|
|
30
30
|
|
|
31
31
|
[Open the recipe](../ux-demo/?component=recipe-app-shell) · [TSX source](../ux-demo/recipes/app-shell.tsx)
|
|
32
32
|
|
|
@@ -52,7 +52,7 @@ whole width). The app owns each rail's collapsed and size signals — which
|
|
|
52
52
|
routing, persistence, and data. Adapt only public `--kui-layout-*` and
|
|
53
53
|
component variables.
|
|
54
54
|
|
|
55
|
-
## Navigation
|
|
55
|
+
## Navigation Sidebar
|
|
56
56
|
|
|
57
57
|
[Open the recipe](../ux-demo/?component=recipe-navigation-sidebar) · [TSX source](../ux-demo/recipes/navigation-sidebar.tsx)
|
|
58
58
|
|
|
@@ -65,7 +65,7 @@ permissions, labels, selection, valid section counts and their localized
|
|
|
65
65
|
content. A toggled `ListHeader` supplies the production `DisclosureArrow` when
|
|
66
66
|
no custom `actionIcon` is needed; ordinary navigation rows stay chevron-free.
|
|
67
67
|
|
|
68
|
-
## Workspace
|
|
68
|
+
## Workspace Header
|
|
69
69
|
|
|
70
70
|
[Open the recipe](../ux-demo/?component=recipe-workspace-header) · [TSX source](../ux-demo/recipes/workspace-header.tsx)
|
|
71
71
|
|
|
@@ -99,7 +99,7 @@ application owns open state, selection, the pushed detail, dismissal policy,
|
|
|
99
99
|
and record actions. Do not put the primary title in a header spanning both
|
|
100
100
|
columns, rebuild the dialog, or reach into private shadow parts.
|
|
101
101
|
|
|
102
|
-
## Composer
|
|
102
|
+
## Composer Form
|
|
103
103
|
|
|
104
104
|
[Open the recipe](../ux-demo/?component=recipe-composer-form) · [TSX source](../ux-demo/recipes/composer-form.tsx)
|
|
105
105
|
|
|
@@ -118,7 +118,7 @@ Because upgraded Web Awesome fields retain live value properties, controlled
|
|
|
118
118
|
resets synchronize both those properties and the rendered value attributes;
|
|
119
119
|
the Reset action also announces `Draft reset` through the catalog live region.
|
|
120
120
|
|
|
121
|
-
## List
|
|
121
|
+
## List Workspace States
|
|
122
122
|
|
|
123
123
|
[Open the recipe](../ux-demo/?component=recipe-list-workspace-states) · [TSX source](../ux-demo/recipes/list-workspace-states.tsx)
|
|
124
124
|
|
|
@@ -127,7 +127,7 @@ populated, stale/background refresh, and error/retry states. The recipe owns
|
|
|
127
127
|
feedback placement; the app owns fetching, cache age, retry policy, and domain
|
|
128
128
|
rows.
|
|
129
129
|
|
|
130
|
-
## Compact
|
|
130
|
+
## Compact Toolbar Choices and Actions
|
|
131
131
|
|
|
132
132
|
[Open the recipe](../ux-demo/?component=recipe-compact-toolbar) · [TSX source](../ux-demo/recipes/compact-toolbar.tsx)
|
|
133
133
|
|
|
@@ -140,7 +140,7 @@ widths the toolbar stacks its zones and wraps whole trailing groups onto another
|
|
|
140
140
|
row, so the last action is never clipped. The app owns values, actions,
|
|
141
141
|
persistence, and responsive priority.
|
|
142
142
|
|
|
143
|
-
## Navigation
|
|
143
|
+
## Navigation Stack
|
|
144
144
|
|
|
145
145
|
[Open the recipe](../ux-demo/?component=recipe-navigation-stack) · [TSX source](../ux-demo/recipes/navigation-stack.tsx)
|
|
146
146
|
|
|
@@ -152,7 +152,7 @@ layout guide
|
|
|
152
152
|
[`app-layouts.md`](app-layouts.md) for choosing among `NavStack`, `SplitView`,
|
|
153
153
|
`Workbench`, and `TabNavigator`.
|
|
154
154
|
|
|
155
|
-
## Loading
|
|
155
|
+
## Loading Inspector
|
|
156
156
|
|
|
157
157
|
[Open the recipe](../ux-demo/?component=recipe-loading-inspector) · [TSX source](../ux-demo/recipes/loading-inspector.tsx)
|
|
158
158
|
|
|
@@ -166,7 +166,7 @@ the populated record — no separate skeleton markup. The composition is the poi
|
|
|
166
166
|
record title instead of truncating it. The app owns the loading lifecycle and
|
|
167
167
|
which values are still unknown.
|
|
168
168
|
|
|
169
|
-
## Collapsible
|
|
169
|
+
## Collapsible Sidebar
|
|
170
170
|
|
|
171
171
|
[Open the recipe](../ux-demo/?component=recipe-collapsible-sidebar) · [TSX source](../ux-demo/recipes/collapsible-sidebar.tsx)
|
|
172
172
|
|
package/docs/split-view.md
CHANGED
|
@@ -114,12 +114,12 @@ compactStack={{
|
|
|
114
114
|
list: { toolbar: { trailing: <ComposeGroup /> } },
|
|
115
115
|
detail: {
|
|
116
116
|
toolbar: { trailing: <ReplyGroup /> },
|
|
117
|
-
bottomToolbar: { label: "Message
|
|
117
|
+
bottomToolbar: { label: "Message Actions", leading: <MessageActions /> },
|
|
118
118
|
},
|
|
119
119
|
}}
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
The catalog's **Interactive
|
|
122
|
+
The catalog's **Interactive Compact Drill-Down** example exercises this exact
|
|
123
123
|
controlled flow: a list action sets the selected message, `detailActive` pushes
|
|
124
124
|
its detail, and the wired Back action clears the selection to reveal the
|
|
125
125
|
preserved list. It also forwards `compactStack`: a level-2 heading title over
|
|
@@ -128,7 +128,7 @@ bottom toolbar on the detail. Use the same structure in application demos so
|
|
|
128
128
|
compact examples show the interaction rather than rendering a disconnected
|
|
129
129
|
detail state.
|
|
130
130
|
|
|
131
|
-
The catalog's **Resizable,
|
|
131
|
+
The catalog's **Resizable, Collapsible List** example forwards `resizable`: a
|
|
132
132
|
hidden separator that still resizes the list (its committed width comes back
|
|
133
133
|
through `wireResizableRegions`' `onCommit` into the app's size signal), a Hide
|
|
134
134
|
control in the list's own toolbar, and a `FloatingToolbar` restore control in
|
package/docs/sunken-panel.md
CHANGED
|
@@ -8,7 +8,7 @@ issue tracker or component catalog.
|
|
|
8
8
|
```tsx
|
|
9
9
|
import { SunkenPanel } from '@kerfjs/ui/sunken-panel';
|
|
10
10
|
|
|
11
|
-
<SunkenPanel ariaLabel="Release
|
|
11
|
+
<SunkenPanel ariaLabel="Release Workspace">
|
|
12
12
|
<ReleaseSummary />
|
|
13
13
|
<ReleaseChecks />
|
|
14
14
|
</SunkenPanel>;
|
|
@@ -33,7 +33,7 @@ can shrink with its parent. Like `Grid`, `flex` accepts `true` (equivalent to
|
|
|
33
33
|
|
|
34
34
|
```tsx
|
|
35
35
|
<List fill>
|
|
36
|
-
<Toolbar label="Work
|
|
36
|
+
<Toolbar label="Work Area" />
|
|
37
37
|
<SunkenPanel flex>
|
|
38
38
|
<WorkArea />
|
|
39
39
|
</SunkenPanel>
|