@kerfjs/ui 5.0.0-beta.77 → 5.0.0-beta.79

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.
Files changed (128) hide show
  1. package/README.md +9 -4
  2. package/ai/application-ui-diagnostic-ids-v1.json +4 -0
  3. package/ai/compile-time-contracts-v1.json +3 -3
  4. package/ai/component-catalog.json +152 -31
  5. package/ai/component-composition-rules.json +6 -14
  6. package/ai/component-composition.json +123 -29
  7. package/ai/components/README.md +1 -1
  8. package/ai/components/document-baseline.md +1 -1
  9. package/ai/components/nav-stack.md +6 -6
  10. package/ai/components/pane.md +3 -1
  11. package/ai/components/surface-scaffold.md +11 -2
  12. package/ai/components/{tab-scaffold.md → tab-navigator.md} +14 -14
  13. package/ai/components/token-search-field.md +1 -0
  14. package/ai/components/toolbar-control-group.md +2 -0
  15. package/ai/components/toolbar-text.md +2 -0
  16. package/ai/components/toolbar.md +6 -8
  17. package/ai/public-api-signatures-v1.md +68 -140
  18. package/ai/skill.md +15 -4
  19. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  20. package/dist/browser/nav-stack.js +2 -0
  21. package/dist/browser/split-view.js +2 -0
  22. package/dist/browser/tab-navigator.js +4 -0
  23. package/dist/catalog-resources.d.ts +3 -3
  24. package/dist/catalog.d.ts +3 -3
  25. package/dist/catalog.js +3 -3
  26. package/dist/{chunk-WJN3V2H5.js → chunk-2GOCOLQL.js} +18 -4
  27. package/dist/chunk-2GOCOLQL.js.map +1 -0
  28. package/dist/{chunk-QYXKMLHO.js → chunk-3CXRQAYT.js} +2 -2
  29. package/dist/chunk-3CXRQAYT.js.map +1 -0
  30. package/dist/{chunk-G4VKQP7B.js → chunk-3SXWV2IR.js} +5 -1
  31. package/dist/chunk-3SXWV2IR.js.map +1 -0
  32. package/dist/{chunk-VLPE6OPN.js → chunk-62VMNBV2.js} +6 -2
  33. package/dist/chunk-62VMNBV2.js.map +1 -0
  34. package/dist/{chunk-XIZRXI7N.js → chunk-A7DYEERU.js} +13 -1
  35. package/dist/chunk-A7DYEERU.js.map +1 -0
  36. package/dist/{chunk-6VQPLV3O.js → chunk-DSLRNR43.js} +9 -8
  37. package/dist/chunk-DSLRNR43.js.map +1 -0
  38. package/dist/{chunk-AOAW55JN.js → chunk-DXQZ3BEO.js} +4 -1
  39. package/dist/chunk-DXQZ3BEO.js.map +1 -0
  40. package/dist/chunk-IKCUPTR2.js +170 -0
  41. package/dist/chunk-IKCUPTR2.js.map +1 -0
  42. package/dist/{chunk-Z6PE5T7N.js → chunk-JL4BBZP4.js} +4 -3
  43. package/dist/chunk-JL4BBZP4.js.map +1 -0
  44. package/dist/collapsible-panel.js +2 -2
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.js +8 -8
  47. package/dist/nav-stack-B1Qc2e5q.d.ts +101 -0
  48. package/dist/nav-stack.d.ts +11 -93
  49. package/dist/nav-stack.js +5 -1
  50. package/dist/pane.d.ts +5 -2
  51. package/dist/pane.js +1 -1
  52. package/dist/split-view.d.ts +9 -4
  53. package/dist/split-view.js +7 -3
  54. package/dist/split-view.js.map +1 -1
  55. package/dist/styles/components/actions/toolbar/toolbar.css +7 -14
  56. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +63 -13
  57. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +8 -1
  58. package/dist/styles/components/forms/token-search-field/token-search-field.css +12 -1
  59. package/dist/styles/components/layout/pane/pane.css +18 -1
  60. package/dist/styles/components/navigation/nav-stack/nav-stack.css +6 -12
  61. package/dist/styles/components/navigation/tab-scaffold/tab-scaffold.css +18 -1
  62. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +55 -0
  63. package/dist/styles/nav-stack.css +6 -12
  64. package/dist/styles/pane.css +18 -1
  65. package/dist/styles/surface-scaffold.css +55 -0
  66. package/dist/styles/{tab-scaffold.css → tab-navigator.css} +18 -1
  67. package/dist/styles/token-search-field.css +12 -1
  68. package/dist/styles/toolbar-control-group.css +63 -13
  69. package/dist/styles/toolbar-text.css +8 -1
  70. package/dist/styles/toolbar.css +7 -14
  71. package/dist/surface-scaffold-register.d.ts +4 -0
  72. package/dist/surface-scaffold-register.js +59 -0
  73. package/dist/surface-scaffold-register.js.map +1 -0
  74. package/dist/surface-scaffold.d.ts +10 -2
  75. package/dist/surface-scaffold.js +1 -1
  76. package/dist/{tab-scaffold.d.ts → tab-navigator.d.ts} +12 -10
  77. package/dist/{tab-scaffold.js → tab-navigator.js} +4 -3
  78. package/dist/tab-navigator.js.map +1 -0
  79. package/dist/token-search-field.js +1 -1
  80. package/dist/wire-catalog.js +1 -1
  81. package/dist/wire-scroll-dividers.d.ts +3 -3
  82. package/dist/wire-scroll-dividers.js +1 -1
  83. package/dist/wire-tab-navigator.d.ts +11 -0
  84. package/dist/{wire-tab-scaffold.js → wire-tab-navigator.js} +3 -3
  85. package/dist/wire-tab-navigator.js.map +1 -0
  86. package/dist/wire-token-search-fields.js +1 -1
  87. package/dist/wire-toolbar-visibility.js +1 -1
  88. package/dist/workbench.d.ts +5 -13
  89. package/dist/workbench.js +1 -1
  90. package/docs/app-layouts.md +44 -11
  91. package/docs/component-contract.md +9 -2
  92. package/docs/component-selection.md +17 -15
  93. package/docs/design/templates/token-search-field/empty-dark.svg +1 -1
  94. package/docs/design/templates/token-search-field/empty.svg +1 -1
  95. package/docs/design/templates/token-search-field-dark.svg +1 -1
  96. package/docs/design/templates/token-search-field.svg +1 -1
  97. package/docs/design/templates.md +1 -1
  98. package/docs/examples/application-ui-profile.json +4 -4
  99. package/docs/layout.md +31 -8
  100. package/docs/nav-stack.md +30 -18
  101. package/docs/recipes.md +6 -2
  102. package/docs/split-view.md +7 -4
  103. package/docs/surface-scaffold.md +46 -0
  104. package/docs/{tab-scaffold.md → tab-navigator.md} +83 -11
  105. package/docs/type-contracts.md +3 -3
  106. package/docs/ui-analyzer.md +5 -0
  107. package/docs/ui-doctor.md +33 -0
  108. package/docs/workbench.md +3 -2
  109. package/doctor/component-style-checks.mjs +457 -0
  110. package/doctor/index.mjs +43 -13
  111. package/llms.txt +18 -6
  112. package/package.json +16 -11
  113. package/ux-demo/recipes/list-detail-dialog.tsx +4 -0
  114. package/ux-demo/recipes/navigation-stack.tsx +2 -2
  115. package/dist/browser/tab-scaffold.js +0 -4
  116. package/dist/chunk-6VQPLV3O.js.map +0 -1
  117. package/dist/chunk-AOAW55JN.js.map +0 -1
  118. package/dist/chunk-G4VKQP7B.js.map +0 -1
  119. package/dist/chunk-QYXKMLHO.js.map +0 -1
  120. package/dist/chunk-VLPE6OPN.js.map +0 -1
  121. package/dist/chunk-WJN3V2H5.js.map +0 -1
  122. package/dist/chunk-XIZRXI7N.js.map +0 -1
  123. package/dist/chunk-Z4EPMX25.js +0 -123
  124. package/dist/chunk-Z4EPMX25.js.map +0 -1
  125. package/dist/chunk-Z6PE5T7N.js.map +0 -1
  126. package/dist/tab-scaffold.js.map +0 -1
  127. package/dist/wire-tab-scaffold.d.ts +0 -11
  128. package/dist/wire-tab-scaffold.js.map +0 -1
