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

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 (79) hide show
  1. package/ai/component-catalog.json +19 -8
  2. package/ai/component-composition.json +34 -1
  3. package/ai/components/README.md +1 -1
  4. package/ai/components/content-item.md +1 -1
  5. package/ai/components/list-header.md +4 -3
  6. package/ai/components/pane.md +2 -1
  7. package/ai/components/sunken-panel.md +1 -1
  8. package/ai/components/tab-navigator.md +2 -1
  9. package/ai/components/workbench.md +2 -1
  10. package/ai/public-api-signatures-v1.md +45 -16
  11. package/ai/skill.md +2 -2
  12. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  13. package/dist/browser/tab-navigator.js +1 -1
  14. package/dist/catalog.js +2 -2
  15. package/dist/{chunk-HPREYDKV.js → chunk-3XPGJUUQ.js} +5 -1
  16. package/dist/chunk-3XPGJUUQ.js.map +1 -0
  17. package/dist/{chunk-VLQUXZKA.js → chunk-7TE6XDFI.js} +8 -3
  18. package/dist/chunk-7TE6XDFI.js.map +1 -0
  19. package/dist/{chunk-IKCUPTR2.js → chunk-CVKIADIS.js} +4 -2
  20. package/dist/chunk-CVKIADIS.js.map +1 -0
  21. package/dist/{chunk-DXQZ3BEO.js → chunk-FL6J644M.js} +6 -1
  22. package/dist/chunk-FL6J644M.js.map +1 -0
  23. package/dist/{chunk-JL4BBZP4.js → chunk-JZM3G6RT.js} +4 -2
  24. package/dist/chunk-JZM3G6RT.js.map +1 -0
  25. package/dist/{chunk-DSLRNR43.js → chunk-LQKY5S4F.js} +17 -4
  26. package/dist/chunk-LQKY5S4F.js.map +1 -0
  27. package/dist/{chunk-M6BWQMQY.js → chunk-VIGVNDXZ.js} +11 -6
  28. package/dist/chunk-VIGVNDXZ.js.map +1 -0
  29. package/dist/collapsible-panel.d.ts +5 -1
  30. package/dist/collapsible-panel.js +6 -2
  31. package/dist/collapsible-panel.js.map +1 -1
  32. package/dist/content-item.d.ts +8 -1
  33. package/dist/content-item.js +1 -1
  34. package/dist/index.js +4 -4
  35. package/dist/list-header.d.ts +2 -7
  36. package/dist/list-header.js +1 -1
  37. package/dist/nav-stack.js +1 -1
  38. package/dist/pane.d.ts +8 -3
  39. package/dist/pane.js +1 -1
  40. package/dist/split-view.js +1 -1
  41. package/dist/styles/collapsible-panel.css +5 -0
  42. package/dist/styles/components/layout/collapsible-panel/collapsible-panel.css +5 -0
  43. package/dist/styles/components/layout/pane/pane.css +18 -4
  44. package/dist/styles/components/layout/workbench/workbench.css +9 -1
  45. package/dist/styles/components/navigation/{tab-scaffold/tab-scaffold.css → tab-navigator/tab-navigator.css} +13 -0
  46. package/dist/styles/components/surfaces/content-item/content-item.css +1 -1
  47. package/dist/styles/components/surfaces/sunken-panel/sunken-panel.css +5 -0
  48. package/dist/styles/content-item.css +1 -1
  49. package/dist/styles/pane.css +18 -4
  50. package/dist/styles/sunken-panel.css +5 -0
  51. package/dist/styles/tab-navigator.css +13 -0
  52. package/dist/styles/workbench.css +9 -1
  53. package/dist/sunken-panel.d.ts +5 -1
  54. package/dist/sunken-panel.js +1 -1
  55. package/dist/tab-navigator.d.ts +5 -1
  56. package/dist/tab-navigator.js +4 -0
  57. package/dist/tab-navigator.js.map +1 -1
  58. package/dist/wire-tab-navigator.js +1 -1
  59. package/dist/wire-tab-navigator.js.map +1 -1
  60. package/dist/workbench.d.ts +11 -1
  61. package/dist/workbench.js +1 -1
  62. package/docs/accessibility.md +5 -1
  63. package/docs/collapsible-panel.md +8 -1
  64. package/docs/component-contract.md +7 -5
  65. package/docs/layout.md +22 -6
  66. package/docs/sunken-panel.md +6 -0
  67. package/docs/tab-navigator.md +10 -2
  68. package/docs/type-contracts.md +2 -1
  69. package/docs/ux-demo.md +2 -0
  70. package/docs/workbench.md +12 -0
  71. package/llms.txt +13 -5
  72. package/package.json +1 -1
  73. package/dist/chunk-DSLRNR43.js.map +0 -1
  74. package/dist/chunk-DXQZ3BEO.js.map +0 -1
  75. package/dist/chunk-HPREYDKV.js.map +0 -1
  76. package/dist/chunk-IKCUPTR2.js.map +0 -1
  77. package/dist/chunk-JL4BBZP4.js.map +0 -1
  78. package/dist/chunk-M6BWQMQY.js.map +0 -1
  79. package/dist/chunk-VLQUXZKA.js.map +0 -1
