@kerfjs/ui 5.0.0-beta.26 → 5.0.0-beta.29

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.
@@ -1,6 +1,6 @@
1
1
  # Public API signatures for the UI authoring corpus
2
2
 
3
- Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.26` and `kerfjs@5.0.0-beta.26`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
3
+ Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.29` and `kerfjs@5.0.0-beta.29`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
4
4
 
5
5
  ## `@kerfjs/ui/disclosure-arrow`
6
6
 
@@ -1387,6 +1387,10 @@ type SelectAccessibleName = {
1387
1387
  label?: never;
1388
1388
  ariaLabel: string;
1389
1389
  };
1390
+ type SelectPresentation = 'form' | 'toolbar-borderless' | 'navigation';
1391
+ type SelectSize = 'default' | 'compact';
1392
+ type SelectSelectedPresentation = 'label' | 'icon-only';
1393
+ type SelectFocusRingOwner = 'select' | 'group';
1390
1394
  interface SelectBaseProps<Value extends string = string> {
1391
1395
  name: string;
1392
1396
  value: NoInfer<Value>;
@@ -1402,19 +1406,19 @@ interface SelectBaseProps<Value extends string = string> {
1402
1406
  /** Render as an unanimated loading skeleton: the label above a static, empty control box. */
1403
1407
  placeholder?: boolean;
1404
1408
  /** Form (default), borderless toolbar, or intrinsic navigation chrome. */
1405
- presentation?: 'form' | 'toolbar-borderless' | 'navigation';
1406
- size?: 'default' | 'compact';
1409
+ presentation?: SelectPresentation;
1410
+ size?: SelectSize;
1407
1411
  /** Show only the selected choice icon while retaining the Select's accessible name. */
1408
- selectedPresentation?: 'label' | 'icon-only';
1412
+ selectedPresentation?: SelectSelectedPresentation;
1409
1413
  /** Let an enclosing ToolbarControlGroup paint the composed focus ring. */
1410
- focusRingOwner?: 'select' | 'group';
1414
+ focusRingOwner?: SelectFocusRingOwner;
1411
1415
  /** Maximum closed-control label width in CSS pixels before ellipsis. */
1412
1416
  labelMaxWidth?: number;
1413
1417
  }
1414
1418
  type SelectProps<Value extends string = string> = SelectBaseProps<Value> & SelectAccessibleName;
1415
1419
  declare function Select<Value extends string>({ name, value, label, ariaLabel, choices, className, placeholderText, hint, disabled, fitMenu, renderSelected, placeholder, presentation, size, selectedPresentation, focusRingOwner, labelMaxWidth, }: SelectProps<Value>): SafeHtml;
1416
1420
 
1417
- export { Select, type SelectChoice, type SelectProps };
1421
+ export { Select, type SelectChoice, type SelectFocusRingOwner, type SelectPresentation, type SelectProps, type SelectSelectedPresentation, type SelectSize };
1418
1422
  ```
1419
1423
 
1420
1424
  ## `@kerfjs/ui/state-banner`
package/ai/skill.md CHANGED
@@ -97,9 +97,9 @@ Hard rules:
97
97
  3. Keep state, product copy, persistence, and domain mappings in the application. Do not add product-specific actions or fields to a generic component. Put ListItem/ListActionRow/ListHeader/AppTab domain `data-*` metadata in `rootAttributes`; use ListActionRow `trailingActionAttributes` and ListHeader `triggerAttributes` only for domain `data-*` or native popover target/action and `aria-controls`/`aria-haspopup`. These slots do not replace component-owned action, item/tab identity, selection, disclosure, naming, disabled, icon, or role semantics.
98
98
  4. Wire `data-action` hooks from one stable root with `delegate()` or `delegateActions()` and retain disposers.
99
99
  5. Use the opinionated `--kui-color-*` semantic ramps and component-level override properties. Override tokens at the narrowest useful scope and prefer equivalent props/tokens. Public-class-to-public-class selectors are supported when every Kerf class appears in the catalog entry's `publicClasses`; never target descendant tags, ids, attribute-only anatomy, or unlisted implementation classes.
100
- 6. `Select` is pure until the app explicitly imports `@kerfjs/ui/select/register`; do not import Web Awesome's full registration bundle. When an app writes direct `wa-*` JSX, add `import type {} from '@kerfjs/ui/webawesome'` for the catalog-supported intrinsic-element declarations, import the CSS-only `@kerfjs/ui/webawesome.css` theme once, and keep importing individual Web Awesome component modules so their JavaScript remains tree-shakeable. The type boundary emits no code and registers nothing. Pass icon-bearing `choices` and `renderSelected` content normally: `Select` preserves its slotted option icons across Kerf rerenders and keys selected content by the controlled value, so app wrappers must not add competing morph-control attributes. Give it a visible `label` or an `ariaLabel` for a visually hidden name; the nonempty visible label takes precedence and the package names the actual shadow combobox, including `renderSelected`, without adding label geometry. Use `hint` for persistent supporting text below the control and `placeholderText` only for the empty value inside the closed control; loading placeholders retain the hint.
100
+ 6. `Select` is pure until the app explicitly imports `@kerfjs/ui/select/register`; do not import Web Awesome's full registration bundle. When an app writes direct `wa-*` JSX, add `import type {} from '@kerfjs/ui/webawesome'` for the catalog-supported intrinsic-element declarations, import the CSS-only `@kerfjs/ui/webawesome.css` theme once, and keep importing individual Web Awesome component modules so their JavaScript remains tree-shakeable. The type boundary emits no code and registers nothing. Pass icon-bearing `choices` and `renderSelected` content normally: `Select` preserves its slotted option icons across Kerf rerenders and keys selected content by the controlled value, so app wrappers must not add competing morph-control attributes. Give it a visible `label` or an `ariaLabel` for a visually hidden name; the nonempty visible label takes precedence and the package names the actual shadow combobox, including `renderSelected`, without adding label geometry. Use `hint` for persistent supporting text below the control and `placeholderText` only for the empty value inside the closed control; loading placeholders retain the hint. When testing name or description, target the element with the `combobox` role rather than the `wa-select` wrapper. Web Awesome's hint attribute and explicit hint slot both describe that shadow combobox across supported engines; do not add an `aria-description` mirror or application shadow-DOM patch.
101
101
  7. Decorative icons are hidden; controls are named; focus is visible; state never relies on color alone; reduced motion and increased contrast remain usable. `DisclosureArrow` defaults to an 18px root-scaled visual and exposes `--kui-disclosure-arrow-size` for consumer sizing; it never becomes the interaction or accessible-name owner. Put it in an owning native control with a stable accessible name and controlled `aria-expanded`. `ListHeader` toggle mode supplies it when `actionIcon` is omitted, but the app must reveal matching content; a custom icon replaces it. Author replacement icon content facing right before its configured direction transform is applied. Direction changes take the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. Kerf `Select` separately keeps its intrinsic Web Awesome expand glyph at `--kui-disclosure-icon-scale: .5`.
102
- 8. `ResizableRegion` uses `wireResizableRegions()` for Arrow, Shift+Arrow, Home/End, and pointer behavior. The app owns size persistence. `handleIcon` replaces decorative dormant glyph content only.
102
+ 8. `ResizableRegion` uses `wireResizableRegions()` for Arrow, Shift+Arrow, Home/End, and pointer behavior. The app owns size persistence. `handleIcon` replaces decorative dormant glyph content only. For compact overlays, set `presentation="overlay"` and the overlay maximum variables; Kerf clamps both the region track and its fixed-size animated content, so do not add descendant width/height overrides.
103
103
  9. Use controlled `SegmentedControl` for a small exclusive choice set. Select `appearance="toolbar"` when nesting it inside `ToolbarControlGroup`; use rounded or pill shapes for standalone contexts. Handle its action, update `value`, keep meaningful choice labels, and preserve every enabled native button in sequential Tab order.
104
104
  10. Compose `AppTab` inside controlled `TabBar`; call `wireTabBars()` once and retain its disposer. It owns same-bar drag mechanics, including proximity-based horizontal edge autoscroll, while the app applies `onReorder` and owns order, selection, panels, close policy, routing, and persistence. Arrow/Home/End select on move by default and restore focus by bar/tab identity when controlled activation replaces the strip; pass `activation: 'manual'` (or `TabBar activation="manual"` per strip) so arrow keys move focus only and the user selects with Enter/Space/click — use it when selecting a tab is a heavy action. Use runtime-filtered `rootAttributes` for domain metadata and keep an optional `closeIcon` decorative and noninteractive.
105
105
  11. Use token-controlled `TokenSearchField` when free text and removable structured filters share one editor. Editable text stays DOM-owned between token changes. The leading icon, first text line, clear action, and trailing slot share one fixed row when content wraps. The app owns parsing and suggestions; call `readTokenSearchField()` on input, empty `textContent` on clear, use `placeTokenSearchCaret()` after explicit controlled focus changes, and call `wireTokenSearchFields()` once so Enter submits without inserting a line break and keyboard chip deletion restores focus plus the text-relative caret after controlled replacement. Enable `collapsible` for an animated iconic closed state, standalone or inside `ToolbarControlGroup`; the field keeps text or tokens expanded, and `wireTokenSearchFields()` manages the transient expand/collapse/focus by default (activate to reveal + focus, Escape or empty blur to collapse). Bind the field's `expanded` to the returned handle's `expanded(id)` signal or adopt your own via `collapsible.signals`; opt a behavior out only when the app must own it. Do not hand-roll the open handler, the focusout collapse, a clear-button mousedown guard, or reopening after controlled clear or Select All deletion — the helper keeps the replacement editor open and focused. Deletion restoration finishes before the next keystroke, so a delayed animation frame cannot overwrite a later selection. Persist both query and tokens returned by the DOM read. For real-app adoption it also provides a focusout keep-open exception (`data-token-search-keep-open` regions or `collapsible.keepOpenOn(target)`, so a sibling suggestions/date/help surface does not collapse an empty field), opt-in atomic-chip keyboard (`keyboard`: Backspace/Delete remove the adjacent chip via `onRemoveToken`, ArrowRight moves the caret past a trailing chip), and an `onEdit({id, editor, event})` input callback (the `InputEvent` lets you gate on `inputType`/`data`) — reach for these instead of re-adding hand-rolled keydown/input handlers around the field.
@@ -1,6 +1,6 @@
1
1
  # Web Awesome JSX signatures for the UI authoring corpus
2
2
 
3
- Generated from the emitted `@kerfjs/ui@5.0.0-beta.26` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
3
+ Generated from the emitted `@kerfjs/ui@5.0.0-beta.29` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
4
4
 
5
5
  ```ts
6
6
  import { KerfCustomElement } from 'kerfjs/jsx-runtime';
@@ -132,4 +132,4 @@ function Select({
132
132
 
133
133
  export { Select };
134
134
 
135
- //# sourceMappingURL=chunk-FRVS5RFM.js.map
135
+ //# sourceMappingURL=chunk-2NMQW7FX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/select.tsx"],"names":[],"mappings":"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","file":"chunk-2NMQW7FX.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\nimport { ChevronDown } from 'lucide';\n\nimport { LucideIcon, type LucideNode } from './lucide-icon.js';\nimport { Skeleton } from './skeleton.js';\n\nexport interface SelectChoice<Value extends string = string> {\n value: Value;\n label: string;\n icon?: LucideNode;\n iconName?: string;\n color?: string;\n group?: string;\n separatorBefore?: boolean;\n}\n\ntype SelectAccessibleName =\n { label: string; ariaLabel?: string } | { label?: never; ariaLabel: string };\n\nexport type SelectPresentation = 'form' | 'toolbar-borderless' | 'navigation';\nexport type SelectSize = 'default' | 'compact';\nexport type SelectSelectedPresentation = 'label' | 'icon-only';\nexport type SelectFocusRingOwner = 'select' | 'group';\n\ninterface SelectBaseProps<Value extends string = string> {\n name: string;\n value: NoInfer<Value>;\n choices: readonly SelectChoice<Value>[];\n className?: string;\n /** Empty-value hint text shown in the closed control (the native select placeholder). */\n placeholderText?: string;\n /** Supporting text shown below the control and associated with its combobox. */\n hint?: string;\n disabled?: boolean;\n fitMenu?: boolean;\n renderSelected?: (choice: SelectChoice<Value>) => SafeHtml;\n /** Render as an unanimated loading skeleton: the label above a static, empty control box. */\n placeholder?: boolean;\n /** Form (default), borderless toolbar, or intrinsic navigation chrome. */\n presentation?: SelectPresentation;\n size?: SelectSize;\n /** Show only the selected choice icon while retaining the Select's accessible name. */\n selectedPresentation?: SelectSelectedPresentation;\n /** Let an enclosing ToolbarControlGroup paint the composed focus ring. */\n focusRingOwner?: SelectFocusRingOwner;\n /** Maximum closed-control label width in CSS pixels before ellipsis. */\n labelMaxWidth?: number;\n}\n\nexport type SelectProps<Value extends string = string> =\n SelectBaseProps<Value> & SelectAccessibleName;\n\nexport function Select<Value extends string>({\n name,\n value,\n label,\n ariaLabel,\n choices,\n className = '',\n placeholderText,\n hint,\n disabled = false,\n fitMenu = false,\n renderSelected,\n placeholder = false,\n presentation = 'form',\n size = 'default',\n selectedPresentation = 'label',\n focusRingOwner = 'select',\n labelMaxWidth,\n}: SelectProps<Value>) {\n if (placeholder) {\n return (\n <div\n class={`kui-select kui-select--placeholder ${className}`.trim()}\n data-component=\"select\"\n data-placeholder=\"true\"\n data-presentation={presentation}\n data-size={size}\n data-selected-presentation={selectedPresentation}\n data-focus-ring-owner={focusRingOwner}\n aria-busy=\"true\"\n style={\n labelMaxWidth === undefined\n ? undefined\n : `--kui-select-label-max-width:${labelMaxWidth}px`\n }\n >\n {label && <span class=\"kui-select__placeholder-label\">{label}</span>}\n <span\n class=\"kui-select__placeholder-box\"\n aria-label={ariaLabel}\n role=\"img\"\n >\n <Skeleton width=\"10em\" />\n <span class=\"kui-select__placeholder-chevron\" aria-hidden=\"true\">\n <LucideIcon icon={ChevronDown} name=\"chevron-down\" />\n </span>\n </span>\n {hint && <span class=\"kui-select__placeholder-hint\">{hint}</span>}\n </div>\n );\n }\n const selected = choices.find((choice) => choice.value === value);\n const icon = (choice: SelectChoice<Value>, selectedIcon = false) => (\n <span\n data-key={`${name}:${choice.value}:${selectedIcon ? 'selected' : 'option'}`}\n data-morph-skip\n slot=\"start\"\n class={`kui-select__icon${selectedIcon ? ' kui-select__icon--selected' : ''}`}\n style={choice.color ? `color:${choice.color}` : undefined}\n >\n {choice.icon ? (\n <LucideIcon\n icon={choice.icon}\n name={\n choice.iconName ?? choice.label.toLowerCase().replaceAll(' ', '-')\n }\n />\n ) : null}\n </span>\n );\n const option = (choice: SelectChoice<Value>) => (\n <>\n {choice.separatorBefore && <wa-divider></wa-divider>}\n <wa-option value={choice.value}>\n {choice.icon ? icon(choice) : null}\n {choice.label}\n </wa-option>\n </>\n );\n const groups = [\n ...new Set(\n choices\n .map((choice) => choice.group)\n .filter((group): group is string => Boolean(group)),\n ),\n ];\n const ungrouped = choices.filter((choice) => !choice.group);\n // Web Awesome names its shadow combobox from the label, not the host's\n // aria-label. Keep ariaLabel-only names available without visible chrome.\n return (\n <wa-select\n class={`kui-select${renderSelected ? ' kui-select--custom-selected' : ''}${fitMenu ? ' kui-select--fit-menu' : ''}${!label ? ' kui-select--label-hidden' : ''} ${className}`.trim()}\n data-component=\"select\"\n data-presentation={presentation}\n data-size={size}\n data-selected-presentation={selectedPresentation}\n data-focus-ring-owner={focusRingOwner}\n name={name}\n label={label || ariaLabel}\n aria-label={ariaLabel}\n value={value}\n placeholder={placeholderText}\n hint={hint}\n disabled={disabled}\n style={\n labelMaxWidth === undefined\n ? undefined\n : `--kui-select-label-max-width:${labelMaxWidth}px`\n }\n >\n {selected &&\n (renderSelected ? (\n <span\n data-key={`${name}:${value}:custom-selected`}\n slot=\"start\"\n class=\"kui-select__custom-selected\"\n >\n {renderSelected(selected)}\n </span>\n ) : selected.icon ? (\n icon(selected, true)\n ) : null)}\n {ungrouped.map(option)}\n {groups.map((group, index) => (\n <div\n class={`kui-select__group${index > 0 || ungrouped.length > 0 ? ' kui-select__group--separated' : ''}`}\n role=\"group\"\n aria-label={group}\n >\n <span class=\"kui-select__group-title\">{group}</span>\n {choices.filter((choice) => choice.group === group).map(option)}\n </div>\n ))}\n </wa-select>\n );\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { AppTab, AppTabProps } from './app-tab.js';
1
+ export { AppTab, AppTabPresentation, AppTabProps, AppTabSize } from './app-tab.js';
2
2
  export { DisclosureArrow, DisclosureArrowProps, DisclosureDirection } from './disclosure-arrow.js';
3
3
  export { EmptyState, EmptyStateProps } from './empty-state.js';
4
4
  export { FloatingToolbar, FloatingToolbarPosition, FloatingToolbarProps } from './floating-toolbar.js';
@@ -13,15 +13,15 @@ export { LucideIcon, LucideIconProps, LucideNode } from './lucide-icon.js';
13
13
  export { Pane, PaneContentElement, PaneElement, PaneProps, PaneSeparatorSide } from './pane.js';
14
14
  export { ResizableRegion, ResizableRegionAxis, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionEdge, ResizableRegionPresentation, ResizableRegionProps, ResizableRegionRestorePosition, ResizableRegionSeparator, clampRegionSize, resizeRegionFromPointer } from './resizable-region.js';
15
15
  export { SegmentedControl, SegmentedControlAppearance, SegmentedControlChoice, SegmentedControlLayout, SegmentedControlProps, SegmentedControlShape, SegmentedControlSize } from './segmented-control.js';
16
- export { Select, SelectChoice, SelectProps } from './select.js';
16
+ export { Select, SelectChoice, SelectFocusRingOwner, SelectPresentation, SelectProps, SelectSelectedPresentation, SelectSize } from './select.js';
17
17
  export { Skeleton, SkeletonProps } from './skeleton.js';
18
18
  export { StateBanner, StateBannerProps, StateBannerTone, StateBannerUrgency } from './state-banner.js';
19
19
  export { SunkenPanel, SunkenPanelProps, SunkenPanelShape } from './sunken-panel.js';
20
20
  export { DialogSurface, DialogSurfacePresentation, DialogSurfaceProps, DialogSurfaceSize, PopupSurface, PopupSurfaceInset, PopupSurfaceProps, SurfaceInset } from './surface-scaffold.js';
21
- export { TabActivation, TabBar, TabBarProps } from './tab-bar.js';
21
+ export { TabActivation, TabBar, TabBarAllocation, TabBarPresentation, TabBarProps, TabBarTrailingPlacement } from './tab-bar.js';
22
22
  export { TokenSearchEditorAttributes, TokenSearchField, TokenSearchFieldProps, TokenSearchFieldValue, TokenSearchToken, placeTokenSearchCaret, readTokenSearchField } from './token-search-field.js';
23
23
  export { Toolbar, ToolbarProps } from './toolbar.js';
24
- export { ToolbarControlGroup, ToolbarControlGroupAppearance, ToolbarControlGroupButtonAppearance, ToolbarControlGroupProps, ToolbarControlGroupShape, ToolbarControlGroupTone } from './toolbar-control-group.js';
24
+ export { ToolbarControlGroup, ToolbarControlGroupAppearance, ToolbarControlGroupButtonAppearance, ToolbarControlGroupContent, ToolbarControlGroupDensity, ToolbarControlGroupProps, ToolbarControlGroupSelectedChrome, ToolbarControlGroupSelectedTone, ToolbarControlGroupShape, ToolbarControlGroupSize, ToolbarControlGroupTone } from './toolbar-control-group.js';
25
25
  export { HeadingLevel, ToolbarText, ToolbarTextProps, ToolbarTextSize } from './toolbar-text.js';
26
26
  export { ValueTable, ValueTableProps, ValueTableRow, ValueTableRowProps } from './value-table.js';
27
27
  export { ResizeCommit, WireResizableRegionsOptions, wireResizableRegions } from './wire-resizable-regions.js';
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from '.
10
10
  export { ToolbarText } from './chunk-R7ZWUN64.js';
11
11
  export { ResizableRegion, clampRegionSize, resizeRegionFromPointer } from './chunk-HP2B2L26.js';
12
12
  export { SegmentedControl } from './chunk-IJBSZ4NX.js';
13
- export { Select } from './chunk-FRVS5RFM.js';
13
+ export { Select } from './chunk-2NMQW7FX.js';
14
14
  export { ListActionRow } from './chunk-VCE4MPVE.js';
15
15
  export { ListInsetControl } from './chunk-QO55FN2Y.js';
16
16
  export { ListInsetText } from './chunk-FEY65TBV.js';
package/dist/select.d.ts CHANGED
@@ -18,6 +18,10 @@ type SelectAccessibleName = {
18
18
  label?: never;
19
19
  ariaLabel: string;
20
20
  };
21
+ type SelectPresentation = 'form' | 'toolbar-borderless' | 'navigation';
22
+ type SelectSize = 'default' | 'compact';
23
+ type SelectSelectedPresentation = 'label' | 'icon-only';
24
+ type SelectFocusRingOwner = 'select' | 'group';
21
25
  interface SelectBaseProps<Value extends string = string> {
22
26
  name: string;
23
27
  value: NoInfer<Value>;
@@ -33,16 +37,16 @@ interface SelectBaseProps<Value extends string = string> {
33
37
  /** Render as an unanimated loading skeleton: the label above a static, empty control box. */
34
38
  placeholder?: boolean;
35
39
  /** Form (default), borderless toolbar, or intrinsic navigation chrome. */
36
- presentation?: 'form' | 'toolbar-borderless' | 'navigation';
37
- size?: 'default' | 'compact';
40
+ presentation?: SelectPresentation;
41
+ size?: SelectSize;
38
42
  /** Show only the selected choice icon while retaining the Select's accessible name. */
39
- selectedPresentation?: 'label' | 'icon-only';
43
+ selectedPresentation?: SelectSelectedPresentation;
40
44
  /** Let an enclosing ToolbarControlGroup paint the composed focus ring. */
41
- focusRingOwner?: 'select' | 'group';
45
+ focusRingOwner?: SelectFocusRingOwner;
42
46
  /** Maximum closed-control label width in CSS pixels before ellipsis. */
43
47
  labelMaxWidth?: number;
44
48
  }
45
49
  type SelectProps<Value extends string = string> = SelectBaseProps<Value> & SelectAccessibleName;
46
50
  declare function Select<Value extends string>({ name, value, label, ariaLabel, choices, className, placeholderText, hint, disabled, fitMenu, renderSelected, placeholder, presentation, size, selectedPresentation, focusRingOwner, labelMaxWidth, }: SelectProps<Value>): SafeHtml;
47
51
 
48
- export { Select, type SelectChoice, type SelectProps };
52
+ export { Select, type SelectChoice, type SelectFocusRingOwner, type SelectPresentation, type SelectProps, type SelectSelectedPresentation, type SelectSize };
package/dist/select.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Select } from './chunk-FRVS5RFM.js';
1
+ export { Select } from './chunk-2NMQW7FX.js';
2
2
 
3
3
 
4
4
 
@@ -127,6 +127,32 @@
127
127
  .kui-resizable-region[data-presentation="overlay"][data-collapsed="true"] {
128
128
  pointer-events: none;
129
129
  }
130
+ .kui-resizable-region[data-presentation="overlay"][data-axis="horizontal"][data-collapse-motion]:not(
131
+ [data-collapse-motion="none"]
132
+ )
133
+ > .kui-resizable-region__content {
134
+ width: min(
135
+ var(--kui-resizable-region-expanded-size),
136
+ var(--kui-resizable-region-overlay-max-width, 85vw)
137
+ );
138
+ min-width: min(
139
+ var(--kui-resizable-region-expanded-size),
140
+ var(--kui-resizable-region-overlay-max-width, 85vw)
141
+ );
142
+ }
143
+ .kui-resizable-region[data-presentation="overlay"][data-axis="vertical"][data-collapse-motion]:not(
144
+ [data-collapse-motion="none"]
145
+ )
146
+ > .kui-resizable-region__content {
147
+ height: min(
148
+ var(--kui-resizable-region-expanded-size),
149
+ var(--kui-resizable-region-overlay-max-height, 85vh)
150
+ );
151
+ min-height: min(
152
+ var(--kui-resizable-region-expanded-size),
153
+ var(--kui-resizable-region-overlay-max-height, 85vh)
154
+ );
155
+ }
130
156
  .kui-resizable-region[data-presentation="hidden"] {
131
157
  display: none;
132
158
  }
@@ -40,6 +40,11 @@ Use `hint` for persistent supporting text below the control; use
40
40
  `placeholderText` only for the empty value shown inside the closed control.
41
41
  Kerf passes hint text through Web Awesome's form-control contract, which renders
42
42
  the hint part and connects the shadow combobox to it with `aria-describedby`.
43
+ The accessible control is that shadow combobox, not the `wa-select` wrapper;
44
+ inspect or test the element returned by the `combobox` role. Both the `hint`
45
+ attribute used by Kerf and Web Awesome's explicit `hint` slot produce a computed
46
+ accessible description in Chromium, Firefox, and WebKit, so applications do not
47
+ need an `aria-description` mirror or a shadow-DOM patch.
43
48
  Loading placeholders keep the same visible hint while replacing the interactive
44
49
  control with inert chrome.
45
50
 
@@ -23,6 +23,9 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
23
23
  Reusable shell policies are typed props: `separator`, `collapseMotion`,
24
24
  `contentOverflow`, and `presentation`. A collapsed panel may also receive a
25
25
  `restoreControl`, which Kerf places at the safe-area-aware `restorePosition`.
26
+ Overlay presentation also clamps fixed-size animated content to the configured
27
+ responsive overlay maximum, so a remembered desktop size cannot escape a narrow
28
+ viewport.
26
29
  - **`CollapsiblePanelToggle({ side, collapsed, action, panelId?, label? })`** and
27
30
  **`collapsiblePanelToggleIcon(side, collapsed)`** — the standard toggle
28
31
  affordance and its icon convention, so every sidebar reads the same: `PanelLeft*`
@@ -117,6 +117,9 @@ an upstream component or recipe request.
117
117
  - `TabBar` changes tabpanels and supports overflow/reorder; `SegmentedControl` chooses among a few compact views; `Select` handles a longer value list.
118
118
  - `StateBanner` persists beside affected work; `EmptyState` replaces absent content; `wa-callout` is contextual ecosystem content; `wa-toast` and `wa-toast-item` are transient and must not carry the only copy of important state.
119
119
  - `ResizableRegion` is an interactive controlled pane. CSS grid is the right answer when columns do not need a user-operable separator.
120
+ - A `ResizableRegion` overlay automatically clamps both its track and fixed-size
121
+ animated content to the responsive overlay maximum. Set the policy and maximum
122
+ on the component instead of adding application descendant width/height fixes.
120
123
  - Configure application panels through the shared `separator`, `collapseMotion`,
121
124
  `contentOverflow`, `presentation`, `restoreControl`, and `restorePosition`
122
125
  props on `ResizableRegion`, `Workbench` panels, and `CollapsiblePanel`. These
@@ -11,18 +11,18 @@ public-signature artifact.
11
11
 
12
12
  ## Strengthened contracts
13
13
 
14
- | ID | Compile-time guarantee |
15
- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
- | `KUI-T001` | `ListHeader` is a passive heading, a fully named/icon-bearing trailing action, or a controlled disclosure with `action` + `expanded`. Props ignored by the selected mode are rejected. |
17
- | `KUI-T002` | `Select` has a visible `label` or an `ariaLabel`. |
18
- | `KUI-T003` | A literal `Select.value` belongs to its literal `choices`. |
19
- | `KUI-T004` | A literal `SegmentedControl.value` belongs to its literal `choices`. |
20
- | `KUI-T005` | `expanded`, `expandAction`, and `expandLabel` exist only on `TokenSearchField({ collapsible: true })`. |
21
- | `KUI-T006` | `TokenSearchEditorAttributes` accepts application `data-*` metadata but rejects component-owned identity, morph, count, and placeholder attributes. |
22
- | `KUI-T007` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
23
- | `KUI-T008` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
24
- | `KUI-T009` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
25
- | `KUI-T010` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all ToolbarControlGroup presentation axes. |
14
+ | ID | Compile-time guarantee |
15
+ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
+ | `KUI-T001` | `ListHeader` is a passive heading, a fully named/icon-bearing trailing action, or a controlled disclosure with `action` + `expanded`. Props ignored by the selected mode are rejected. |
17
+ | `KUI-T002` | `Select` has a visible `label` or an `ariaLabel`. |
18
+ | `KUI-T003` | A literal `Select.value` belongs to its literal `choices`. |
19
+ | `KUI-T004` | A literal `SegmentedControl.value` belongs to its literal `choices`. |
20
+ | `KUI-T005` | `expanded`, `expandAction`, and `expandLabel` exist only on `TokenSearchField({ collapsible: true })`. |
21
+ | `KUI-T006` | `TokenSearchEditorAttributes` accepts application `data-*` metadata but rejects component-owned identity, morph, count, and placeholder attributes. |
22
+ | `KUI-T007` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
23
+ | `KUI-T008` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
24
+ | `KUI-T009` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
25
+ | `KUI-T010` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all AppTab, TabBar, ToolbarControlGroup, and Select presentation axes; the convenience root barrel re-exports them. |
26
26
 
27
27
  Literal identity inference is intentionally additive for dynamic applications.
28
28
  When choices or ids arrive at runtime and the state signal is correctly typed as
package/docs/workbench.md CHANGED
@@ -55,7 +55,8 @@ an optional `label`. Common shell behavior is configured rather than restyled:
55
55
  - `contentOverflow: "clip" | "auto" | "visible"` lets a drawer temporarily
56
56
  expose an open popup without a descendant override;
57
57
  - `presentation: "inline" | "overlay" | "hidden"` supports compact overlays
58
- or a responsive replacement;
58
+ or a responsive replacement. Overlay panels clamp both their track and fixed-size
59
+ animated content to the configured viewport-relative maximum;
59
60
  - `restoreControl` places an application-owned restore affordance in a
60
61
  safe-area-aware viewport corner (`restorePosition` chooses the corner).
61
62
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.26",
3
+ "version": "5.0.0-beta.29",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/select.tsx"],"names":[],"mappings":"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","file":"chunk-FRVS5RFM.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\nimport { ChevronDown } from 'lucide';\n\nimport { LucideIcon, type LucideNode } from './lucide-icon.js';\nimport { Skeleton } from './skeleton.js';\n\nexport interface SelectChoice<Value extends string = string> {\n value: Value;\n label: string;\n icon?: LucideNode;\n iconName?: string;\n color?: string;\n group?: string;\n separatorBefore?: boolean;\n}\n\ntype SelectAccessibleName =\n { label: string; ariaLabel?: string } | { label?: never; ariaLabel: string };\n\ninterface SelectBaseProps<Value extends string = string> {\n name: string;\n value: NoInfer<Value>;\n choices: readonly SelectChoice<Value>[];\n className?: string;\n /** Empty-value hint text shown in the closed control (the native select placeholder). */\n placeholderText?: string;\n /** Supporting text shown below the control and associated with its combobox. */\n hint?: string;\n disabled?: boolean;\n fitMenu?: boolean;\n renderSelected?: (choice: SelectChoice<Value>) => SafeHtml;\n /** Render as an unanimated loading skeleton: the label above a static, empty control box. */\n placeholder?: boolean;\n /** Form (default), borderless toolbar, or intrinsic navigation chrome. */\n presentation?: 'form' | 'toolbar-borderless' | 'navigation';\n size?: 'default' | 'compact';\n /** Show only the selected choice icon while retaining the Select's accessible name. */\n selectedPresentation?: 'label' | 'icon-only';\n /** Let an enclosing ToolbarControlGroup paint the composed focus ring. */\n focusRingOwner?: 'select' | 'group';\n /** Maximum closed-control label width in CSS pixels before ellipsis. */\n labelMaxWidth?: number;\n}\n\nexport type SelectProps<Value extends string = string> =\n SelectBaseProps<Value> & SelectAccessibleName;\n\nexport function Select<Value extends string>({\n name,\n value,\n label,\n ariaLabel,\n choices,\n className = '',\n placeholderText,\n hint,\n disabled = false,\n fitMenu = false,\n renderSelected,\n placeholder = false,\n presentation = 'form',\n size = 'default',\n selectedPresentation = 'label',\n focusRingOwner = 'select',\n labelMaxWidth,\n}: SelectProps<Value>) {\n if (placeholder) {\n return (\n <div\n class={`kui-select kui-select--placeholder ${className}`.trim()}\n data-component=\"select\"\n data-placeholder=\"true\"\n data-presentation={presentation}\n data-size={size}\n data-selected-presentation={selectedPresentation}\n data-focus-ring-owner={focusRingOwner}\n aria-busy=\"true\"\n style={\n labelMaxWidth === undefined\n ? undefined\n : `--kui-select-label-max-width:${labelMaxWidth}px`\n }\n >\n {label && <span class=\"kui-select__placeholder-label\">{label}</span>}\n <span\n class=\"kui-select__placeholder-box\"\n aria-label={ariaLabel}\n role=\"img\"\n >\n <Skeleton width=\"10em\" />\n <span class=\"kui-select__placeholder-chevron\" aria-hidden=\"true\">\n <LucideIcon icon={ChevronDown} name=\"chevron-down\" />\n </span>\n </span>\n {hint && <span class=\"kui-select__placeholder-hint\">{hint}</span>}\n </div>\n );\n }\n const selected = choices.find((choice) => choice.value === value);\n const icon = (choice: SelectChoice<Value>, selectedIcon = false) => (\n <span\n data-key={`${name}:${choice.value}:${selectedIcon ? 'selected' : 'option'}`}\n data-morph-skip\n slot=\"start\"\n class={`kui-select__icon${selectedIcon ? ' kui-select__icon--selected' : ''}`}\n style={choice.color ? `color:${choice.color}` : undefined}\n >\n {choice.icon ? (\n <LucideIcon\n icon={choice.icon}\n name={\n choice.iconName ?? choice.label.toLowerCase().replaceAll(' ', '-')\n }\n />\n ) : null}\n </span>\n );\n const option = (choice: SelectChoice<Value>) => (\n <>\n {choice.separatorBefore && <wa-divider></wa-divider>}\n <wa-option value={choice.value}>\n {choice.icon ? icon(choice) : null}\n {choice.label}\n </wa-option>\n </>\n );\n const groups = [\n ...new Set(\n choices\n .map((choice) => choice.group)\n .filter((group): group is string => Boolean(group)),\n ),\n ];\n const ungrouped = choices.filter((choice) => !choice.group);\n // Web Awesome names its shadow combobox from the label, not the host's\n // aria-label. Keep ariaLabel-only names available without visible chrome.\n return (\n <wa-select\n class={`kui-select${renderSelected ? ' kui-select--custom-selected' : ''}${fitMenu ? ' kui-select--fit-menu' : ''}${!label ? ' kui-select--label-hidden' : ''} ${className}`.trim()}\n data-component=\"select\"\n data-presentation={presentation}\n data-size={size}\n data-selected-presentation={selectedPresentation}\n data-focus-ring-owner={focusRingOwner}\n name={name}\n label={label || ariaLabel}\n aria-label={ariaLabel}\n value={value}\n placeholder={placeholderText}\n hint={hint}\n disabled={disabled}\n style={\n labelMaxWidth === undefined\n ? undefined\n : `--kui-select-label-max-width:${labelMaxWidth}px`\n }\n >\n {selected &&\n (renderSelected ? (\n <span\n data-key={`${name}:${value}:custom-selected`}\n slot=\"start\"\n class=\"kui-select__custom-selected\"\n >\n {renderSelected(selected)}\n </span>\n ) : selected.icon ? (\n icon(selected, true)\n ) : null)}\n {ungrouped.map(option)}\n {groups.map((group, index) => (\n <div\n class={`kui-select__group${index > 0 || ungrouped.length > 0 ? ' kui-select__group--separated' : ''}`}\n role=\"group\"\n aria-label={group}\n >\n <span class=\"kui-select__group-title\">{group}</span>\n {choices.filter((choice) => choice.group === group).map(option)}\n </div>\n ))}\n </wa-select>\n );\n}\n"]}