@@ -642,7 +642,8 @@
642
642
  "padding": "child",
643
643
  "notes": [
644
644
  "The pane is unpadded; separators are independently opt-in on logical edges and default off.",
645
- "Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding."
645
+ "Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding.",
646
+ "The scrolling content exposes its resolved logical inline padding to descendants as --kui-pane-content-inset-inline-start/end, including safe areas and deepInset."
646
647
  ]
647
648
  }
648
649
  },
@@ -670,6 +671,8 @@
670
671
  "--kui-pane-separator-color",
671
672
  "--kui-pane-separator-width",
672
673
  "--kui-pane-chrome-background",
674
+ "--kui-pane-content-inset-inline-start",
675
+ "--kui-pane-content-inset-inline-end",
673
676
  "--kui-sunken-panel-background"
674
677
  ]
675
678
  },
@@ -697,7 +700,7 @@
697
700
  "required": false
698
701
  },
699
702
  {
700
- "id": "view content and titles",
703
+ "id": "view content and structured top and bottom toolbar configurations",
701
704
  "owner": "application",
702
705
  "required": false
703
706
  },
@@ -712,7 +715,7 @@
712
715
  "required": false
713
716
  },
714
717
  {
715
- "id": "per-view bottom toolbar content or a persistent fallback",
718
+ "id": "per-view bottom toolbar or a persistent structured fallback",
716
719
  "owner": "application",
717
720
  "required": false
718
721
  },
@@ -722,12 +725,12 @@
722
725
  "required": false
723
726
  },
724
727
  {
725
- "id": "per-view fixed header content above the active view's scroll area",
728
+ "id": "per-view header and footer with List and Pane configuration",
726
729
  "owner": "application",
727
730
  "required": false
728
731
  },
729
732
  {
730
- "id": "top-toolbar configuration, title size, and heading level",
733
+ "id": "top-toolbar defaults, title size, and heading level",
731
734
  "owner": "application",
732
735
  "required": false
733
736
  },
@@ -812,7 +815,6 @@
812
815
  "kui-nav-stack__chrome-copy",
813
816
  "kui-nav-stack__chrome-copy--bottom",
814
817
  "kui-nav-stack__chrome-copy--exiting",
815
- "kui-nav-stack__header",
816
818
  "kui-nav-stack__viewport",
817
819
  "kui-nav-stack__view",
818
820
  "kui-nav-stack__view--entering",
@@ -964,10 +966,10 @@
964
966
  }
965
967
  },
966
968
  {
967
- "key": "@kerfjs/ui:tab-scaffold",
969
+ "key": "@kerfjs/ui:tab-navigator",
968
970
  "package": "@kerfjs/ui",
969
- "id": "tab-scaffold",
970
- "name": "TabScaffold",
971
+ "id": "tab-navigator",
972
+ "name": "TabNavigator",
971
973
  "kind": "component",
972
974
  "source": "kerf",
973
975
  "parents": { "mode": "any", "entries": [] },
@@ -1008,8 +1010,8 @@
1008
1010
  ],