@@ -59,6 +59,10 @@ interface CollapsiblePanelProps {
59
59
  size?: number;
60
60
  /** Accessible label for the panel region. */
61
61
  label?: string;
62
+ /** Opt into keyboard (`0`) or programmatic (`-1`) focus on the panel region. */
63
+ tabIndex?: 0 | -1;
64
+ /** Keep the standard focus outline visible while the panel is expanded. */
65
+ outlined?: boolean;
62
66
  /** Panel content. */
63
67
  children?: KerfUiContent;
64
68
  /**
@@ -110,7 +114,7 @@ interface CollapsiblePanelProps {
110
114
  * and persistence semantics, and with `CollapsiblePanelToggle` for the standard
111
115
  * affordance. See `ui/docs/collapsible-panel.md` and `docs/23-app-layouts.md`.
112
116
  */
113
- declare function CollapsiblePanel({ id, side, collapsed, size, label, children, toolbar, header, headerList, headerPlacement, footer, footerList, bottomToolbar, footerPlacement, pane, separator, collapseMotion, contentOverflow, presentation, restoreControl, restorePosition, className, }: CollapsiblePanelProps): SafeHtml;
117
+ declare function CollapsiblePanel({ id, side, collapsed, size, label, tabIndex, outlined, children, toolbar, header, headerList, headerPlacement, footer, footerList, bottomToolbar, footerPlacement, pane, separator, collapseMotion, contentOverflow, presentation, restoreControl, restorePosition, className, }: CollapsiblePanelProps): SafeHtml;
114
118
  interface CollapsiblePanelRelocatedProps {
115
119
  /** The panel's `id`. */
116
120
  panelId: string;
@@ -1,5 +1,5 @@
1
- import { collapsiblePanelToggleIcon, composedPanelBody, relocatedPanelGroups } from './chunk-JL4BBZP4.js';
2
- export { collapsiblePanelToggleIcon } from './chunk-JL4BBZP4.js';
1
+ import { collapsiblePanelToggleIcon, composedPanelBody, relocatedPanelGroups } from './chunk-JZM3G6RT.js';
2
+ export { collapsiblePanelToggleIcon } from './chunk-JZM3G6RT.js';
3
3
 
4
4
 
5
5
 
@@ -48,6 +48,8 @@ function CollapsiblePanel({
48
48
  collapsed = false,
49
49
  size,
50
50
  label,
51
+ tabIndex,
52
+ outlined = false,
51
53
  children,
52
54
  toolbar,
53
55
  header,
@@ -76,12 +78,14 @@ function CollapsiblePanel({
76
78
  "data-collapsible-panel": id,
77
79
  "data-side": side,
78
80
  "data-collapsed": String(collapsed),
81
+ "data-outlined": !collapsed && presentation !== "hidden" && outlined ? "true" : void 0,
79
82
  "data-separator": separator,
80
83
  "data-collapse-motion": collapseMotion,
81
84
  "data-content-overflow": contentOverflow,
82
85
  "data-presentation": presentation,
83
86
  "aria-label": label || void 0,
84
87
  "aria-hidden": collapsed || presentation === "hidden" ? "true" : void 0,
88
+ tabindex: collapsed || presentation === "hidden" ? tabIndex === void 0 ? void 0 : -1 : tabIndex,
85
89
  inert: collapsed,
86
90
  style: size ? `${sizeVar}: ${size}px` : void 0,
87
91
  children: /* @__PURE__ */ jsx("div", { class: "kui-collapsible-panel__content", children: toolbar ? composedPanelBody({
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/layout/collapsible-panel/collapsible-panel.tsx"],"names":[],"mappings":"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","file":"collapsible-panel.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport {\n collapsiblePanelToggleIcon,\n composedPanelBody,\n type PanelBottomToolbar,\n type PanelChromePlacement,\n type PanelSide,\n type PanelToggle,\n type PanelToggleAttributes,\n type PanelToolbar,\n relocatedPanelGroups,\n} from '../../../shared/panels/panel-toolbar.js';\nimport type { ListConfig } from '../../collections/list/list.js';\nimport { LucideIcon } from '../../media/lucide-icon/lucide-icon.js';\nimport type { PaneConfig } from '../pane/pane.js';\nimport type {\n ResizableRegionCollapseMotion,\n ResizableRegionContentOverflow,\n ResizableRegionPresentation,\n ResizableRegionRestorePosition,\n ResizableRegionSeparator,\n} from '../resizable-region/resizable-region.js';\n\nexport { collapsiblePanelToggleIcon } from '../../../shared/panels/panel-toolbar.js';\n\n/** Which edge a {@link CollapsiblePanel} docks to. */\nexport type CollapsiblePanelSide = PanelSide;\n\n/** The standard toggle a panel toolbar renders (see {@link CollapsiblePanelToolbar}). */\nexport type CollapsiblePanelToolbarToggle = PanelToggle;\n\n/**\n * A panel's composed top toolbar. Its groups occupy `leading`, `center`, and\n * `trailing` while open; groups marked `relocateOnCollapse` and the standard\n * toggle move to the work-area toolbar through\n * {@link CollapsiblePanelRelocated} while it is collapsed.\n */\nexport type CollapsiblePanelToolbar = PanelToolbar;\nexport type CollapsiblePanelBottomToolbar = PanelBottomToolbar;\nexport type CollapsiblePanelChromePlacement = PanelChromePlacement;\n\n/** A CollapsiblePanel toggle's `wireSidebar` hook. */\nconst toggleAttributes = (panelId: string): PanelToggleAttributes => ({\n 'data-collapsible-target': panelId,\n // Keyed, so the morph never reuses a (possibly focused) toggle's button for\n // another control as the toggle moves between toolbars.\n 'data-key': `${panelId}-toggle`,\n});\n\nexport interface CollapsiblePanelToggleProps {\n /** The panel this toggle controls. */\n side: CollapsiblePanelSide;\n /** The panel's current collapsed state (drives the icon direction). */\n collapsed: boolean;\n /** `data-action` the button carries so `wireSidebar` can delegate its click. */\n action: string;\n /** The panel id the button targets (`data-tab-panel`-style: `data-collapsible-panel`). */\n panelId?: string;\n /** Accessible label; defaults to \"Collapse\"/\"Expand\". */\n label?: string;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A standard collapse/expand toggle button for a {@link CollapsiblePanel}: the\n * recognizable per-side icon (see {@link collapsiblePanelToggleIcon}) plus the\n * `data-action` / `aria-expanded` `wireSidebar` reads. Placement is the app's —\n * put it in the panel's own header (to collapse) and somewhere always-visible\n * (to expand while collapsed).\n */\nexport function CollapsiblePanelToggle({\n side,\n collapsed,\n action,\n panelId,\n label,\n className = '',\n slot,\n}: CollapsiblePanelToggleProps) {\n const glyph = collapsiblePanelToggleIcon(side, collapsed);\n const accessible = label ?? (collapsed ? 'Expand' : 'Collapse');\n return (\n <button\n type=\"button\"\n class={`kui-collapsible-panel__toggle ${className}`.trim()}\n data-action={action}\n data-collapsible-target={panelId}\n aria-expanded={String(!collapsed)}\n aria-label={accessible}\n slot={slot}\n >\n <LucideIcon icon={glyph.icon} name={glyph.name} />\n </button>\n );\n}\n\nexport interface CollapsiblePanelProps {\n /** A stable id for the panel — `wireSidebar` targets it and toggles reference it. */\n id: string;\n /** Which edge the panel docks to: a left/right rail or a bottom drawer. */\n side: CollapsiblePanelSide;\n /** Whether the panel is currently collapsed (the app owns this signal). */\n collapsed?: boolean;\n /** Rail width or drawer height in px. Overrides the CSS default. */\n size?: number;\n /** Accessible label for the panel region. */\n label?: string;\n /** Panel content. */\n children?: KerfUiContent;\n /**\n * The panel's top toolbar, composed so its groups follow the panel's open\n * state. With it, `children` renders in a `Pane` below the toolbar; render\n * {@link CollapsiblePanelRelocated} in the app's work-area toolbar so the\n * marked groups and toggle stay reachable while the panel is collapsed.\n */\n toolbar?: CollapsiblePanelToolbar;\n /** Fixed content below a toolbar panel's top toolbar. */\n header?: KerfUiContent;\n headerList?: ListConfig;\n headerPlacement?: CollapsiblePanelChromePlacement;\n /** Fixed content above a toolbar panel's bottom toolbar. */\n footer?: KerfUiContent;\n footerList?: ListConfig;\n bottomToolbar?: CollapsiblePanelBottomToolbar;\n footerPlacement?: CollapsiblePanelChromePlacement;\n /**\n * Configuration for a `toolbar` panel's `Pane` (`contentElement`,\n * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example\n * `{ contentElement: 'nav', contentLabel: 'Sections' }` for a navigation\n * rail. Omitted or `undefined` fields keep the `Pane` defaults. Ignored\n * without a `toolbar`, where `children` renders as given.\n */\n pane?: PaneConfig;\n separator?: ResizableRegionSeparator;\n collapseMotion?: ResizableRegionCollapseMotion;\n contentOverflow?: ResizableRegionContentOverflow;\n presentation?: ResizableRegionPresentation;\n /** Control shown while collapsed, in a safe-area-aware corner of the panel's container (not the viewport). */\n restoreControl?: SafeHtml;\n restorePosition?: ResizableRegionRestorePosition;\n className?: string;\n}\n\n/**\n * A standalone collapsible side rail or bottom drawer, outside the full\n * {@link Workbench} shell. It owns only the presentation: a fixed-size content\n * area that stays laid out while the panel's track snaps to zero and the content\n * slides out via `transform` (one reflow, composited — the same technique\n * `Workbench` and the catalog sidebar use). Bottom-drawer content stays anchored\n * to the panel's fixed bottom edge, so the track cannot move its layout origin\n * underneath the transform transition. A collapsed panel renders `inert` (with\n * `aria-hidden`), so neither Tab, pointer, nor assistive technology reaches\n * content that has slid out of view; its `restoreControl` renders outside the\n * panel and stays reachable.\n * The app owns the `collapsed` signal;\n * pair it with `wireSidebar` for the toggle, focus, compact-overlay, keyboard,\n * and persistence semantics, and with `CollapsiblePanelToggle` for the standard\n * affordance. See `ui/docs/collapsible-panel.md` and `docs/23-app-layouts.md`.\n */\nexport function CollapsiblePanel({\n id,\n side,\n collapsed = false,\n size,\n label,\n children,\n toolbar,\n header,\n headerList,\n headerPlacement,\n footer,\n footerList,\n bottomToolbar,\n footerPlacement,\n pane,\n separator = 'auto',\n collapseMotion = 'slide',\n contentOverflow = 'clip',\n presentation = 'inline',\n restoreControl,\n restorePosition = side === 'left' ? 'bottom-start' : 'bottom-end',\n className = '',\n}: CollapsiblePanelProps) {\n const sizeVar =\n side === 'bottom'\n ? '--kui-collapsible-panel-height'\n : '--kui-collapsible-panel-width';\n return (\n <>\n <aside\n class={`kui-collapsible-panel kui-collapsible-panel--${side} ${className}`.trim()}\n data-component=\"collapsible-panel\"\n data-collapsible-panel={id}\n data-side={side}\n data-collapsed={String(collapsed)}\n data-separator={separator}\n data-collapse-motion={collapseMotion}\n data-content-overflow={contentOverflow}\n data-presentation={presentation}\n aria-label={label || undefined}\n aria-hidden={\n collapsed || presentation === 'hidden' ? 'true' : undefined\n }\n inert={collapsed}\n style={size ? `${sizeVar}: ${size}px` : undefined}\n >\n <div class=\"kui-collapsible-panel__content\">\n {toolbar\n ? composedPanelBody({\n toolbar,\n side,\n collapsed,\n attributes: toggleAttributes(id),\n pane,\n header,\n headerList,\n headerPlacement,\n footer,\n footerList,\n bottomToolbar,\n footerPlacement,\n content: children,\n })\n : children}\n </div>\n </aside>\n {collapsed && restoreControl && presentation !== 'hidden' && (\n <div\n class=\"kui-collapsible-panel__restore\"\n data-panel-restore={id}\n data-position={restorePosition}\n >\n {restoreControl}\n </div>\n )}\n </>\n );\n}\n\nexport interface CollapsiblePanelRelocatedProps {\n /** The panel's `id`. */\n panelId: string;\n side: CollapsiblePanelSide;\n /** The panel's current collapsed state. */\n collapsed: boolean;\n /** The same `toolbar` the panel receives. */\n toolbar: CollapsiblePanelToolbar;\n}\n\n/**\n * A collapsed {@link CollapsiblePanel}'s marked groups and standard\n * toggle, for the app's work-area toolbar — nothing while the panel is open.\n * Put it first in the leading zone for a left rail, last in the trailing zone\n * for a right rail, and last in a bottom toolbar (or a `FloatingToolbar`\n * `restoreControl`) for a bottom drawer. `wireSidebar` hands focus to it when\n * the panel closes from its own toggle.\n */\nexport function CollapsiblePanelRelocated({\n panelId,\n side,\n collapsed,\n toolbar,\n}: CollapsiblePanelRelocatedProps) {\n return (\n <>\n {relocatedPanelGroups(\n toolbar,\n side,\n collapsed,\n toggleAttributes(panelId),\n )}\n </>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/components/layout/collapsible-panel/collapsible-panel.tsx"],"names":[],"mappings":"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","file":"collapsible-panel.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport {\n collapsiblePanelToggleIcon,\n composedPanelBody,\n type PanelBottomToolbar,\n type PanelChromePlacement,\n type PanelSide,\n type PanelToggle,\n type PanelToggleAttributes,\n type PanelToolbar,\n relocatedPanelGroups,\n} from '../../../shared/panels/panel-toolbar.js';\nimport type { ListConfig } from '../../collections/list/list.js';\nimport { LucideIcon } from '../../media/lucide-icon/lucide-icon.js';\nimport type { PaneConfig } from '../pane/pane.js';\nimport type {\n ResizableRegionCollapseMotion,\n ResizableRegionContentOverflow,\n ResizableRegionPresentation,\n ResizableRegionRestorePosition,\n ResizableRegionSeparator,\n} from '../resizable-region/resizable-region.js';\n\nexport { collapsiblePanelToggleIcon } from '../../../shared/panels/panel-toolbar.js';\n\n/** Which edge a {@link CollapsiblePanel} docks to. */\nexport type CollapsiblePanelSide = PanelSide;\n\n/** The standard toggle a panel toolbar renders (see {@link CollapsiblePanelToolbar}). */\nexport type CollapsiblePanelToolbarToggle = PanelToggle;\n\n/**\n * A panel's composed top toolbar. Its groups occupy `leading`, `center`, and\n * `trailing` while open; groups marked `relocateOnCollapse` and the standard\n * toggle move to the work-area toolbar through\n * {@link CollapsiblePanelRelocated} while it is collapsed.\n */\nexport type CollapsiblePanelToolbar = PanelToolbar;\nexport type CollapsiblePanelBottomToolbar = PanelBottomToolbar;\nexport type CollapsiblePanelChromePlacement = PanelChromePlacement;\n\n/** A CollapsiblePanel toggle's `wireSidebar` hook. */\nconst toggleAttributes = (panelId: string): PanelToggleAttributes => ({\n 'data-collapsible-target': panelId,\n // Keyed, so the morph never reuses a (possibly focused) toggle's button for\n // another control as the toggle moves between toolbars.\n 'data-key': `${panelId}-toggle`,\n});\n\nexport interface CollapsiblePanelToggleProps {\n /** The panel this toggle controls. */\n side: CollapsiblePanelSide;\n /** The panel's current collapsed state (drives the icon direction). */\n collapsed: boolean;\n /** `data-action` the button carries so `wireSidebar` can delegate its click. */\n action: string;\n /** The panel id the button targets (`data-tab-panel`-style: `data-collapsible-panel`). */\n panelId?: string;\n /** Accessible label; defaults to \"Collapse\"/\"Expand\". */\n label?: string;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A standard collapse/expand toggle button for a {@link CollapsiblePanel}: the\n * recognizable per-side icon (see {@link collapsiblePanelToggleIcon}) plus the\n * `data-action` / `aria-expanded` `wireSidebar` reads. Placement is the app's —\n * put it in the panel's own header (to collapse) and somewhere always-visible\n * (to expand while collapsed).\n */\nexport function CollapsiblePanelToggle({\n side,\n collapsed,\n action,\n panelId,\n label,\n className = '',\n slot,\n}: CollapsiblePanelToggleProps) {\n const glyph = collapsiblePanelToggleIcon(side, collapsed);\n const accessible = label ?? (collapsed ? 'Expand' : 'Collapse');\n return (\n <button\n type=\"button\"\n class={`kui-collapsible-panel__toggle ${className}`.trim()}\n data-action={action}\n data-collapsible-target={panelId}\n aria-expanded={String(!collapsed)}\n aria-label={accessible}\n slot={slot}\n >\n <LucideIcon icon={glyph.icon} name={glyph.name} />\n </button>\n );\n}\n\nexport interface CollapsiblePanelProps {\n /** A stable id for the panel — `wireSidebar` targets it and toggles reference it. */\n id: string;\n /** Which edge the panel docks to: a left/right rail or a bottom drawer. */\n side: CollapsiblePanelSide;\n /** Whether the panel is currently collapsed (the app owns this signal). */\n collapsed?: boolean;\n /** Rail width or drawer height in px. Overrides the CSS default. */\n size?: number;\n /** Accessible label for the panel region. */\n label?: string;\n /** Opt into keyboard (`0`) or programmatic (`-1`) focus on the panel region. */\n tabIndex?: 0 | -1;\n /** Keep the standard focus outline visible while the panel is expanded. */\n outlined?: boolean;\n /** Panel content. */\n children?: KerfUiContent;\n /**\n * The panel's top toolbar, composed so its groups follow the panel's open\n * state. With it, `children` renders in a `Pane` below the toolbar; render\n * {@link CollapsiblePanelRelocated} in the app's work-area toolbar so the\n * marked groups and toggle stay reachable while the panel is collapsed.\n */\n toolbar?: CollapsiblePanelToolbar;\n /** Fixed content below a toolbar panel's top toolbar. */\n header?: KerfUiContent;\n headerList?: ListConfig;\n headerPlacement?: CollapsiblePanelChromePlacement;\n /** Fixed content above a toolbar panel's bottom toolbar. */\n footer?: KerfUiContent;\n footerList?: ListConfig;\n bottomToolbar?: CollapsiblePanelBottomToolbar;\n footerPlacement?: CollapsiblePanelChromePlacement;\n /**\n * Configuration for a `toolbar` panel's `Pane` (`contentElement`,\n * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example\n * `{ contentElement: 'nav', contentLabel: 'Sections' }` for a navigation\n * rail. Omitted or `undefined` fields keep the `Pane` defaults. Ignored\n * without a `toolbar`, where `children` renders as given.\n */\n pane?: PaneConfig;\n separator?: ResizableRegionSeparator;\n collapseMotion?: ResizableRegionCollapseMotion;\n contentOverflow?: ResizableRegionContentOverflow;\n presentation?: ResizableRegionPresentation;\n /** Control shown while collapsed, in a safe-area-aware corner of the panel's container (not the viewport). */\n restoreControl?: SafeHtml;\n restorePosition?: ResizableRegionRestorePosition;\n className?: string;\n}\n\n/**\n * A standalone collapsible side rail or bottom drawer, outside the full\n * {@link Workbench} shell. It owns only the presentation: a fixed-size content\n * area that stays laid out while the panel's track snaps to zero and the content\n * slides out via `transform` (one reflow, composited — the same technique\n * `Workbench` and the catalog sidebar use). Bottom-drawer content stays anchored\n * to the panel's fixed bottom edge, so the track cannot move its layout origin\n * underneath the transform transition. A collapsed panel renders `inert` (with\n * `aria-hidden`), so neither Tab, pointer, nor assistive technology reaches\n * content that has slid out of view; its `restoreControl` renders outside the\n * panel and stays reachable.\n * The app owns the `collapsed` signal;\n * pair it with `wireSidebar` for the toggle, focus, compact-overlay, keyboard,\n * and persistence semantics, and with `CollapsiblePanelToggle` for the standard\n * affordance. See `ui/docs/collapsible-panel.md` and `docs/23-app-layouts.md`.\n */\nexport function CollapsiblePanel({\n id,\n side,\n collapsed = false,\n size,\n label,\n tabIndex,\n outlined = false,\n children,\n toolbar,\n header,\n headerList,\n headerPlacement,\n footer,\n footerList,\n bottomToolbar,\n footerPlacement,\n pane,\n separator = 'auto',\n collapseMotion = 'slide',\n contentOverflow = 'clip',\n presentation = 'inline',\n restoreControl,\n restorePosition = side === 'left' ? 'bottom-start' : 'bottom-end',\n className = '',\n}: CollapsiblePanelProps) {\n const sizeVar =\n side === 'bottom'\n ? '--kui-collapsible-panel-height'\n : '--kui-collapsible-panel-width';\n return (\n <>\n <aside\n class={`kui-collapsible-panel kui-collapsible-panel--${side} ${className}`.trim()}\n data-component=\"collapsible-panel\"\n data-collapsible-panel={id}\n data-side={side}\n data-collapsed={String(collapsed)}\n data-outlined={\n !collapsed && presentation !== 'hidden' && outlined\n ? 'true'\n : undefined\n }\n data-separator={separator}\n data-collapse-motion={collapseMotion}\n data-content-overflow={contentOverflow}\n data-presentation={presentation}\n aria-label={label || undefined}\n aria-hidden={\n collapsed || presentation === 'hidden' ? 'true' : undefined\n }\n tabindex={\n collapsed || presentation === 'hidden'\n ? tabIndex === undefined\n ? undefined\n : -1\n : tabIndex\n }\n inert={collapsed}\n style={size ? `${sizeVar}: ${size}px` : undefined}\n >\n <div class=\"kui-collapsible-panel__content\">\n {toolbar\n ? composedPanelBody({\n toolbar,\n side,\n collapsed,\n attributes: toggleAttributes(id),\n pane,\n header,\n headerList,\n headerPlacement,\n footer,\n footerList,\n bottomToolbar,\n footerPlacement,\n content: children,\n })\n : children}\n </div>\n </aside>\n {collapsed && restoreControl && presentation !== 'hidden' && (\n <div\n class=\"kui-collapsible-panel__restore\"\n data-panel-restore={id}\n data-position={restorePosition}\n >\n {restoreControl}\n </div>\n )}\n </>\n );\n}\n\nexport interface CollapsiblePanelRelocatedProps {\n /** The panel's `id`. */\n panelId: string;\n side: CollapsiblePanelSide;\n /** The panel's current collapsed state. */\n collapsed: boolean;\n /** The same `toolbar` the panel receives. */\n toolbar: CollapsiblePanelToolbar;\n}\n\n/**\n * A collapsed {@link CollapsiblePanel}'s marked groups and standard\n * toggle, for the app's work-area toolbar — nothing while the panel is open.\n * Put it first in the leading zone for a left rail, last in the trailing zone\n * for a right rail, and last in a bottom toolbar (or a `FloatingToolbar`\n * `restoreControl`) for a bottom drawer. `wireSidebar` hands focus to it when\n * the panel closes from its own toggle.\n */\nexport function CollapsiblePanelRelocated({\n panelId,\n side,\n collapsed,\n toolbar,\n}: CollapsiblePanelRelocatedProps) {\n return (\n <>\n {relocatedPanelGroups(\n toolbar,\n side,\n collapsed,\n toggleAttributes(panelId),\n )}\n </>\n );\n}\n"]}
@@ -13,10 +13,12 @@ type ContentItemSelectionMode = 'none' | 'single' | 'multiple' | 'toggle';
13
13
  type ContentItemRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
14
14
  'data-component'?: never;
15
15
  'data-appearance'?: never;
16
+ 'data-outlined'?: never;
16
17
  }>;
17
18
  type ContentItemInteractiveRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
18
19
  'data-component'?: never;
19
20
  'data-appearance'?: never;
21
+ 'data-outlined'?: never;
20
22
  'data-action'?: never;
21
23
  'data-item-id'?: never;
22
24
  'data-interactive'?: never;
@@ -57,6 +59,8 @@ interface ContentItemBaseProps {
57
59
  * combined with `data-nav-focus` in `rootAttributes`.
58
60
  */
59
61
  focusTarget?: boolean;
62
+ /** Keep the standard focus outline visible, such as for a drop target. */
63
+ outlined?: boolean;
60
64
  className?: string;
61
65
  /** Native named-slot assignment when composed inside a web component. */
62
66
  slot?: string;
@@ -68,6 +72,8 @@ type ContentItemProps = ContentItemBaseProps & ({
68
72
  selectionMode?: never;
69
73
  selected?: never;
70
74
  disabled?: never;
75
+ /** Opt into keyboard (`0`) or programmatic (`-1`) focus. */
76
+ tabIndex?: 0 | -1;
71
77
  /** Existing static `data-*` metadata remains available. */
72
78
  rootAttributes?: ContentItemRootAttributes;
73
79
  } | {
@@ -79,6 +85,7 @@ type ContentItemProps = ContentItemBaseProps & ({
79
85
  selectionMode?: ContentItemSelectionMode;
80
86
  selected?: boolean;
81
87
  disabled?: boolean;
88
+ tabIndex?: never;
82
89
  /** Safe app metadata; interaction attributes are component-owned. */
83
90
  rootAttributes?: ContentItemInteractiveRootAttributes;
84
91
  });
@@ -87,6 +94,6 @@ type ContentItemProps = ContentItemBaseProps & ({
87
94
  * border (transparent unless `framed`), 8px padding, and a rounded or pill
88
95
  * radius. It owns that whole geometry, so wrappers must not add more.
89
96
  */
90
- declare function ContentItem({ appearance, children, frame, flush, shape, title, ariaLabel, focusTarget, interactive, action, itemId, selectionMode, selected, disabled, className, rootAttributes, slot, }: ContentItemProps): kerfjs.SafeHtml;
97
+ declare function ContentItem({ appearance, children, frame, flush, shape, title, ariaLabel, focusTarget, outlined, tabIndex, interactive, action, itemId, selectionMode, selected, disabled, className, rootAttributes, slot, }: ContentItemProps): kerfjs.SafeHtml;
91
98
 
92
99
  export { ContentItem, type ContentItemAppearance, type ContentItemFrame, type ContentItemProps, type ContentItemSelectionMode, type ContentItemShape, SemanticTone };
@@ -1,4 +1,4 @@
1
- export { ContentItem } from './chunk-VLQUXZKA.js';
1
+ export { ContentItem } from './chunk-7TE6XDFI.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=content-item.js.map
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ export { createTokenSearchModel } from './chunk-IM3GKYOG.js';
9
9
  export { ValueTable, ValueTableRow } from './chunk-H7ZJEI3H.js';
10
10
  export { Spacer } from './chunk-75I3SNUJ.js';
11
11
  export { StateBanner } from './chunk-ARZ4RSQO.js';
12
- export { SunkenPanel } from './chunk-HPREYDKV.js';
12
+ export { SunkenPanel } from './chunk-3XPGJUUQ.js';
13
13
  export { DialogSurface, PopupSurface } from './chunk-A7DYEERU.js';
14
14
  export { TabBar } from './chunk-JOR5LGYE.js';
15
15
  export { SegmentedControl } from './chunk-NS2TBYM4.js';
@@ -22,7 +22,7 @@ export { AppTab } from './chunk-HFLGWMG3.js';
22
22
  export { PopupMenu, closePopupMenu, openPopupMenuAt } from './chunk-NJZMR7HM.js';
23
23
  export { ResizableRegion, clampRegionSize, resizeRegionFromPointer } from './chunk-Y6KT7ZTR.js';
24
24
  export { Row } from './chunk-5D3WDMIK.js';
25
- export { ListHeader } from './chunk-M6BWQMQY.js';
25
+ export { ListHeader } from './chunk-VIGVNDXZ.js';
26
26
  export { FieldLabel, Text } from './chunk-4Y4L5YEI.js';
27
27
  export { ListInsetText } from './chunk-NMWDHZVM.js';
28
28
  export { ListItem, ListItemLink } from './chunk-HFQDSSED.js';
@@ -35,12 +35,12 @@ export { Badge } from './chunk-J3AWE5I4.js';
35
35
  export { Chip } from './chunk-DQDTZE4W.js';
36
36
  export { ToolbarActionLink, ToolbarControlGroup } from './chunk-RRCD3A6G.js';
37
37
  export { Toolbar } from './chunk-BYHGRKC3.js';
38
- export { Pane } from './chunk-DXQZ3BEO.js';
38
+ export { Pane } from './chunk-FL6J644M.js';
39
39
  export { List } from './chunk-NVRJ7C3W.js';
40
40
 
41
41
  export { LucideIcon } from './chunk-PQQQXJGV.js';
42
42
  export { LoadingSpinner } from './chunk-3RE2JMZU.js';
43
- export { ContentItem } from './chunk-VLQUXZKA.js';
43
+ export { ContentItem } from './chunk-7TE6XDFI.js';
44
44
 
45
45
  export { calc, colorVar, em, flex, foregroundColor, foregroundColorVar, lengthVar, pct, plus, px, rem, space, uiColor } from './chunk-LRAIS3YB.js';
46
46
 
@@ -89,13 +89,8 @@ type ListHeaderIndicatorProps = {
89
89
  } | {
90
90
  count?: never;
91
91
  countLabel?: never;
92
- badge: SafeHtml;
93
- status?: never;
94
- } | {
95
- count?: never;
96
- countLabel?: never;
97
- badge?: never;
98
- status?: SafeHtml;
92
+ badge?: SafeHtml | undefined;
93
+ status?: SafeHtml | undefined;
99
94
  };
100
95
  type ListHeaderProps = ListHeaderBaseProps & ListHeaderIndicatorProps & ListHeaderModeProps;
101
96
  declare function ListHeader({ label, size, headingLevel, count, countLabel, badge, status, density, divider, inline, width, indicatorTone, action, actionLabel, actionIcon, actionDisabled, disabledReason, expanded, toggle, placeholder, rootAttributes, triggerAttributes, slot, }: ListHeaderProps): SafeHtml;
@@ -1,4 +1,4 @@
1
- export { ListHeader } from './chunk-M6BWQMQY.js';
1
+ export { ListHeader } from './chunk-VIGVNDXZ.js';
2
2
 
3
3
 
4
4
 
package/dist/nav-stack.js CHANGED
@@ -1,4 +1,4 @@
1
- export { NavStack } from './chunk-IKCUPTR2.js';
1
+ export { NavStack } from './chunk-CVKIADIS.js';
2
2
 
3
3
 
4
4
 
package/dist/pane.d.ts CHANGED
@@ -24,6 +24,7 @@ type PaneRootAttributes = Readonly<Record<`data-${string}`, string | undefined>
24
24
  'data-chrome-dividers'?: never;
25
25
  'data-appearance'?: never;
26
26
  'data-deep-inset'?: never;
27
+ 'data-outlined'?: never;
27
28
  }>;
28
29
  /** How a Pane's header and footer relate to its scrolling content. */
29
30
  type PaneChromePlacement = 'fixed' | 'auto';
@@ -63,8 +64,12 @@ interface PaneProps {
63
64
  chromeDividers?: PaneChromeDividers;
64
65
  /** Paint the scrolling work surface with the shared lowered-surface color. */
65
66
  appearance?: PaneAppearance;
66
- /** Add an extra 8px inline gutter to scrolling content (default: false). */
67
+ /** Add 8px to every side of scrolling content (default: false). */
67
68
  deepInset?: boolean;
69
+ /** Opt into keyboard (`0`) or programmatic (`-1`) focus on the Pane root. */
70
+ tabIndex?: 0 | -1;
71
+ /** Keep the standard focus outline visible, such as for a drop target. */
72
+ outlined?: boolean;
68
73
  /** Root semantics. Defaults to `div`. */
69
74
  element?: PaneElement;
70
75
  /** Scrolling content semantics. Defaults to `div`. */
@@ -99,13 +104,13 @@ interface PaneProps {
99
104
  * or a CollapsiblePanel) forwards, so the app configures that pane instead of
100
105
  * styling it. An omitted or `undefined` field keeps the composite's default.
101
106
  */
102
- type PaneConfig = Pick<PaneProps, 'contentElement' | 'contentLabel' | 'separators' | 'safeAreaEdges' | 'chromeDividers' | 'appearance' | 'deepInset'>;
107
+ type PaneConfig = Pick<PaneProps, 'contentElement' | 'contentLabel' | 'separators' | 'safeAreaEdges' | 'chromeDividers' | 'appearance' | 'deepInset' | 'tabIndex' | 'outlined'>;
103
108
  /**
104
109
  * An unpadded application column with optional fixed header/footer slots and one
105
110
  * scrolling vertical content owner. Separator lines are independently opt-in on
106
111
  * each logical edge, so the same component works as a sidebar, main area,
107
112
  * inspector, or dialog column.
108
113
  */
109
- declare function Pane({ header, children, footer, chromePlacement, chromeDividers, appearance, deepInset, element, contentElement, separators, safeAreaEdges, id, label, contentLabel, className, headerClassName, contentClassName, footerClassName, rootAttributes, slot, }: PaneProps): kerfjs.SafeHtml;
114
+ declare function Pane({ header, children, footer, chromePlacement, chromeDividers, appearance, deepInset, tabIndex, outlined, element, contentElement, separators, safeAreaEdges, id, label, contentLabel, className, headerClassName, contentClassName, footerClassName, rootAttributes, slot, }: PaneProps): kerfjs.SafeHtml;
110
115
 
111
116
  export { Pane, type PaneAppearance, type PaneChromeDividers, type PaneChromePlacement, type PaneConfig, type PaneContentElement, type PaneElement, type PaneProps, type PaneSeparatorSide };
package/dist/pane.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Pane } from './chunk-DXQZ3BEO.js';
1
+ export { Pane } from './chunk-FL6J644M.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=pane.js.map
@@ -1,4 +1,4 @@
1
- import { NavStack } from './chunk-IKCUPTR2.js';
1
+ import { NavStack } from './chunk-CVKIADIS.js';
2
2
  import { ResizableRegion } from './chunk-Y6KT7ZTR.js';
3
3
 
4
4
 
@@ -35,6 +35,11 @@
35
35
  background: var(--kui-color-surface);
36
36
  }
37
37
 
38
+ .kui-collapsible-panel:is(:focus-visible, [data-outlined="true"]) {
39
+ outline: var(--kui-focus-ring);
40
+ outline-offset: -3px;
41
+ }
42
+
38
43
  .kui-collapsible-panel--left,
39
44
  .kui-collapsible-panel--right {
40
45
  width: var(--_kui-collapsible-panel-extent);
@@ -35,6 +35,11 @@
35
35
  background: var(--kui-color-surface);
36
36
  }
37
37
 
38
+ .kui-collapsible-panel:is(:focus-visible, [data-outlined="true"]) {
39
+ outline: var(--kui-focus-ring);
40
+ outline-offset: -3px;
41
+ }
42
+
38
43
  .kui-collapsible-panel--left,
39
44
  .kui-collapsible-panel--right {
40
45
  width: var(--_kui-collapsible-panel-extent);
@@ -22,6 +22,11 @@
22
22
  grid-template-rows: auto minmax(0, 1fr) auto;
23
23
  }
24
24
 
25
+ .kui-pane:is(:focus-visible, [data-outlined="true"]) {
26
+ outline: var(--kui-focus-ring);
27
+ outline-offset: -3px;
28
+ }
29
+
25
30
  /* Paint the active scroll owner once, so alpha lowered colors do not stack.
26
31
  Fixed chrome leaves the content slot scrolling; auto chrome lets the Pane
27
32
  root scroll in its short mode, while its content remains transparent. */
@@ -146,8 +151,16 @@
146
151
  pane edge while keeping their own content aligned with ordinary items. */
147
152
  --kui-pane-content-inset-inline-start: var(--_kui-pane-safe-inline-start);
148
153
  --kui-pane-content-inset-inline-end: var(--_kui-pane-safe-inline-end);
149
- --_kui-pane-content-block-start: var(--_kui-pane-safe-block-start);
150
- --_kui-pane-content-block-end: var(--_kui-pane-safe-block-end);
154
+ --_kui-pane-deep-block-inset: 0px;
155
+ --_kui-pane-content-safe-block-start: var(--_kui-pane-safe-block-start);
156
+ --_kui-pane-content-safe-block-end: var(--_kui-pane-safe-block-end);
157
+ --_kui-pane-content-block-start: calc(
158
+ var(--_kui-pane-content-safe-block-start) +
159
+ var(--_kui-pane-deep-block-inset)
160
+ );
161
+ --_kui-pane-content-block-end: calc(
162
+ var(--_kui-pane-content-safe-block-end) + var(--_kui-pane-deep-block-inset)
163
+ );
151
164
  min-width: 0;
152
165
  min-height: 0;
153
166
  overflow: auto;
@@ -167,6 +180,7 @@
167
180
  /* Add one outer gutter without changing the inherited item-margin token.
168
181
  Nested Row, List, and Grid therefore keep their own default 8px insets. */
169
182
  .kui-pane[data-deep-inset="true"] > .kui-pane__content {
183
+ --_kui-pane-deep-block-inset: var(--kui-space-xs);
170
184
  --kui-pane-content-inset-inline-start: calc(
171
185
  var(--_kui-pane-safe-inline-start) + var(--kui-space-xs)
172
186
  );
@@ -176,11 +190,11 @@
176
190
  }
177
191
 
178
192
  .kui-pane__header ~ .kui-pane__content {
179
- --_kui-pane-content-block-start: 0px;
193
+ --_kui-pane-content-safe-block-start: 0px;
180
194
  }
181
195
 
182
196
  .kui-pane__content:has(~ .kui-pane__footer) {
183
- --_kui-pane-content-block-end: 0px;
197
+ --_kui-pane-content-safe-block-end: 0px;
184
198
  }
185
199
 
186
200
  .kui-pane__footer {
@@ -105,6 +105,14 @@
105
105
  overflow: auto;
106
106
  }
107
107
 
108
+ :is(.kui-workbench__main, .kui-workbench__rail, .kui-workbench__drawer):is(
109
+ :focus-visible,
110
+ [data-outlined="true"]
111
+ ) {
112
+ outline: var(--kui-focus-ring);
113
+ outline-offset: -3px;
114
+ }
115
+
108
116
  /* When no Pane chrome is composed, the Workbench region owns its scroll.
109
117
  A resizable auto-overflow panel instead scrolls its content box so its
110
118
  separator handle remains fixed. Paint only that owner. */
@@ -209,7 +217,7 @@
209
217
  composed toolbar's footer (or the app's own) sits at the region's bottom
210
218
  edge rather than under short content. Each of those components fills the
211
219
  region from its own stylesheet (pane.css, nav-stack.css, split-view.css,
212
- tab-scaffold.css); a nested Workbench fills it here. */
220
+ tab-navigator.css); a nested Workbench fills it here. */
213
221
  :is(.kui-workbench__main, .kui-workbench__panel-content)
214
222
  > [data-component="workbench"]:only-child {
215
223
  height: 100%;
@@ -46,6 +46,11 @@
46
46
  inset: 0;
47
47
  }
48
48
 
49
+ .kui-tab-scaffold__scene:is(:focus-visible, [data-outlined="true"]) {
50
+ outline: var(--kui-focus-ring);
51
+ outline-offset: -3px;
52
+ }
53
+
49
54
  .kui-tab-scaffold__scene[data-appearance="sunken"] {
50
55
  background: var(
51
56
  --kui-sunken-panel-background,
@@ -86,8 +91,16 @@
86
91
  ):only-child
87
92
  )
88
93
  ) {
94
+ padding-block-start: calc(
95
+ var(--kui-edge-inset-block-start) + var(--kui-space-xs)
96
+ );
97
+ padding-block-end: var(--kui-space-xs);
89
98
  padding-inline: calc(var(--kui-edge-inset-inline-start) + var(--kui-space-xs))
90
99
  calc(var(--kui-edge-inset-inline-end) + var(--kui-space-xs));
100
+ scroll-padding-block: calc(
101
+ var(--kui-edge-inset-block-start) + var(--kui-space-xs)
102
+ )
103
+ var(--kui-space-xs);
91
104
  }
92
105
 
93
106
  .kui-tab-scaffold__scene
@@ -108,7 +108,7 @@
108
108
  --kui-content-item-foreground: var(--kui-color-brand-on-fill);
109
109
  }
110
110
 
111
- .kui-content-item[data-interactive="true"]:focus-visible {
111
+ .kui-content-item:is(:focus-visible, [data-outlined="true"]) {
112
112
  outline: var(--kui-focus-ring);
113
113
  outline-offset: 1px;
114
114
  }
@@ -27,3 +27,8 @@
27
27
  .kui-sunken-panel[data-shape="square"] {
28
28
  border-radius: 0;
29
29
  }
30
+
31
+ .kui-sunken-panel:is(:focus-visible, [data-outlined="true"]) {
32
+ outline: var(--kui-focus-ring);
33
+ outline-offset: -3px;
34
+ }
@@ -108,7 +108,7 @@
108
108
  --kui-content-item-foreground: var(--kui-color-brand-on-fill);
109
109
  }
110
110
 
111
- .kui-content-item[data-interactive="true"]:focus-visible {
111
+ .kui-content-item:is(:focus-visible, [data-outlined="true"]) {
112
112
  outline: var(--kui-focus-ring);
113
113
  outline-offset: 1px;
114
114
  }
@@ -22,6 +22,11 @@
22
22
  grid-template-rows: auto minmax(0, 1fr) auto;
23
23
  }
24
24
 
25
+ .kui-pane:is(:focus-visible, [data-outlined="true"]) {
26
+ outline: var(--kui-focus-ring);
27
+ outline-offset: -3px;
28
+ }
29
+
25
30
  /* Paint the active scroll owner once, so alpha lowered colors do not stack.
26
31
  Fixed chrome leaves the content slot scrolling; auto chrome lets the Pane
27
32
  root scroll in its short mode, while its content remains transparent. */
@@ -146,8 +151,16 @@
146
151
  pane edge while keeping their own content aligned with ordinary items. */
147
152
  --kui-pane-content-inset-inline-start: var(--_kui-pane-safe-inline-start);
148
153
  --kui-pane-content-inset-inline-end: var(--_kui-pane-safe-inline-end);
149
- --_kui-pane-content-block-start: var(--_kui-pane-safe-block-start);
150
- --_kui-pane-content-block-end: var(--_kui-pane-safe-block-end);
154
+ --_kui-pane-deep-block-inset: 0px;
155
+ --_kui-pane-content-safe-block-start: var(--_kui-pane-safe-block-start);
156
+ --_kui-pane-content-safe-block-end: var(--_kui-pane-safe-block-end);
157
+ --_kui-pane-content-block-start: calc(
158
+ var(--_kui-pane-content-safe-block-start) +
159
+ var(--_kui-pane-deep-block-inset)
160
+ );
161
+ --_kui-pane-content-block-end: calc(
162
+ var(--_kui-pane-content-safe-block-end) + var(--_kui-pane-deep-block-inset)
163
+ );
151
164
  min-width: 0;
152
165
  min-height: 0;
153
166
  overflow: auto;
@@ -167,6 +180,7 @@
167
180
  /* Add one outer gutter without changing the inherited item-margin token.
168
181
  Nested Row, List, and Grid therefore keep their own default 8px insets. */
169
182
  .kui-pane[data-deep-inset="true"] > .kui-pane__content {
183
+ --_kui-pane-deep-block-inset: var(--kui-space-xs);
170
184
  --kui-pane-content-inset-inline-start: calc(
171
185
  var(--_kui-pane-safe-inline-start) + var(--kui-space-xs)
172
186
  );
@@ -176,11 +190,11 @@
176
190
  }
177
191
 
178
192
  .kui-pane__header ~ .kui-pane__content {
179
- --_kui-pane-content-block-start: 0px;
193
+ --_kui-pane-content-safe-block-start: 0px;
180
194
  }
181
195
 
182
196
  .kui-pane__content:has(~ .kui-pane__footer) {
183
- --_kui-pane-content-block-end: 0px;
197
+ --_kui-pane-content-safe-block-end: 0px;
184
198
  }
185
199
 
186
200
  .kui-pane__footer {
@@ -27,3 +27,8 @@
27
27
  .kui-sunken-panel[data-shape="square"] {
28
28
  border-radius: 0;
29
29
  }
30
+
31
+ .kui-sunken-panel:is(:focus-visible, [data-outlined="true"]) {
32
+ outline: var(--kui-focus-ring);
33
+ outline-offset: -3px;
34
+ }
@@ -46,6 +46,11 @@
46
46
  inset: 0;
47
47
  }
48
48
 
49
+ .kui-tab-scaffold__scene:is(:focus-visible, [data-outlined="true"]) {
50
+ outline: var(--kui-focus-ring);
51
+ outline-offset: -3px;
52
+ }
53
+
49
54
  .kui-tab-scaffold__scene[data-appearance="sunken"] {
50
55
  background: var(
51
56
  --kui-sunken-panel-background,
@@ -86,8 +91,16 @@
86
91
  ):only-child
87
92
  )
88
93
  ) {
94
+ padding-block-start: calc(
95
+ var(--kui-edge-inset-block-start) + var(--kui-space-xs)
96
+ );
97
+ padding-block-end: var(--kui-space-xs);
89
98
  padding-inline: calc(var(--kui-edge-inset-inline-start) + var(--kui-space-xs))
90
99
  calc(var(--kui-edge-inset-inline-end) + var(--kui-space-xs));
100
+ scroll-padding-block: calc(
101
+ var(--kui-edge-inset-block-start) + var(--kui-space-xs)
102
+ )
103
+ var(--kui-space-xs);
91
104
  }
92
105
 
93
106
  .kui-tab-scaffold__scene
@@ -105,6 +105,14 @@
105
105
  overflow: auto;
106
106
  }
107
107
 
108
+ :is(.kui-workbench__main, .kui-workbench__rail, .kui-workbench__drawer):is(
109
+ :focus-visible,
110
+ [data-outlined="true"]
111
+ ) {
112
+ outline: var(--kui-focus-ring);
113
+ outline-offset: -3px;
114
+ }
115
+
108
116
  /* When no Pane chrome is composed, the Workbench region owns its scroll.
109
117
  A resizable auto-overflow panel instead scrolls its content box so its
110
118
  separator handle remains fixed. Paint only that owner. */
@@ -209,7 +217,7 @@
209
217
  composed toolbar's footer (or the app's own) sits at the region's bottom
210
218
  edge rather than under short content. Each of those components fills the
211
219
  region from its own stylesheet (pane.css, nav-stack.css, split-view.css,
212
- tab-scaffold.css); a nested Workbench fills it here. */
220
+ tab-navigator.css); a nested Workbench fills it here. */
213
221
  :is(.kui-workbench__main, .kui-workbench__panel-content)
214
222
  > [data-component="workbench"]:only-child {
215
223
  height: 100%;
@@ -13,6 +13,10 @@ interface SunkenPanelProps {
13
13
  flex?: boolean | CssFlexKeyword | CssFlex;
14
14
  /** Fill a parent with a definite height; use flex inside a flex layout. */
15
15
  fill?: boolean;
16
+ /** Opt into keyboard (`0`) or programmatic (`-1`) focus on the panel. */
17
+ tabIndex?: 0 | -1;
18
+ /** Keep the standard focus outline visible, such as for a drop target. */
19
+ outlined?: boolean;
16
20
  className?: string;
17
21
  /** Native named-slot assignment when composed inside a web component. */
18
22
  slot?: string;
@@ -22,6 +26,6 @@ interface SunkenPanelProps {
22
26
  * stack. The panel owns its background and padding; children own their own
23
27
  * borders and internal geometry.
24
28
  */
25
- declare function SunkenPanel({ children, ariaLabel, shape, flex, fill, className, slot, }: SunkenPanelProps): kerfjs.SafeHtml;
29
+ declare function SunkenPanel({ children, ariaLabel, shape, flex, fill, tabIndex, outlined, className, slot, }: SunkenPanelProps): kerfjs.SafeHtml;
26
30
 
27
31
  export { SunkenPanel, type SunkenPanelProps, type SunkenPanelShape };
@@ -1,3 +1,3 @@
1
- export { SunkenPanel } from './chunk-HPREYDKV.js';
1
+ export { SunkenPanel } from './chunk-3XPGJUUQ.js';
2
2
 
3
3
  //# sourceMappingURL=sunken-panel.js.map
@@ -11,8 +11,12 @@ interface TabNavigatorTabBase<Id extends string> {
11
11
  content: KerfUiContent;
12
12
  /** Background of this scene's scrolling work surface. */
13
13
  appearance?: PaneAppearance;
14
- /** Add an extra 8px inline gutter to a plain scene's scrolling content. */
14
+ /** Add 8px to every side of a plain scene's scrolling content. */
15
15
  deepInset?: boolean;
16
+ /** Opt into keyboard (`0`) or programmatic (`-1`) focus on this scene. */
17
+ tabIndex?: 0 | -1;
18
+ /** Keep the standard focus outline visible while this scene is active. */
19
+ outlined?: boolean;
16
20
  }
17
21
  /** A tab with an optional count or short-status badge. */
18
22
  interface TabNavigatorTabCountBadge {
@@ -28,7 +28,11 @@ function TabNavigator({
28
28
  "data-active": String(tab.id === active),
29
29
  "data-appearance": tab.appearance === "sunken" ? "sunken" : void 0,
30
30
  "data-deep-inset": tab.deepInset ? "true" : void 0,
31
+ "data-outlined": tab.id === active && tab.outlined ? "true" : void 0,
32
+ role: tab.tabIndex === void 0 ? void 0 : "tabpanel",
33
+ "aria-label": tab.tabIndex === void 0 ? void 0 : tab.label,
31
34
  "aria-hidden": String(tab.id !== active),
35
+ tabindex: tab.id === active ? tab.tabIndex : tab.tabIndex === void 0 ? void 0 : -1,
32
36
  children: tab.content
33
37
  }
34
38
  )) }),