1009
1011
  "wiring": {
1010
1012
  "required": true,
1011
- "helpers": ["wireTabScaffold", "wireScrollDividers"],
1012
- "obligations": ["Use wireTabScaffold as documented."],
1013
+ "helpers": ["wireTabNavigator", "wireScrollDividers"],
1014
+ "obligations": ["Use wireTabNavigator as documented."],
1013
1015
  "stateAttributes": [
1014
1016
  {
1015
1017
  "name": "data-scroll-overflow",
@@ -1033,7 +1035,7 @@
1033
1035
  "border": "conditional",
1034
1036
  "padding": "self",
1035
1037
  "notes": [
1036
- "The scaffold owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.",
1038
+ "The navigator owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.",
1037
1039
  "The bar's top line is scroll state (wireScrollDividers): it shows only while the active scene's content continues below the bar, by coloring the bar's always-present 1px top border."
1038
1040
  ]
1039
1041
  }
@@ -1428,30 +1430,26 @@
1428
1430
  {
1429
1431
  "id": "leading",
1430
1432
  "jsx": { "prop": "leading" },
1431
- "accepts": ["toolbar-text", "toolbar-control-group"],
1433
+ "accepts": ["KerfUiContent"],
1432
1434
  "cardinality": { "min": 0, "max": "unbounded" },
1433
1435
  "exclusiveWith": []
1434
1436
  },
1435
1437
  {
1436
1438
  "id": "center",
1437
1439
  "jsx": { "prop": "center" },
1438
- "accepts": ["toolbar-text", "toolbar-control-group"],
1440
+ "accepts": ["KerfUiContent"],
1439
1441
  "cardinality": { "min": 0, "max": "unbounded" },
1440
1442
  "exclusiveWith": []
1441
1443
  },
1442
1444
  {
1443
1445
  "id": "trailing",
1444
1446
  "jsx": { "prop": "trailing" },
1445
- "accepts": ["toolbar-text", "toolbar-control-group", "wa-button"],
1447
+ "accepts": ["KerfUiContent"],
1446
1448
  "cardinality": { "min": 0, "max": "unbounded" },
1447
1449
  "exclusiveWith": []
1448
1450
  }
1449
1451
  ],
1450
- "children": {
1451
- "mode": "listed",
1452
- "concepts": ["toolbar-text", "toolbar-control-group", "wa-button"],
1453
- "requiredConcepts": []
1454
- },
1452
+ "children": { "mode": "any", "concepts": [], "requiredConcepts": [] },
1455
1453
  "state": [
1456
1454
  { "id": "actions", "owner": "application", "required": false },
1457
1455
  {
@@ -1498,6 +1496,18 @@
1498
1496
  "on": "private aria-hidden measurement boxes under Toolbar",
1499
1497
  "helper": "wireToolbarVisibility",
1500
1498
  "meaning": "Internal out-of-flow CSS length resolver; created and removed by wireToolbarVisibility."
1499
+ },
1500
+ {
1501
+ "name": "data-morph-preserve",
1502
+ "on": "private aria-hidden measurement boxes and visibility state children",
1503
+ "helper": "wireToolbarVisibility",
1504
+ "meaning": "Keeps helper-owned geometry and state across Kerf renders; replacement and explicit removal are repaired, and disposal removes them."
1505
+ },
1506
+ {
1507
+ "name": "data-toolbar-visibility-state",
1508
+ "on": "private hidden children of width-managed items and paired busy statuses",
1509
+ "helper": "wireToolbarVisibility",
1510
+ "meaning": "Preserves actual CSS visibility while rendering removes a transient parent marker, preventing geometry-driven render feedback."
1501
1511
  }
1502
1512
  ]
1503
1513
  },
@@ -1543,14 +1553,7 @@
1543
1553
  "--kui-toolbar-zone-padding-inline"
1544
1554
  ]
1545
1555
  },
1546
- "diagnostics": [
1547
- {
1548
- "id": "KUI-C101",
1549
- "severity": "error",
1550
- "when": "a direct zone child is neither ToolbarText nor ToolbarControlGroup nor a standalone wa-button in trailing",
1551
- "message": "Wrap toolbar controls in ToolbarControlGroup; only ToolbarText and ToolbarControlGroup, plus one standalone primary wa-button in trailing, are direct zone children."
1552
- }
1553
- ],
1556
+ "diagnostics": [],
1554
1557
  "provenance": {
1555
1558
  "selection": "ai/component-catalog.json",
1556
1559
  "composition": "docs/component-selection.md#toolbar-composition"
@@ -1608,6 +1611,18 @@
1608
1611
  "on": "private aria-hidden measurement boxes under Toolbar",
1609
1612
  "helper": "wireToolbarVisibility",
1610
1613
  "meaning": "Internal out-of-flow CSS length resolver; created and removed by wireToolbarVisibility."
1614
+ },
1615
+ {
1616
+ "name": "data-morph-preserve",
1617
+ "on": "private aria-hidden measurement boxes and visibility state children",
1618
+ "helper": "wireToolbarVisibility",
1619
+ "meaning": "Keeps helper-owned geometry and state across Kerf renders; replacement and explicit removal are repaired, and disposal removes them."
1620
+ },
1621
+ {
1622
+ "name": "data-toolbar-visibility-state",
1623
+ "on": "private hidden children of width-managed items and paired busy statuses",
1624
+ "helper": "wireToolbarVisibility",
1625
+ "meaning": "Preserves actual CSS visibility while rendering removes a transient parent marker, preventing geometry-driven render feedback."
1611
1626
  }
1612
1627
  ]
1613
1628
  },
@@ -1742,7 +1757,68 @@
1742
1757
  "Use popup surfaces only for real dropdown menus with named triggers."
1743
1758
  ]
1744
1759
  },
1745
- "cssValueProps": [],
1760
+ "cssValueProps": [
1761
+ {
1762
+ "path": "preferredWidth",
1763
+ "grammar": "length",
1764
+ "helpers": [
1765
+ "px",
1766
+ "rem",
1767
+ "remify",
1768
+ "em",
1769
+ "pct",
1770
+ "space",
1771
+ "lengthVar",
1772
+ "calc"
1773
+ ],
1774
+ "nonStandaloneHelpers": ["plus"],
1775
+ "shorthands": [],
1776
+ "canonicalShorthands": [],
1777
+ "exceptionalShorthands": [],
1778
+ "rawPolicy": "forbid",
1779
+ "examples": ["preferredWidth={remify(832)}"]
1780
+ },
1781
+ {
1782
+ "path": "viewportGutter",
1783
+ "grammar": "length",
1784
+ "helpers": [
1785
+ "px",
1786
+ "rem",
1787
+ "remify",
1788
+ "em",
1789
+ "pct",
1790
+ "space",
1791
+ "lengthVar",
1792
+ "calc"
1793
+ ],
1794
+ "nonStandaloneHelpers": ["plus"],
1795
+ "shorthands": [],
1796
+ "canonicalShorthands": [],
1797
+ "exceptionalShorthands": [],
1798
+ "rawPolicy": "forbid",
1799
+ "examples": ["viewportGutter={remify(8)}"]
1800
+ },
1801
+ {
1802
+ "path": "maxHeight",
1803
+ "grammar": "length",
1804
+ "helpers": [
1805
+ "px",
1806
+ "rem",
1807
+ "remify",
1808
+ "em",
1809
+ "pct",
1810
+ "space",
1811
+ "lengthVar",
1812
+ "calc"
1813
+ ],
1814
+ "nonStandaloneHelpers": ["plus"],
1815
+ "shorthands": ["viewport"],
1816
+ "canonicalShorthands": ["viewport"],
1817
+ "exceptionalShorthands": [],
1818
+ "rawPolicy": "forbid",
1819
+ "examples": ["maxHeight=\"viewport\"", "maxHeight={remify(640)}"]
1820
+ }
1821
+ ],
1746
1822
  "boundaries": {
1747
1823
  "rootClass": "kui-dialog-surface",
1748
1824
  "publicClasses": ["kui-dialog-surface", "kui-popup-surface"],
@@ -1862,6 +1938,18 @@
1862
1938
  "on": "private aria-hidden measurement boxes under Toolbar",
1863
1939
  "helper": "wireToolbarVisibility",
1864
1940
  "meaning": "Internal out-of-flow CSS length resolver; created and removed by wireToolbarVisibility."
1941
+ },
1942
+ {
1943
+ "name": "data-morph-preserve",
1944
+ "on": "private aria-hidden measurement boxes and visibility state children",
1945
+ "helper": "wireToolbarVisibility",
1946
+ "meaning": "Keeps helper-owned geometry and state across Kerf renders; replacement and explicit removal are repaired, and disposal removes them."
1947
+ },
1948
+ {
1949
+ "name": "data-toolbar-visibility-state",
1950
+ "on": "private hidden children of width-managed items and paired busy statuses",
1951
+ "helper": "wireToolbarVisibility",
1952
+ "meaning": "Preserves actual CSS visibility while rendering removes a transient parent marker, preventing geometry-driven render feedback."
1865
1953
  }
1866
1954
  ]
1867
1955
  },
@@ -3403,6 +3491,12 @@
3403
3491
  "on": "the text span inside kui-token-search__editor",
3404
3492
  "helper": "wireTokenSearchFields",
3405
3493
  "meaning": "\"true\" on that span while it holds no text."
3494
+ },
3495
+ {
3496
+ "name": "data-placeholder-visible",
3497
+ "on": "the kui-token-search root",
3498
+ "helper": "wireTokenSearchFields",
3499
+ "meaning": "Tracks whether the DOM-owned editor is empty so its placeholder stays outside the editable area."
3406
3500
  }
3407
3501
  ]
3408
3502
  },
@@ -21,7 +21,7 @@ Exact prop and callback types live in [`public-api-signatures-v1.md`](../public-
21
21
  - [Pane](./pane.md) — Organize a sidebar, main area, inspector, or dialog column into fixed vertical header/footer chrome around one scrolling content owner.
22
22
  - [NavStack](./nav-stack.md) — Present a single linear or drill-down flow while preserving each prior view's state, scroll position, and place in the stack.
23
23
  - [SplitView](./split-view.md) — Present a selectable list and its detail together when space permits, with a one-pane drill-down replacement on compact devices.
24
- - [TabScaffold](./tab-scaffold.md) — Switch among two to five co-equal top-level destinations on compact devices while preserving each destination's independent content state.
24
+ - [TabNavigator](./tab-navigator.md) — Switch among two to five co-equal top-level destinations on compact devices while preserving each destination's independent content state.
25
25
  - [Workbench](./workbench.md) — Arrange a complex tool or editor as a stable central work area with optional peripheral rails and a bottom drawer.
26
26
  - [CollapsiblePanel](./collapsible-panel.md) — Add one independently collapsible peripheral panel without adopting the complete multi-panel Workbench shell.
27
27
  - [SunkenPanel](./sunken-panel.md) — Group a vertical list of application content on a visually lowered surface with one owned 8px inset and an explicit rounded or square-corner shape.
@@ -11,7 +11,7 @@ Opt-in document-level defaults: border-box sizing, body margin/font/surface, nat
11
11
  Let an application opt into Kerf UI-owned document defaults and a definite full-height chain for a percentage-height application shell.
12
12
 
13
13
  - An application wants Kerf UI to own document-level box sizing, body typography, native table-cell and form-control font metrics, surface, and link color.
14
- - A full-height shell (Workbench, SplitView, NavStack, or TabScaffold) mounts into one direct container: put .kui-app-root on that container.
14
+ - A full-height shell (Workbench, SplitView, NavStack, or TabNavigator) mounts into one direct container: put .kui-app-root on that container.
15
15
 
16
16
  **Not when:**
17
17
 
@@ -16,12 +16,12 @@ Present a single linear or drill-down flow while preserving each prior view's st
16
16
  **Not when:**
17
17
 
18
18
  - Do not use NavStack when a list and detail should remain visible together; use SplitView.
19
- - Do not use it for co-equal top-level destinations on compact devices; wrap one stack per destination in TabScaffold.
19
+ - Do not use it for co-equal top-level destinations on compact devices; wrap one stack per destination in TabNavigator.
20
20
 
21
21
  **Alternatives:**
22
22
 
23
23
  - [SplitView](./split-view.md) (roomy-alternative) — Promote a list-to-detail stack to SplitView once both regions fit together.
24
- - [TabScaffold](./tab-scaffold.md) (composes-with) — Use one NavStack as each TabScaffold tab's persistent content.
24
+ - [TabNavigator](./tab-navigator.md) (composes-with) — Use one NavStack as each TabNavigator tab's persistent content.
25
25
 
26
26
  ## Imports
27
27
 
@@ -57,7 +57,7 @@ Exact prop names and types: [`@kerfjs/ui/nav-stack`](../public-api-signatures-v1
57
57
 
58
58
  ## State and wiring
59
59
 
60
- **The app owns:** ordered view stack and stable keys; view content and titles; push and pop actions; preferred initial focus targets when DOM order is insufficient; per-view bottom toolbar content or a persistent fallback; per-view leading, center, and trailing top-toolbar groups; per-view fixed header content above the active view's scroll area; top-toolbar configuration, title size, and heading level; whether the chrome and bottom-toolbar dividers follow the scroll, always show, or never show (chromeDividers).
60
+ **The app owns:** ordered view stack and stable keys; view content and structured top and bottom toolbar configurations; push and pop actions; preferred initial focus targets when DOM order is insufficient; per-view bottom toolbar or a persistent structured fallback; per-view leading, center, and trailing top-toolbar groups; per-view header and footer with List and Pane configuration; top-toolbar defaults, title size, and heading level; whether the chrome and bottom-toolbar dividers follow the scroll, always show, or never show (chromeDividers).
61
61
 
62
62
  **Wiring:** `wireNavStack`, `wireScrollDividers` is required.
63
63
 
@@ -90,9 +90,9 @@ Margin: none · border: conditional · padding: child (layout role: structure).
90
90
 
91
91
  The component owns its own styles. Configure it through its props and variants; do not override its internals.
92
92
 
93
- Public class hooks (select for layout placement only, never to change the component's look): `kui-nav-stack`, `kui-nav-stack__chrome`, `kui-nav-stack__bottom`, `kui-nav-stack__chrome--entering`, `kui-nav-stack__chrome-copy`, `kui-nav-stack__chrome-copy--bottom`, `kui-nav-stack__chrome-copy--exiting`, `kui-nav-stack__header`, `kui-nav-stack__viewport`, `kui-nav-stack__view`, `kui-nav-stack__view--entering`, `kui-nav-stack__view--exiting`.
93
+ Public class hooks (select for layout placement only, never to change the component's look): `kui-nav-stack`, `kui-nav-stack__chrome`, `kui-nav-stack__bottom`, `kui-nav-stack__chrome--entering`, `kui-nav-stack__chrome-copy`, `kui-nav-stack__chrome-copy--bottom`, `kui-nav-stack__chrome-copy--exiting`, `kui-nav-stack__viewport`, `kui-nav-stack__view`, `kui-nav-stack__view--entering`, `kui-nav-stack__view--exiting`.
94
94
 
95
- Never put `kui-nav-stack`, `kui-nav-stack__chrome`, `kui-nav-stack__bottom`, `kui-nav-stack__chrome--entering`, `kui-nav-stack__chrome-copy`, `kui-nav-stack__chrome-copy--bottom`, `kui-nav-stack__chrome-copy--exiting`, `kui-nav-stack__header`, `kui-nav-stack__viewport`, `kui-nav-stack__view`, `kui-nav-stack__view--entering`, `kui-nav-stack__view--exiting` on an element you write; render `NavStack` instead (`KUI-L103`).
95
+ Never put `kui-nav-stack`, `kui-nav-stack__chrome`, `kui-nav-stack__bottom`, `kui-nav-stack__chrome--entering`, `kui-nav-stack__chrome-copy`, `kui-nav-stack__chrome-copy--bottom`, `kui-nav-stack__chrome-copy--exiting`, `kui-nav-stack__viewport`, `kui-nav-stack__view`, `kui-nav-stack__view--entering`, `kui-nav-stack__view--exiting` on an element you write; render `NavStack` instead (`KUI-L103`).
96
96
 
97
97
  Public tokens it reads: `--kui-nav-stack-transition-duration`. Set a token only where its public contract allows; prefer a prop.
98
98
 
@@ -100,6 +100,6 @@ Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-
100
100
 
101
101
  ## Related
102
102
 
103
- - Components: [Toolbar](./toolbar.md), [ToolbarControlGroup](./toolbar-control-group.md), [ToolbarText](./toolbar-text.md), [SplitView](./split-view.md), [TabScaffold](./tab-scaffold.md).
103
+ - Components: [Toolbar](./toolbar.md), [ToolbarControlGroup](./toolbar-control-group.md), [ToolbarText](./toolbar-text.md), [SplitView](./split-view.md), [TabNavigator](./tab-navigator.md).
104
104
  - Docs: [`docs/nav-stack.md`](../../docs/nav-stack.md), [`docs/app-layouts.md#decision-matrix`](../../docs/app-layouts.md#decision-matrix).
105
105
  - UX catalog route: `?component=nav-stack`.
@@ -14,6 +14,7 @@ Organize a sidebar, main area, inspector, or dialog column into fixed vertical h
14
14
  - A pane boundary needs an opt-in separator on any combination of logical sides.
15
15
  - Pinned chrome needs a divider from the scrolling content only while content is scrolled beneath it (wireScrollDividers).
16
16
  - A lowered background must cover the scrolling work viewport and blank space after short content without a second scroll container (appearance: sunken).
17
+ - A child table or other component needs edge-to-edge decoration with text aligned to other pane content.
17
18
 
18
19
  **Not when:**
19
20
 
@@ -76,6 +77,7 @@ Margin: child · border: conditional · padding: child (layout role: structure).
76
77
 
77
78
  - The pane is unpadded; separators are independently opt-in on logical edges and default off.
78
79
  - Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-\*); content block insets are scroll padding.
80
+ - The scrolling content exposes its resolved logical inline padding to descendants as --kui-pane-content-inset-inline-start/end, including safe areas and deepInset.
79
81
 
80
82
  ## Accessibility
81
83
 
@@ -90,7 +92,7 @@ Public class hooks (select for layout placement only, never to change the compon
90
92
 
91
93
  Never put `kui-pane`, `kui-pane__content`, `kui-pane__footer`, `kui-pane__header`, `kui-pane__toolbar` on an element you write; render `Pane` instead (`KUI-L103`).
92
94
 
93
- Public tokens it reads: `--kui-edge-inset-block-end`, `--kui-edge-inset-block-start`, `--kui-edge-inset-inline-end`, `--kui-edge-inset-inline-start`, `--kui-pane-separator-color`, `--kui-pane-separator-width`, `--kui-pane-chrome-background`, `--kui-sunken-panel-background`. Set a token only where its public contract allows; prefer a prop.
95
+ Public tokens it reads: `--kui-edge-inset-block-end`, `--kui-edge-inset-block-start`, `--kui-edge-inset-inline-end`, `--kui-edge-inset-inline-start`, `--kui-pane-separator-color`, `--kui-pane-separator-width`, `--kui-pane-chrome-background`, `--kui-pane-content-inset-inline-start`, `--kui-pane-content-inset-inline-end`, `--kui-sunken-panel-background`. Set a token only where its public contract allows; prefer a prop.
94
96
 
95
97
  Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
96
98
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  `@kerfjs/ui:surface-scaffold` · Kerf UI · component · Structure
6
6
 
7
- Typed Web Awesome dialog and popup surface sizing, presentation, and inset composition.
7
+ Typed Web Awesome dialog preferred widths and viewport bounds, presentation, and popup inset composition.
8
8
 
9
9
  ## When to use
10
10
 
@@ -12,6 +12,7 @@ Configure recurring dialog and popup geometry without consumer ::part() override
12
12
 
13
13
  - A Web Awesome dialog or dropdown needs a standard size, presentation, body/footer inset, or list-compatible menu inset.
14
14
  - A dialog body should compose rows, sections, or aligned bare prose through List and ListInsetText.
15
+ - A modal needs a typed preferred width, viewport gutter, or dynamic viewport-bounded height cap while retaining native body scrolling and footer actions.
15
16
 
16
17
  **Not when:**
17
18
 
@@ -22,7 +23,8 @@ Configure recurring dialog and popup geometry without consumer ::part() override
22
23
 
23
24
  - JavaScript: `@kerfjs/ui/surface-scaffold` — exports `DialogSurface`, `PopupSurface`.
24
25
  - CSS: the browser build of `@kerfjs/ui/surface-scaffold` pulls its CSS automatically; import `@kerfjs/ui/surface-scaffold.css` manually only without the `browser` export condition.
25
- - Declared side effects: browser-condition-css.
26
+ - Registration: import `@kerfjs/ui/surface-scaffold/register` once (a side effect).
27
+ - Declared side effects: browser-condition-css, custom-element-registration.
26
28
 
27
29
  ## Props
28
30
 
@@ -32,9 +34,16 @@ Exact prop names and types: [`@kerfjs/ui/surface-scaffold`](../public-api-signat
32
34
 
33
35
  - small, medium, or large dialog
34
36
  - modal, side-sheet, or fullscreen dialog
37
+ - typed modal preferred width, viewport gutter, and maximum height, including viewport cap
35
38
  - none, compact, or comfortable body and footer inset
36
39
  - standard, compact, or zero-inset popup menu
37
40
 
41
+ **CSS-value props** (typed builders from `@kerfjs/ui/css-values`; raw CSS strings are rejected):
42
+
43
+ - `preferredWidth`: length grammar; raw values: forbid; helpers `px`, `rem`, `remify`, `em`, `pct`, `space`, `lengthVar`, `calc` — e.g. `preferredWidth={remify(832)}`
44
+ - `viewportGutter`: length grammar; raw values: forbid; helpers `px`, `rem`, `remify`, `em`, `pct`, `space`, `lengthVar`, `calc` — e.g. `viewportGutter={remify(8)}`
45
+ - `maxHeight`: length grammar; raw values: forbid; shorthands `viewport`; helpers `px`, `rem`, `remify`, `em`, `pct`, `space`, `lengthVar`, `calc` — e.g. `maxHeight="viewport"`
46
+
38
47
  ## Composition
39
48
 
40
49
  - Parents: any.
@@ -1,10 +1,10 @@
1
- # TabScaffold
1
+ # TabNavigator
2
2
 
3
3
  <!-- Generated by scripts/sync-component-docs.mjs from ai/component-catalog.json and ai/component-composition.json. Do not edit; run `npm run catalog:sync`. -->
4
4
 
5
- `@kerfjs/ui:tab-scaffold` · Kerf UI · component · Structure
5
+ `@kerfjs/ui:tab-navigator` · Kerf UI · component · Structure
6
6
 
7
- A controlled compact-device bottom tab scaffold that keeps every tab scene mounted so its navigation and scroll state survive selection changes.
7
+ A controlled compact-device bottom tab navigator that keeps every destination scene mounted so its navigation and scroll state survive selection changes.
8
8
 
9
9
  ## When to use
10
10
 
@@ -15,7 +15,7 @@ Switch among two to five co-equal top-level destinations on compact devices whil
15
15
 
16
16
  **Not when:**
17
17
 
18
- - Do not use TabScaffold for document tabs or reorderable work items; use TabBar.
18
+ - Do not use TabNavigator for document tabs or reorderable work items; use TabBar.
19
19
  - Do not retain the bottom bar on desktop when the same destinations should be promoted to a Workbench rail or sidebar.
20
20
 
21
21
  **Alternatives:**
@@ -25,15 +25,15 @@ Switch among two to five co-equal top-level destinations on compact devices whil
25
25
 
26
26
  ## Imports
27
27
 
28
- - JavaScript: `@kerfjs/ui/tab-scaffold` — exports `TabScaffoldTab`, `TabScaffoldProps`, `TabScaffold`.
29
- - CSS: the browser build of `@kerfjs/ui/tab-scaffold` pulls its CSS automatically; import `@kerfjs/ui/tab-scaffold.css` manually only without the `browser` export condition.
30
- - Wiring: `wireTabScaffold` from `@kerfjs/ui/wire-tab-scaffold` (required).
28
+ - JavaScript: `@kerfjs/ui/tab-navigator` — exports `TabNavigatorTab`, `TabNavigatorProps`, `TabNavigator`.
29
+ - CSS: the browser build of `@kerfjs/ui/tab-navigator` pulls its CSS automatically; import `@kerfjs/ui/tab-navigator.css` manually only without the `browser` export condition.
30
+ - Wiring: `wireTabNavigator` from `@kerfjs/ui/wire-tab-navigator` (required).
31
31
  - Wiring: `wireScrollDividers` from `@kerfjs/ui/wire-scroll-dividers` (optional).
32
32
  - Declared side effects: browser-condition-css.
33
33
 
34
34
  ## Props
35
35
 
36
- Exact prop names and types: [`@kerfjs/ui/tab-scaffold`](../public-api-signatures-v1.md#kerfjsuitab-scaffold), [`@kerfjs/ui/wire-tab-scaffold`](../public-api-signatures-v1.md#kerfjsuiwire-tab-scaffold), [`@kerfjs/ui/wire-scroll-dividers`](../public-api-signatures-v1.md#kerfjsuiwire-scroll-dividers) in `public-api-signatures-v1.md`. Do not infer props from examples.
36
+ Exact prop names and types: [`@kerfjs/ui/tab-navigator`](../public-api-signatures-v1.md#kerfjsuitab-navigator), [`@kerfjs/ui/wire-tab-navigator`](../public-api-signatures-v1.md#kerfjsuiwire-tab-navigator), [`@kerfjs/ui/wire-scroll-dividers`](../public-api-signatures-v1.md#kerfjsuiwire-scroll-dividers) in `public-api-signatures-v1.md`. Do not infer props from examples.
37
37
 
38
38
  **Variants (configure, do not restyle):**
39
39
 
@@ -55,9 +55,9 @@ Exact prop names and types: [`@kerfjs/ui/tab-scaffold`](../public-api-signatures
55
55
 
56
56
  **The app owns:** controlled active tab id; tab labels, icons, and content; tab badge counts or dots and their localized badgeLabel phrases; routing and persistence; responsive replacement on larger device classes; whether the bar divider follows the scroll, always shows, or never shows (chromeDividers).
57
57
 
58
- **Wiring:** `wireTabScaffold`, `wireScrollDividers` is required.
58
+ **Wiring:** `wireTabNavigator`, `wireScrollDividers` is required.
59
59
 
60
- - Use wireTabScaffold as documented.
60
+ - Use wireTabNavigator as documented.
61
61
 
62
62
  **Wiring-owned state attributes** — never render, remove, or branch on these as app state:
63
63
 
@@ -68,7 +68,7 @@ Exact prop names and types: [`@kerfjs/ui/tab-scaffold`](../public-api-signatures
68
68
 
69
69
  Margin: none · border: conditional · padding: self (layout role: structure). `self` means the component already owns it — do not add wrapper padding, margin, or borders around it.
70
70
 
71
- - The scaffold owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.
71
+ - The navigator owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.
72
72
  - The bar's top line is scroll state (wireScrollDividers): it shows only while the active scene's content continues below the bar, by coloring the bar's always-present 1px top border.
73
73
 
74
74
  ## Accessibility
@@ -83,12 +83,12 @@ The component owns its own styles. Configure it through its props and variants;
83
83
 
84
84
  Public class hooks (select for layout placement only, never to change the component's look): `kui-tab-scaffold`, `kui-tab-scaffold__scenes`, `kui-tab-scaffold__scene`, `kui-tab-scaffold__bar`, `kui-tab-scaffold__tab`, `kui-tab-scaffold__tab-icon`, `kui-tab-scaffold__tab-badge`, `kui-tab-scaffold__tab-label`.
85
85
 
86
- Never put `kui-tab-scaffold`, `kui-tab-scaffold__scenes`, `kui-tab-scaffold__scene`, `kui-tab-scaffold__bar`, `kui-tab-scaffold__tab`, `kui-tab-scaffold__tab-icon`, `kui-tab-scaffold__tab-badge`, `kui-tab-scaffold__tab-label` on an element you write; render `TabScaffold` instead (`KUI-L103`).
86
+ Never put `kui-tab-scaffold`, `kui-tab-scaffold__scenes`, `kui-tab-scaffold__scene`, `kui-tab-scaffold__bar`, `kui-tab-scaffold__tab`, `kui-tab-scaffold__tab-icon`, `kui-tab-scaffold__tab-badge`, `kui-tab-scaffold__tab-label` on an element you write; render `TabNavigator` instead (`KUI-L103`).
87
87
 
88
88
  Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
89
89
 
90
90
  ## Related
91
91
 
92
92
  - Components: [Badge](./badge.md), [AppTab](./tabs.md), [Workbench](./workbench.md).
93
- - Docs: [`docs/tab-scaffold.md`](../../docs/tab-scaffold.md), [`docs/app-layouts.md#decision-matrix`](../../docs/app-layouts.md#decision-matrix).
94
- - UX catalog route: `?component=tab-scaffold`.
93
+ - Docs: [`docs/tab-navigator.md`](../../docs/tab-navigator.md), [`docs/app-layouts.md#decision-matrix`](../../docs/app-layouts.md#decision-matrix).
94
+ - UX catalog route: `?component=tab-navigator`.
@@ -70,6 +70,7 @@ Zones (a zone is bound to JSX only through its listed prop; never assume the zon
70
70
 
71
71
  - `data-token-search-text` on `the text span inside kui-token-search__editor` (`wireTokenSearchFields`): Marks the plain-text span the helper inserts when the editor is emptied.
72
72
  - `data-empty` on `the text span inside kui-token-search__editor` (`wireTokenSearchFields`): "true" on that span while it holds no text.
73
+ - `data-placeholder-visible` on `the kui-token-search root` (`wireTokenSearchFields`): Tracks whether the DOM-owned editor is empty so its placeholder stays outside the editable area.
73
74
 
74
75
  ## Geometry
75
76
 
@@ -88,6 +88,8 @@ Zones (a zone is bound to JSX only through its listed prop; never assume the zon
88
88
 
89
89
  - `data-toolbar-width-hidden` on `ToolbarText, ToolbarControlGroup and its paired busy status` (`wireToolbarVisibility`): True when typed hideBelow/showBelow thresholds hide this item at the nearest Toolbar content width. Re-applied after rendering; disposal restores prior markers.
90
90
  - `data-toolbar-visibility-probe` on `private aria-hidden measurement boxes under Toolbar` (`wireToolbarVisibility`): Internal out-of-flow CSS length resolver; created and removed by wireToolbarVisibility.
91
+ - `data-morph-preserve` on `private aria-hidden measurement boxes and visibility state children` (`wireToolbarVisibility`): Keeps helper-owned geometry and state across Kerf renders; replacement and explicit removal are repaired, and disposal removes them.
92
+ - `data-toolbar-visibility-state` on `private hidden children of width-managed items and paired busy statuses` (`wireToolbarVisibility`): Preserves actual CSS visibility while rendering removes a transient parent marker, preventing geometry-driven render feedback.
91
93
 
92
94
  ## Geometry
93
95
 
@@ -67,6 +67,8 @@ Exact prop names and types: [`@kerfjs/ui/toolbar-text`](../public-api-signatures
67
67
 
68
68
  - `data-toolbar-width-hidden` on `ToolbarText, ToolbarControlGroup and its paired busy status` (`wireToolbarVisibility`): True when typed hideBelow/showBelow thresholds hide this item at the nearest Toolbar content width. Re-applied after rendering; disposal restores prior markers.
69
69
  - `data-toolbar-visibility-probe` on `private aria-hidden measurement boxes under Toolbar` (`wireToolbarVisibility`): Internal out-of-flow CSS length resolver; created and removed by wireToolbarVisibility.
70
+ - `data-morph-preserve` on `private aria-hidden measurement boxes and visibility state children` (`wireToolbarVisibility`): Keeps helper-owned geometry and state across Kerf renders; replacement and explicit removal are repaired, and disposal removes them.
71
+ - `data-toolbar-visibility-state` on `private hidden children of width-managed items and paired busy statuses` (`wireToolbarVisibility`): Preserves actual CSS visibility while rendering removes a transient parent marker, preventing geometry-driven render feedback.
70
72
 
71
73
  ## Geometry
72
74
 
@@ -47,14 +47,14 @@ Exact prop names and types: [`@kerfjs/ui/toolbar`](../public-api-signatures-v1.m
47
47
 
48
48
  - Parents: any.
49
49
  - Contexts: `application-chrome`, `page-header`, `panel-header`, `dialog-header`.
50
- - Children: only [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md), [Button](./wa-button.md).
50
+ - Children: unrestricted.
51
51
  - Built from: [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md), [Button](./wa-button.md), [PopupMenu](./popup-menu.md).
52
52
 
53
53
  Zones (a zone is bound to JSX only through its listed prop; never assume the zone id is a prop):
54
54
 
55
- - `leading` — JSX prop `leading`; accepts [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md); any number.
56
- - `center` — JSX prop `center`; accepts [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md); any number.
57
- - `trailing` — JSX prop `trailing`; accepts [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md), [Button](./wa-button.md); any number.
55
+ - `leading` — JSX prop `leading`; accepts `KerfUiContent`; any number.
56
+ - `center` — JSX prop `center`; accepts `KerfUiContent`; any number.
57
+ - `trailing` — JSX prop `trailing`; accepts `KerfUiContent`; any number.
58
58
 
59
59
  ## State and wiring
60
60
 
@@ -68,6 +68,8 @@ Zones (a zone is bound to JSX only through its listed prop; never assume the zon
68
68
  - `data-scroll-divider` on `a Toolbar named as targets chrome` (`wireScrollDividers`): The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it.
69
69
  - `data-toolbar-width-hidden` on `ToolbarText, ToolbarControlGroup and its paired busy status` (`wireToolbarVisibility`): True when typed hideBelow/showBelow thresholds hide this item at the nearest Toolbar content width. Re-applied after rendering; disposal restores prior markers.
70
70
  - `data-toolbar-visibility-probe` on `private aria-hidden measurement boxes under Toolbar` (`wireToolbarVisibility`): Internal out-of-flow CSS length resolver; created and removed by wireToolbarVisibility.
71
+ - `data-morph-preserve` on `private aria-hidden measurement boxes and visibility state children` (`wireToolbarVisibility`): Keeps helper-owned geometry and state across Kerf renders; replacement and explicit removal are repaired, and disposal removes them.
72
+ - `data-toolbar-visibility-state` on `private hidden children of width-managed items and paired busy statuses` (`wireToolbarVisibility`): Preserves actual CSS visibility while rendering removes a transient parent marker, preventing geometry-driven render feedback.
71
73
 
72
74
  ## Geometry
73
75
 
@@ -92,10 +94,6 @@ Public tokens it reads: `--kui-color-neutral-border-normal`, `--kui-font-sans`,
92
94
 
93
95
  Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
94
96
 
95
- ## Diagnostics
96
-
97
- - `KUI-C101` (error) when a direct zone child is neither ToolbarText nor ToolbarControlGroup nor a standalone wa-button in trailing: Wrap toolbar controls in ToolbarControlGroup; only ToolbarText and ToolbarControlGroup, plus one standalone primary wa-button in trailing, are direct zone children.
98
-
99
97
  ## Related
100
98
 
101
99
  - Components: [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md), [Button](./wa-button.md), [PopupMenu](./popup-menu.md).