kerfjs 5.0.0-beta.104 → 5.0.0-beta.105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -0
- package/ai/cursorrules +2 -2
- package/ai/manifest.json +9 -7
- package/ai/skill.md +5 -5
- package/dist/jsx-runtime.d.ts +5 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,57 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
8
8
|
|
|
9
9
|
### Added
|
|
10
10
|
|
|
11
|
+
- **`wirePaneChrome`.** `@kerfjs/ui/wire-pane-chrome` makes a Pane's open `overlay` compact chrome transient: Escape or a press outside it closes it through the app's `compactChromeOpen` signals, and focus returns to the control that opened it (`KF-EEGAT7`).
|
|
12
|
+
- **ChoiceChips icon picker.** `presentation="icons"` renders square 36px icon-only choices, each named by its label (hidden, and its hover title), and `maxHeight` scrolls a long grid, with native radio (or toggle, or listbox) semantics unchanged (`KF-K60RRM`).
|
|
13
|
+
- **`Pane` `compactChrome`.** A Pane declares what its header and footer do when its container presents compactly: `fixed` (default), `scroll` (inline with the content; a footer settles at the end and scrolls past long content), or `overlay` (over the content on the chrome material, shown while the app's `compactChromeOpen` says so). NavStack views, TabNavigator scenes, full-screen dialogs, and compact Workbenches apply it; roomy containers ignore it. `PaneConfig` forwards both props (`KF-Q8EMWE`).
|
|
14
|
+
- **Vertical `Slider`.** `orientation="vertical"` stands a Slider up with its minimum at the bottom, `length` tall (default 160px), drawn the same in Chromium, Firefox, and WebKit; the AnchoredSurface media volume popup is vertical again (`KF-SVDPSR`).
|
|
15
|
+
- **`FileDropZone` `dropScope`.** A selector for an enclosing element (an attachments panel) that also takes drops: `wireFilePickers` highlights the zone while files are dragged over any part of it and reports drops there for the zone with `via: 'drop'`, so an app no longer writes the zone's `data-dragging` itself (`KF-HNRWM9`).
|
|
16
|
+
- **`PopupMenu` `triggerContent`.** App content, such as a `Badge` showing a status, can be the whole trigger: Kerf owns the bare button around it (no chrome, a pill focus ring, the pointer cursor, `aria-haspopup`), `label` names it, the caret is off by default, and no help tag repeats the name. Submenus and checked choices work as on any PopupMenu (`KF-PHGQ6D`).
|
|
17
|
+
- **Corner count badges.** `Badge` takes `placement="corner"` to straddle the top-trailing corner of the control it sits in (an icon-only `Button` or a button in a `ToolbarControlGroup`, which positions itself for it). `Button` takes `badge` (a count, short text, or `true` for a dot), `badgeLabel` (added to the button's name; the count stays out of it otherwise), and `badgeTone` (default `danger`) (`KF-WT2EMZ`).
|
|
18
|
+
- **`Text` `size="medium"`.** A heading at the 16px body size keeps its heading weight and wraps, for an in-list group title with a long user-authored name (`KF-43XH56`).
|
|
19
|
+
- **`List` `contentWidth` and `contentAlign`.** A page column caps its content at a readable measure (`compact` 440px, `medium` 640px, `wide` 864px) plus its own insets and centers it (or keeps it at the start), composing with `inset="document"`, so a settings page needs no application `max-width` CSS (`KF-P3069N`).
|
|
20
|
+
- **`Select` `maxTriggerWidth` and `minTriggerWidth`.** Typed `CssLength` bounds on the closed trigger under any presentation (title and inline included). The value or `renderSelected` content ellipsizes inside the cap and the caret stays, so an app no longer wraps a Select in its own sized element (`KF-DQANHZ`).
|
|
21
|
+
- **`LucideIcon` `title`.** An icon takes hover text as an SVG `<title>` over its whole box (not just its strokes), so a labeled status icon carries its own explanation without an application wrapper (`KF-2V9XJQ`).
|
|
22
|
+
- **`Button` `title`.** A Button takes native hover text that says more than its name ("Delete the Selected Draft" on an icon-only Delete). An icon-only Button already shows its `ariaLabel` as a help tag; a `title` replaces that tag (`KF-8MYB8B`).
|
|
23
|
+
- **`WorkbenchDialog` in `@kerfjs/ui`, the modal workbench dialog type.** `@kerfjs/ui/workbench-dialog` renders a header-less modal around a `Workbench`. The work area's toolbar carries the dialog's title, actions, and close control; the side rails keep their own toolbars and run the dialog's full height. On compact devices the dialog fills the screen and its rails become overlays over the work area, shown by their toolbar toggles; with `wireWorkbench`, Escape closes an open rail before the dialog (`KF-Q9ERQ6`).
|
|
24
|
+
- `WorkbenchMainToolbar` gains `end`: groups after a hidden right rail's relocated toggle, so a dialog's close control stays outermost.
|
|
25
|
+
- **`ColorField` in `@kerfjs/ui`.** `@kerfjs/ui/color-field` puts a color in a form or inspector: a label above a trigger that shows the color as a swatch (over a checkerboard) and its hex value, with a hint or error, compact size, and a hidden input under `name`.
|
|
26
|
+
- `wireColorFields(root, { onInput, onChange, pickers })` (`@kerfjs/ui/wire-color-fields`) opens a `ColorPicker` in an `AnchoredSurface` below the trigger, with per-field presets and samples. Edits preview on the trigger at once; Escape or a press outside closes the picker and returns focus.
|
|
27
|
+
- `wa-color-picker` is now `Discouraged` (47 in all), and the profile defaults avoid it (`KF-PZBW7F`).
|
|
28
|
+
- **`ColorPicker` in `@kerfjs/ui`.** `@kerfjs/ui/color-picker` is a full inline picker: a saturation and brightness area, hue and opacity sliders, an RGB/HSL/HSB/Grayscale model menu with channel fields, a hex field (8 digits below full opacity), an opacity field, a screen sampler where the EyeDropper API exists, and optional preset and sample swatches with an "Add to Samples" action.
|
|
29
|
+
- `wireColorPickers(root, { onInput, onChange })` (`@kerfjs/ui/wire-color-pickers`) makes it interactive: pointer drags and arrow keys on the area, native range sliders, field commits, model switching, and swatches.
|
|
30
|
+
- Each change reports `#rrggbb` or `#rrggbbaa` through bubbling `kui-color-input`/`kui-color-change` events and the callbacks, and the picker adopts a new controlled value.
|
|
31
|
+
- Hue survives gray colors, and conversions round-trip without drift (`KF-HBE31H`).
|
|
32
|
+
- **`ColorSwatches` in `@kerfjs/ui`.** `@kerfjs/ui/color-swatches` chooses one color from a fixed palette. It is a native radio group of round swatches with no visible text: one Tab stop, arrow keys to move, and the chosen value submitted under `name`. Each swatch is named by its color label, also shown as its hover hint. The chosen swatch wears a ring in the text color, so the choice never depends on hue. A `'transparent'` swatch offers no color. It has `default` and `compact` sizes, a disabled state, and the shared block-content inset (`KF-E4GC0B`).
|
|
33
|
+
- **`TagField` in `@kerfjs/ui`.** `@kerfjs/ui/tag-field` collects short values as removable tags, each submitted as a hidden input under `name`. It is built on SearchField's token editor in its `form-field` presentation, with a label, a hint or `error`, a tag glyph, a clear button, `max`, and `required`/`disabled`.
|
|
34
|
+
- `wireTagFields(root, { onChange })` (`@kerfjs/ui/wire-tag-fields`) adds a tag on Enter or a delimiter (and several from pasted text), and adds the typed text on Tab or when focus leaves the editor.
|
|
35
|
+
- It enforces duplicates, `max`, and `normalize`, reporting each refusal to `onReject`.
|
|
36
|
+
- Removing: a chip's × or Backspace at the start removes a tag, a chip's label moves it back to edit, and the clear button empties the list.
|
|
37
|
+
- Moving: arrows move between the chips and the editor. A `wireSearchFields` on the same root leaves a TagField's keys to `wireTagFields`.
|
|
38
|
+
- `wa-tag-input` is now `Discouraged` (46 in all), and the profile defaults avoid it (`KF-PZ5J93`).
|
|
39
|
+
- **`Slider` in `@kerfjs/ui`.** `@kerfjs/ui/slider` is a native `<input type="range">` drawn as a track, a brand fill up to the value, and a round thumb, the same in Chromium, Firefox, and WebKit. It has a label row, an optional live readout (`showValue`, `unit`, also spoken as the value text), labeled `ticks`, a `hint`, a `compact` size, and a disabled state. It fills its width on the shared block-content inset. `wireSliders(root)` (`@kerfjs/ui/wire-sliders`) keeps the fill and readout in step with a drag before the app re-renders. `wa-slider` is now `Discouraged` (45 in all), and the profile defaults avoid it (`KF-0R9G4Y`).
|
|
40
|
+
- **`ProgressBar` and `ProgressRing` in `@kerfjs/ui`.**
|
|
41
|
+
- `@kerfjs/ui/progress-bar` is a native `<progress>`. It is determinate (`value` of `max`) or, without a `value`, an indeterminate sweep. A visible `label` names it through `aria-labelledby`, or `ariaLabel` does without one. `showValue` adds a readout, and `valueText` replaces the spoken percentage. It takes brand and status `tone`s and a `compact` 4px track.
|
|
42
|
+
- `@kerfjs/ui/progress-ring` is an SVG `role="progressbar"` in `small`, `medium`, and `large` sizes for a line of text, a row, or a toolbar. It is determinate (filling clockwise from the top) or a spinning arc.
|
|
43
|
+
- Both hold still under reduced motion and draw `Highlight` fills in forced colors.
|
|
44
|
+
- `wa-progress-bar` and `wa-progress-ring` are now `Discouraged` (44 in all), and the profile defaults avoid them (`KF-87B2KV`).
|
|
45
|
+
- **`Disclosure` in `@kerfjs/ui`.** `@kerfjs/ui/disclosure` renders a native `<details>` whose `<summary>` carries a `DisclosureArrow`, a title, and an optional quiet `detail`. It sits on the shared content-item geometry, with `plain`, `framed`, and `sunken` appearances, and Kerf block content lands on the title's text column. Disclosures that share a `name` form a native exclusive accordion. The open state is the platform's: `open` renders it open, a re-render never closes it, and the arrow follows the live state; `toggleAction` names it for a captured `toggle` listener. It neutralizes page-wide `<details>` styling such as Web Awesome's `native.css`. `wa-details`, `wa-accordion`, and `wa-accordion-item` are now `Discouraged` (42 in all), and the profile defaults avoid them (`KF-CXCQE9`).
|
|
46
|
+
- **Styled tooltips for `kerfjs/overlay`'s `tooltip()` in `@kerfjs/ui`.** Import `@kerfjs/ui/overlay-tooltip.css` once. A tooltip on any element then takes the help tag's look (loud neutral fill, on-loud 14px text, 3px radius), wraps at 40 characters, never takes the pointer, fades in on its own, and fades out through `exitClass: 'kui-tooltip-exit'` with `exitDuration: 100`. Reduced motion, the static-effects switch, and forced colors are handled. `wa-tooltip` is now `Discouraged` (39 in all), and the package profile defaults avoid it (`KF-VKDRWA`).
|
|
47
|
+
- **Styled toasts for `kerfjs/overlay`'s `toast()` in `@kerfjs/ui`.** Import `@kerfjs/ui/overlay-toast.css` once. Toasts then stack above the bottom edge, clear of the safe area, at most 480px wide, on the raised surface. They take `variant` tones, take the chrome of a `StateBanner` passed as their only content, rise in on their own, and leave through `exitClass: 'kui-toast-exit'` with `exitDuration: 200`. Reduced motion, the static-effects switch, and forced colors are handled. Put `data-placement="top"` on an app-owned region to stack from the top. `wa-toast` and `wa-toast-item` are now `Discouraged` (38 in all), and the package profile defaults avoid them, so `KUI-L301` reports them (`KF-FYTF2Z`).
|
|
48
|
+
- **`ListDetailDialog` in `@kerfjs/ui`, the modal list-detail dialog type.** `@kerfjs/ui/list-detail-dialog` renders a modal whose list and detail columns each run its full height, so the divider runs from top to bottom. The list column carries its own default-size title and controls (`list.title`, `list.toolbar`). The detail column carries the dialog's primary xl title, its `actions`, and the close control, and each column has a pinned `footer`. Pass `compact` from `deviceClass()` and it becomes a full-screen `NavStack` drill-down (`detailActive`, `backLabel`), keeping the close control on every view. It replaces wrapping a `SplitView` in a `DialogSurface` by hand, whose header spanned both columns. The List-detail dialog recipe and the catalog use it. `SplitViewCompactViewToolbars` now also takes a `footer` (`KF-P9VSX1`, `KF-ZZRDDY`, `KF-HZHG4X`).
|
|
49
|
+
- **Non-selectable rows and a single Tab stop for multi-select `List` and `Grid` in `@kerfjs/ui`.** A non-interactive `ContentItem` with `gridRow` renders `role="row"` around a `gridcell`, with no `aria-selected` and no Tab stop. It holds content between selectable rows, such as an activity group or a "messages skipped" divider, so apps no longer hand-write grid roles. `wireContentItems` now makes each multi-select grid one Tab stop through a roving `tabindex`: the last focused row, else the first selected, else the first enabled. The stop survives re-renders. Arrow keys skip non-selectable rows, whose controls stay reachable by Tab (`KF-RAEXQ7`).
|
|
50
|
+
- **Desktop multi-select for `ChoiceChips`, `List`, and `Grid` in `@kerfjs/ui`.** `ChoiceChips` takes `multiple?: boolean | 'toggle'`. With `multiple: true` the group becomes an ARIA multi-select listbox: a click selects one chip, Cmd (Apple platforms) or Ctrl (elsewhere) toggles one, and Shift extends a range. It is one Tab stop: arrows, Home, and End move the selection, Shift with them extends it, Cmd/Ctrl with them moves focus alone, Space toggles, and Cmd/Ctrl+A selects all. Hidden inputs submit each selected value. Wire it with `wireChoiceChips` (`@kerfjs/ui/wire-choice-chips`), which fires `change` on the group; `readChoiceChips` returns the set. The same model is public as `applySelection`, `selectionGesture`, and `isApplePlatform` (`@kerfjs/ui/selection`) for `List`/`Grid` `selectionMode="multiple"` cards, whose activations carry their modifier keys. Without an anchor, a Shift range starts at the first selected item. **Breaking:** the checkbox behavior that `multiple: true` used to select is now `multiple: 'toggle'` (`KF-346HEG`).
|
|
51
|
+
- **`Catalog` secondary groups can hide tagged entries behind a switch.** `CatalogSecondaryGroup` takes an optional `tagFilter: { tag, label, show }`. It adds a compact `Switch` at the top of the open group, and entries carrying `tag` (plus any section they would leave empty) stay hidden until `show` is true. The active entry is always listed. The app owns `show`, and `wireCatalog` reports the switch through `onToggleSecondaryFilter(show)` (action `catalog-toggle-secondary-filter`, configurable with `toggleSecondaryFilterAction`). The UX catalog uses it to hide `Discouraged` Web Awesome entries by default (`KF-8M9QTZ`).
|
|
52
|
+
- **More Web Awesome elements are `Discouraged` in `@kerfjs/ui`.** A review against what Kerf now provides tags six more elements a Kerf component replaces, and moves `wa-button-group` from conditional to avoid: `wa-popover` and `wa-popup` (use `AnchoredSurface`, or `positionAnchored()` from `kerfjs/overlay`), `wa-callout` (`StateBanner`), `wa-card` (`ContentItem` or `SunkenPanel`), `wa-drawer` (`DialogSurface`'s side or bottom sheet, or `CollapsiblePanel`), and `wa-page` (`Workbench`, `SplitView`, `NavStack`, or `TabNavigator`). 34 elements are now `Discouraged`, and the package profile defaults avoid each new one, so `KUI-L301` reports it. `wa-tooltip`, `wa-toast`, and `wa-toast-item` followed once `@kerfjs/ui/overlay-tooltip.css` and `@kerfjs/ui/overlay-toast.css` shipped. The UX catalog's own demos no longer render `wa-card` (`KF-AJFRTE`).
|
|
53
|
+
- **Web Awesome 3.14 elements in the `@kerfjs/ui` catalog.** The optional Web Awesome peer range is now `^3.14.0` (was `^3.12.0`), and the catalog, the `@kerfjs/ui/webawesome` JSX declarations, and the UX catalog's Web Awesome Integration section cover the three elements 3.14 adds: `wa-stepper` and `wa-step` (a multi-step process indicator) and `wa-tag-input` (a form field that submits a list of tags). No Kerf component replaces them, so they are supported integration elements and `KUI-L301`'s profile defaults are unchanged; `wa-tag-input`'s entry points search filters to `TokenSearchField` (`KF-38B7VP`).
|
|
54
|
+
- **Keyboard multi-selection through `wireContentItems`.** Enter and Space on an interactive `ContentItem` now activate it with a click that carries the key's Shift, Ctrl, and Cmd state (Space uses the state at press), and Ctrl- or Cmd-modified Enter and Space are no longer ignored. One delegated click handler that reads `shiftKey`, `ctrlKey`, and `metaKey` now serves range and toggle selection for keyboard and pointer alike. Alt-modified keys are still left to the platform (`KF-45RNDS`).
|
|
55
|
+
- **Design templates for `@kerfjs/ui`'s native form controls.** `docs/design/templates/` now has light and dark SVG templates for `Button`, `TextField`, `Checkbox`, `RadioGroup`, `Switch`, and `Select`, linked from each catalog detail. `Button` now resets the platform's native button appearance like the other Kerf controls; it renders pixel-identically in Chromium, Firefox, and WebKit, and its templates capture as vectors (`KF-97MFYM`).
|
|
56
|
+
- `kerf-ui-doctor`'s `KUI-D040` title-style check now reads Kerf's native form components: the `label` and `ariaLabel` of `TextField`, `Select`, and `RadioGroup`, `TextField`'s `clearLabel`, and the text of a `Button`. `Checkbox` and `Switch` labels and `RadioGroup` choice labels are option text, which stays sentence style and is not read, as before for `wa-checkbox`, `wa-switch`, and `wa-radio` (`KF-MPXMSX`).
|
|
57
|
+
- **`@kerfjs/ui` guidance treats Web Awesome as an optional integration.** Kerf components and native elements are now the only default answer. The catalog tags the 28 Web Awesome elements a Kerf component replaces `Discouraged` (newly `wa-button`, `wa-input`, `wa-textarea`, `wa-checkbox`, `wa-checkbox-group`, `wa-radio`, `wa-radio-group`, `wa-switch`, `wa-dialog`, `wa-tag`, `wa-badge`, `wa-spinner`, and `wa-skeleton`) and lists all 70 under a collapsed `Web Awesome Integration` sidebar section. The package profile defaults avoid each replaced element, so `KUI-L301` (`ui-preferences`, also run by `kerf-ui-doctor`) reports a raw tag and names its Kerf replacement. The selection guide, AI skill, `llms.txt`, design philosophy, and theme contract no longer send applications to `wa-*` when no Kerf component fits. A new migration guide (`docs/webawesome-migration.md`) maps every replaced element to its Kerf component and lists the steps to remove Web Awesome (`KF-F52B04`).
|
|
58
|
+
- **`@kerfjs/ui` no longer needs Web Awesome anywhere.** `@awesome.me/webawesome` stays an optional peer, and `@kerfjs/ui/webawesome.css` (with the type-only `@kerfjs/ui/webawesome`) is now the only entry that touches it. Every Kerf component stylesheet reads only `--kui-*` tokens (`TokenSearchField`, `Text`'s field label and list-header heading, and `Composer` no longer read `--wa-*` variables, three of them without a fallback). `foundation.css` keeps no `wa-*` selectors, and the two tokens whose standalone fallback differed from the Kerf theme now match it: `--kui-font-weight-semibold` falls back to 500 (was 650) and `--kui-font-sans` to `ui-sans-serif, system-ui, sans-serif`. A Kerf-only application renders exactly like the catalog; consumer-bundle tests and a browser parity spec enforce it (`KF-3558JM`).
|
|
59
|
+
- **`Checkbox`, `RadioGroup`, and `Switch` for `@kerfjs/ui`.** Kerf's own toggles instead of `wa-checkbox`, `wa-radio-group` / `wa-radio`, and `wa-switch`: native inputs inside their labels, drawn as a box, circle, or track that matches the old look in every engine and scheme, with `hint` and `error` text on the label column (the input's or group's `aria-description`; an error sets `aria-invalid`), `disabled`, `name`/`value`/`form`, a delegated `action`, and a default or compact size. `Checkbox` takes `checked`, `required`, and `indeterminate` (`wireCheckboxes(root)` from `@kerfjs/ui/wire-checkboxes` sets the native mixed state); `RadioGroup` is a fieldset named by `label` or `ariaLabel` over a `choices` array (per-choice `hint` and `disabled`), stacked or `orientation="horizontal"`, with `value` and `required`; `Switch` is a `role="switch"` checkbox for settings that apply immediately (`KF-5RCPT6`).
|
|
60
|
+
- **`TextField` for `@kerfjs/ui`.** A text field, Kerf's own instead of `wa-input` and `wa-textarea`: a native `<input>` (or, with `multiline`, a `<textarea>`) inside one labeled box, named by `label` or `ariaLabel`, with a `hint` and an `error` below it (together its `aria-description`; an error sets `aria-invalid` and draws the danger border), a leading `icon`, a `clearable` button, `rows` and an optional growing `maxRows`, a live `maxLength` count (`showCount`), `type`, `required` (with an asterisk), `disabled`, `readOnly`, and `autocomplete`, at the 44px control height or `size="compact"` (33px, with a 16px text floor on touch screens). `wireTextFields(root)` (`@kerfjs/ui/wire-text-fields`) makes the clear button empty the field and announce `input` and `change`, and keeps counts current. It matches the old `wa-input` look in every engine and scheme, and the catalog demos and recipes use it instead of `wa-input` and `wa-textarea` (`KF-1DHMP9`).
|
|
61
|
+
- **`Button` for `@kerfjs/ui`.** A standalone action button, Kerf's own instead of `wa-button`: a native `<button>` (or, with `href`, a link) in a `tone` (`neutral`, `brand`, `danger`) and an `emphasis` (`primary`, `secondary`, `plain`), at the 44px control height or `size="compact"` (33px), with an optional leading `icon`, `loading` (a spinner in place of the label, which still names it, and `aria-busy`), `disabled`, a form `type` (default `button`, which never submits) with `name`, `value`, and `form`, a delegated `action`, and an icon-only square form (no label, `ariaLabel` required). It matches the old `wa-button` look pixel for pixel in Chromium, Firefox, and WebKit, light and dark, follows the shared `--kui-layout-rounded-radius`, and keeps the control band in a `Toolbar` trailing zone and a `TabBar` action zone. The catalog's demos and recipes use it (and plain `<button>`s inside toolbar groups) instead of `wa-button`. Import `@kerfjs/ui/button` and `@kerfjs/ui/button.css` (`KF-9HV3B2`).
|
|
11
62
|
- **Action `Chip`.** `Chip` takes an `action` (with the existing `itemId`), and its whole body then renders as a native `<button type="button" data-action data-item-id>` for an application's delegated handler, such as a filter token in a search syntax help popover that inserts itself into the query. The button keeps Chip geometry and adds hover, press, `:focus-visible`, and `disabled` states; an optional `actionLabel` names it when the visible label alone is unclear. A compact, rounded action chip in a wrapping `Row` inside a compact `ValueTable` cell keeps the row height of the compact `Badge` it replaces, even with Web Awesome's native button styles loaded. `action` cannot be combined with `href` or `removeAction`, at the type level or at runtime, because nested interactive content is invalid. The Chip catalog shows a search filter table, and the new Chip design templates cover tags and action chips.
|
|
12
63
|
|
|
13
64
|
- **`@kerfjs/ui/overlay-sheet.css`.** An opt-in stylesheet for core `kerfjs/overlay` dialogs presented with `presentation: 'bottom-sheet'`, matching `DialogSurface`'s sheet:
|
|
@@ -32,8 +83,56 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
32
83
|
- **Scoped tints for `@kerfjs/ui` layout surfaces.** `Pane` (and `PaneConfig`), `NavStack`, `TabNavigator`, and `TabNavigatorTab` take `tint: { color, scheme }`: an app color, typed with `@kerfjs/ui/css-values`, and the `'light'` or `'dark'` scheme it belongs to. Kerf does no color detection. The region paints the tinted surface, and its surface, raised surface, text, quiet text, link and brand text, quiet fills, chrome material, and popup rows re-derive from the color through `color-mix()` and relative color syntax. Lightness is clamped so text keeps WCAG AA over any color: a seed sweep across hue and lightness holds every text token at 4.5:1 or better in Chromium, Firefox, and WebKit, with and without the Web Awesome theme. The scope sets its `color-scheme` and Web Awesome scheme class, so Web Awesome components inside re-derive too. Under `prefers-contrast: more`, or without relative color syntax, it keeps the plain palette in the declared scheme.
|
|
33
84
|
- `@kerfjs/ui` `DialogSurface` gains `presentation="bottom-sheet"`: a dialog attached to the bottom edge of the screen, with square bottom corners, the top corners on the dialog radius, and a panel that runs behind the home indicator and the virtual keyboard while its content stays above them (the larger of the bottom safe area, the keyboard overlap measured from `visualViewport`, and `env(keyboard-inset-height)`). `height`, `maxHeight`, and the new `minHeight` size its visible height. The new `resizable` prop adds a top grabber, a focusable "Resize sheet" separator you drag or move with the arrow, Page Up/Down, Home, and End keys between `minHeight` and the viewport cap. The sheet slides up when it opens and down when it is dismissed; `enterMotion` / `exitMotion` (`"slide"` or `"standard"`) choose per transition, and reduced motion keeps Web Awesome's own animation. The centered `modal` presentation remains the default. The grabber, keyboard clearance, and slide need `@kerfjs/ui/surface-scaffold/register`.
|
|
34
85
|
|
|
86
|
+
### Changed
|
|
87
|
+
|
|
88
|
+
- `@kerfjs/ui` marks two more Web Awesome elements `Discouraged`, for 36 in total; the profile defaults avoid both, so `KUI-L301` reports them. `wa-include` injects fetched markup outside kerf's `SafeHtml` escaping; fetch with `resource()` from `kerfjs/async` and render Kerf content instead. `wa-scroller` gives way to a `Pane`'s scroll edges or `ColumnTrack` (`KF-F5MPVE`).
|
|
89
|
+
- **Breaking: one `Button` replaces `IconButton` and `IconToggleButton` in `@kerfjs/ui`.** `Button` gains `shape` (`rounded` by default, or `pill`) and `pressed`, which makes any Button a toggle: `aria-pressed` reports the state, and a pressed look draws on top of its tone and emphasis (secondary and plain take the quiet tone fill with a doubled outline; primary darkens with an inset ring). An icon-only button is a `Button` with an `icon` and an `ariaLabel` and no label, and help tags now name it on hover and focus. `IconButton`, `IconToggleButton`, and their subpaths and stylesheets are removed with no aliases; migrate `IconButton({ icon, iconName, label })` to `Button({ icon: <LucideIcon …/>, ariaLabel })`, and `IconToggleButton` to that plus `pressed` (and `shape="pill"` for its former default shape). `kerf-ui-doctor` now checks an icon-only Button's `ariaLabel` capitalization (`KF-TQCJSS`).
|
|
90
|
+
- **Breaking: `Composer` is now `MessageComposer` in `@kerfjs/ui`, and its action row is a `Toolbar`.** The new name says what it is: a composer for messages, prompts, and replies. There are no compatibility aliases: `MessageComposer`, `MessageComposerProps`, `wireMessageComposers`, `@kerfjs/ui/message-composer` (and `.css`), `@kerfjs/ui/wire-message-composers`, and `kui-message-composer*`; the catalog id is `message-composer`. The row below the field is now a compact `Toolbar` footer named "<label> Actions", so every toolbar convention applies: control groups and responsive relocation. A new `leading` prop holds controls such as an attach button or a model `Select`, and the `actions` prop is now `trailing` (`KF-ANFPGA`).
|
|
91
|
+
- **Breaking: `AppTab` is now `TabBarItem` in `@kerfjs/ui`.** The item inside a `TabBar` is named after its container, with no compatibility alias: `TabBarItem`, `TabBarItemProps`, `TabBarItemPresentation`, `TabBarItemSize`, and `TabBarItemNameOverflow`; the subpath `@kerfjs/ui/tab-bar-item` (and `.css`); `kui-tab-bar-item*` classes, `data-component="tab-bar-item"`, and `--kui-tab-bar-item-*` tokens (`KF-HAXNZ8`).
|
|
92
|
+
- **Breaking: `TokenSearchField` is now `SearchField` in `@kerfjs/ui`.** Tokens are optional, and it is Kerf's only search control, so the component and everything named after it lose the `Token` prefix, with no compatibility aliases. Exports: `SearchField`, `wireSearchFields`, `readSearchField`, `placeSearchFieldCaret`, `createSearchFieldModel`, and `SearchField*` types (`SearchFieldToken`, `SearchFieldModel`, `SearchFieldState`, …). Subpaths: `@kerfjs/ui/search-field`, `/search-field-model`, `/wire-search-fields`, `/search-field.css`. Markup: `data-component="search-field"`, `kui-search-field*` classes, `data-search-field-*` attributes, and `--kui-search-field-*` tokens. The catalog id is `search-field` (`KF-TF4N13`).
|
|
93
|
+
- **Breaking (`@kerfjs/ui`, 5.0 beta): `PopupMenu` no longer uses Web Awesome's dropdown.** The menu is now Kerf's own: a native trigger `<button>` and a `role="menu"` panel that opens as a manual popover in the browser top layer. `@kerfjs/ui/popup-menu/register` wires every PopupMenu in the document: opening and placement (flip, shift, and a height cap at the viewport edges), keyboard navigation (arrows, Home/End, typeahead, Enter/Space, ArrowRight/Left for submenus), hover-opened submenus with a pointer safe triangle, outside-press and Escape dismissal, and focus return. Its props are unchanged and it looks the same; menus no longer depend on Web Awesome's prototype patches, and a clipping `ResizableRegion` or `Workbench` panel no longer needs to release its clipping for one. Migration for code that reached into the old markup (`KF-EMJJGV`):
|
|
94
|
+
- Query `.kui-popup-menu` (a `<span>`), `.kui-popup-menu__trigger`, `.kui-popup-menu__menu`, and `.kui-popup-menu__item` instead of `wa-dropdown`, its `[slot="trigger"]` `wa-button`, its shadow `menu` part, and `wa-dropdown-item`. The open state is the trigger's `aria-expanded`, not an `open` attribute; `PopupMenuElement` is now plain `HTMLElement`, so open and close a menu with `openPopupMenu`, `openPopupMenuAt`, and `closePopupMenu`.
|
|
95
|
+
- Delegated `data-action`s run as before. The `wa-select` choice event is now a bubbling, cancelable `kui-menu-select` on the root, with `detail.item`, `detail.value`, and `detail.checked`; `wa-show`, `wa-hide`, and `wa-after-hide` are gone.
|
|
96
|
+
- A checkbox item no longer toggles itself: `detail.checked` is the state it asks for, and the item shows it once the application renders it.
|
|
97
|
+
- Escape closes the current submenu first, then the menu.
|
|
98
|
+
- The register no longer registers `wa-dropdown`, `wa-dropdown-item`, `wa-button`, or `wa-divider`. Import those Web Awesome modules yourself where you render them raw.
|
|
99
|
+
- **Breaking (`@kerfjs/ui`, 5.0 beta): `Select` no longer uses Web Awesome's select.** It renders a `kui-select` root holding a native trigger `<button role="combobox">` and a `role="listbox"` that opens as a manual popover in the browser top layer. `@kerfjs/ui/select/register` defines `kui-select` as a form-associated element (it submits under `name` like a native select, `multiple` values included, and returns to its rendered choice on form reset) and wires every Select: placement below the trigger (flipping above when short, capped at the viewport edges), keyboard navigation with typeahead, choosing, the select-all and clear actions, and dismissal by Escape, Tab, or an outside press. Its props are unchanged and it looks the same, with two deliberate fixes: a `title` Select's caret is no longer clipped, and an `inline` Select's box is 20px tall rather than 23.2px. Migration for code that reached into the old markup (`KF-CF0FEN`):
|
|
100
|
+
- Query `kui-select.kui-select`, `.kui-select__trigger`, `.kui-select__popup`, `.kui-select__listbox`, and `.kui-select__option` (`data-value`, `aria-selected`, `aria-disabled`) instead of `wa-select`, its shadow `combobox` / `listbox` parts, and `wa-option`. The open state is the root's `open` attribute and the trigger's `aria-expanded`.
|
|
101
|
+
- `input` and `change` still bubble from the root, and the root's `value` is the chosen value (an array with `multiple`). `wa-show`, `wa-hide`, `wa-after-show`, and `wa-after-hide` are gone; the select-all and clear actions report a `change` only.
|
|
102
|
+
- The `kui-select--label-hidden` class is gone: an `ariaLabel`-only Select now names its trigger with `aria-label` and renders no label element.
|
|
103
|
+
- The register no longer registers `wa-select`, `wa-option`, or `wa-divider`. Import those Web Awesome modules yourself where you render them raw.
|
|
104
|
+
- **Breaking (`@kerfjs/ui`, 5.0 beta): `DialogSurface` is the dialog itself, a native `<dialog>`, instead of a wrapper around a `wa-dialog` you write.** It renders Kerf's header (title, header actions, and a close button), the body, and an optional footer from props, keeps every size, presentation, inset, height, and floating header or footer prop, and looks the same. Open it with `openDialog(dialog)` and close it with `closeDialog(dialog)`, both from `@kerfjs/ui/surface-scaffold`: it opens modally in the top layer with the page inert and focus on an `autofocus` element or the panel, scales and fades in and out, and returns focus to its opener. The close button, any element inside with `data-dialog-close`, Escape, and (with `lightDismiss`) a press on the backdrop dispatch a cancelable `kui-request-close` (`detail.source`: `close-button`, `escape`, or `backdrop`); cancel it to keep the dialog open, and the panel pulses. The native `close` event fires once it has closed. While open, it measures a floating header or footer, follows a bottom sheet's keyboard and grabber, and keeps that state across application re-renders. It renders the host `kerfjs/overlay` uses for popovers and tooltips opened inside it. The four Web Awesome dialog patches are gone, and `surface-scaffold/register` no longer registers `wa-dialog`. Migration (`KF-JR9YFX`):
|
|
105
|
+
|
|
106
|
+
| Before (`wa-dialog` inside `DialogSurface`) | Now (`DialogSurface` props) |
|
|
107
|
+
| ------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
108
|
+
| `<wa-dialog label="Edit">` inside `<DialogSurface>` | `<DialogSurface label="Edit">`, with the dialog's content as its children |
|
|
109
|
+
| `id` on the `wa-dialog` | `id` |
|
|
110
|
+
| `slot="label"` content, such as a `ToolbarText` | `heading` (keep `label`, or name it with `labelledBy`) |
|
|
111
|
+
| `slot="header-actions"` content | `headerActions` |
|
|
112
|
+
| `slot="footer"` buttons or `Composer` | `footer` |
|
|
113
|
+
| `without-header`, `light-dismiss` | `withoutHeader`, `lightDismiss` |
|
|
114
|
+
| `dialog.open = true` / `false`, or `open={…}` in the template | `openDialog(dialog)` / `closeDialog(dialog)` |
|
|
115
|
+
| `data-dialog="close"` on a button | `data-dialog-close` |
|
|
116
|
+
| `wa-request-close` (cancelable) | `kui-request-close` (cancelable), `detail.source` |
|
|
117
|
+
| `wa-show`, `wa-after-show`, `wa-hide`, `wa-after-hide` | the native `close` event (after closing); nothing fires on open |
|
|
118
|
+
| `::part(dialog \| header \| body \| footer)` | `.kui-dialog-surface` and its `__header`, `__body`, and `__footer` (configure through props) |
|
|
119
|
+
|
|
120
|
+
A raw `wa-dialog` outside `DialogSurface` keeps Web Awesome's own behavior and the theme in `@kerfjs/ui/webawesome.css`; import its module yourself where you render it.
|
|
121
|
+
|
|
122
|
+
- **Breaking (`@kerfjs/ui`, 5.0 beta): `IconButton` is an icon-only `Button`, not a `wa-button`.** It takes the same `tone`, `emphasis`, and `size` as `Button` instead of Web Awesome's `variant`, `appearance`, and `size` (`variant` → `tone`: `neutral`, `brand`, `danger`; `appearance` `outlined` → `emphasis="secondary"`, `plain` → `emphasis="plain"`; `size` `xs`–`xl` → `default` or `compact`), renders a native `button[data-icon-only]` named by `label`, and needs no Web Awesome registration. The `kui-icon-button` class is gone; select the icon-only button by `.kui-button[data-icon-only]` (`KF-9HV3B2`).
|
|
123
|
+
- A `Composer`'s Enter-to-send treats a send action with `aria-busy="true"` (a busy `Button`) as unavailable, as it already did a disabled or `loading` one (`KF-9HV3B2`).
|
|
124
|
+
- `@kerfjs/ui` help tags (the names icon-only `Select` and `PopupMenu` triggers and icon-only toolbar buttons show on hover and keyboard focus) are Kerf's own element instead of a Web Awesome `wa-tooltip`, and they look and behave the same. `select/register`, `popup-menu/register`, and `help-tags/register` no longer register `wa-tooltip`: import its module yourself where you render one raw. A theme that restyled `wa-tooltip.kui-help-tag` targets `.kui-help-tag` instead (`KF-9VNFSG`).
|
|
125
|
+
- `@kerfjs/ui` no longer patches any Web Awesome internals, so it supports every Web Awesome 3.x from 3.12 (the optional peer range, `^3.12.0`) rather than effectively one exact version. Its CI runs the ui unit and Chromium browser suites against the newest 3.x as well as the 3.12.0 floor, and both pass on 3.14.0 (`KF-F3FY5G`).
|
|
126
|
+
|
|
35
127
|
### Fixed
|
|
36
128
|
|
|
129
|
+
- **`Combobox` suggestions are no longer clipped inside popups.** The listbox is a top-layer popover placed below the field at its width (flipping above when short), so an `AnchoredSurface`, a dialog, or a scrolling `List` around the field no longer cuts it off. The `--kui-combobox-z-index` token is gone; the top layer needs none (`KF-C558Z9`).
|
|
130
|
+
- **`List` `vAlign="middle"` and `Row` `hAlign="center"` gather their children in the middle** with their `gap`, instead of spreading them with `space-around`. `space-around` is now its own explicit value (`data-*-align="around"`), and `center`/`middle` on the cross axis center wrapped lines (`KF-3ZJ9PF`).
|
|
131
|
+
- **A SearchField no longer shows its placeholder over typed text after an unrelated re-render.** Re-rendering the host for another reason, such as an error message beside the field, reset the field's placeholder state from the app's query while the editor still held typed text. `wireSearchFields` now re-derives it from the live editor (`KF-PZ5J93`).
|
|
132
|
+
- **`<details name>` typechecks in kerf JSX.** The intrinsic `details` element now accepts `name`, the native exclusive-accordion group, so `<details name="faq">` no longer fails to typecheck (`KF-KFH2VT`).
|
|
133
|
+
- **A `SplitView` column's only `Pane` now fills the column in `@kerfjs/ui`.** It used to take only its content height, so the Pane's footer sat right below its content instead of at the column's end (`KF-P9VSX1`).
|
|
134
|
+
- A busy `ToolbarControlGroup` whose control shows text (`content="text"` or `"mixed"`) now hides the whole control under its spinner, label included, while keeping its size. Before, only icons were hidden, so the spinner drew over the label ("Pric◌ Check") (`KF-HCN9BH`).
|
|
135
|
+
- `@kerfjs/ui/webawesome.css` draws a loading active `wa-step`'s spinner in the marker's on-accent color. Web Awesome 3.14 colors that spinner with the same accent that fills an active marker, so it was invisible. The fix goes through the step's public `spinner` part (`KF-AW993A`).
|
|
37
136
|
- A `@kerfjs/ui` `Toolbar` with a single zone now gives that zone its whole content box. A leading-only toolbar kept the empty trailing track and its 8px column gap, so leading content set to fill the row (a flex `Row` of controls) stopped 8px short of the inline-end inset; a trailing-only toolbar had the same gap on the leading side. A lone leading, center, or trailing zone now spans every column track. Covered in Chromium, Firefox, and WebKit.
|
|
38
137
|
- Typing in a model-managed `@kerfjs/ui` `TokenSearchField` no longer re-runs the host `mount()` render on every keystroke. The field read the model's per-keystroke `state` during render, so an app that renders it from one large mount re-rendered and morphed the whole app per key. It now subscribes only to the new `model.structure` signal, which changes when a token is committed, removed, or reordered, when the text becomes empty or non-empty, or when the editor revision changes; the live text stays owned by the editor and `wireTokenSearchFields`. `model.suggestions` now publishes only when the suggestion list's content changes, and a model action that changes state publishes its state, result, and suggestions as one batch. Hosts that read `model.state.value` in their own render still subscribe per keystroke by choice: read `model.state.peek()` there, or bind `model.result` (or a `computed`) as a fine-grained text or attribute hole. An app that coalesced the field's per-keystroke projection to work around this can remove it.
|
|
39
138
|
- A `kerfjs/overlay` `initialFocus` that targets a custom element that cannot take focus yet no longer aborts the open. Before, a Web Awesome `wa-button` whose `focus()` throws before it has rendered made `overlay()` (and `confirm()`, `prompt()`, `form()`, `choice()`) roll back and rethrow. Now focus holds on the overlay itself, then moves to the element once it is defined and rendered, unless the overlay has closed or the user has moved focus in the meantime. The same applies to `initialFocus: true` when the first tab stop is such an element. Covered in Chromium, Firefox, and WebKit.
|
package/ai/cursorrules
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- kerf-skill-version: 1.
|
|
1
|
+
<!-- kerf-skill-version: 1.24.0 -->
|
|
2
2
|
|
|
3
3
|
# kerf.cursorrules — rules for building apps with kerf
|
|
4
4
|
|
|
@@ -45,7 +45,7 @@ trailing native buttons, and keep its `label`, `icon`, and
|
|
|
45
45
|
|
|
46
46
|
Wire emitted `data-action` hooks at the mount root and retain disposers.
|
|
47
47
|
`wireResizableRegions()` and `wireTabBars()` are eventful helpers and return
|
|
48
|
-
disposers. Compose `
|
|
48
|
+
disposers. Compose `TabBarItem` inside controlled `TabBar`; `wireTabBars()` supplies
|
|
49
49
|
horizontal edge autoscroll while dragging. Apply reorder reports
|
|
50
50
|
with `reorderTabs()`, and keep order, selection, close policy, routing, panels,
|
|
51
51
|
and persistence in the host. Toolbars draw no divider by default; call
|
package/ai/manifest.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"kerfjsVersion": "5.0.0-beta.
|
|
2
|
+
"kerfjsVersion": "5.0.0-beta.105",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"name": "skill",
|
|
6
6
|
"source": "kerf.claude-skill.md",
|
|
7
7
|
"bundle": "ai/skill.md",
|
|
8
8
|
"dest": ".claude/skills/kerf-app/SKILL.md",
|
|
9
|
-
"version": "1.
|
|
10
|
-
"sha256": "
|
|
9
|
+
"version": "1.26.0",
|
|
10
|
+
"sha256": "64a86a36399d12e5803a050c116d32d8762608d91ec9222670592ff471bc64b8",
|
|
11
11
|
"history": {
|
|
12
12
|
"1.0.0": "bef982cb743fd4c73e666ee5cf774112e57c93ebb13b24bbacbf08577db0930a",
|
|
13
13
|
"1.1.0": "f2aadb21e33dd389028951ae1ecbd9f8ba68648b3c5beba43fb4dfa2ab29f195",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"1.23.0": "28b82b4d31b98814c8fbbe1cb0bcf716192deb494c020b9af41a30830e6a0007",
|
|
41
41
|
"1.23.1": "e21d7db1097ad95c11af9248ad17d514716bebc5646becf57d19a7598d6e382c",
|
|
42
42
|
"1.24.0": "f74616ec20120fa97ec2ff7e92971f5721ee8dcb0b5b7da2dd2604bb87002b69",
|
|
43
|
-
"1.25.0": "bc2622cb12b382118e44aa50d1afb058252e0caf85b7c0ced4433bc0ca76f7c1"
|
|
43
|
+
"1.25.0": "bc2622cb12b382118e44aa50d1afb058252e0caf85b7c0ced4433bc0ca76f7c1",
|
|
44
|
+
"1.26.0": "64a86a36399d12e5803a050c116d32d8762608d91ec9222670592ff471bc64b8"
|
|
44
45
|
}
|
|
45
46
|
},
|
|
46
47
|
{
|
|
@@ -48,8 +49,8 @@
|
|
|
48
49
|
"source": "kerf.cursorrules",
|
|
49
50
|
"bundle": "ai/cursorrules",
|
|
50
51
|
"dest": ".cursorrules",
|
|
51
|
-
"version": "1.
|
|
52
|
-
"sha256": "
|
|
52
|
+
"version": "1.24.0",
|
|
53
|
+
"sha256": "9578b5141b417b10560a426086c0f8dad3bd6a302f2856bea4808be7d02ef0d3",
|
|
53
54
|
"history": {
|
|
54
55
|
"1.0.0": "98f7faff2b7585ef9cc511add42ea5d9bf0cbae8307b066af090e9281136d2ab",
|
|
55
56
|
"1.1.0": "a2ec8c221dc694c98b81009cd2d99f9159a45fda94585de2f54471b227099eda",
|
|
@@ -80,7 +81,8 @@
|
|
|
80
81
|
"1.21.0": "a1b663b44650b1a04f89c60b26b002322fc6789650291477e14e13329c3ce25f",
|
|
81
82
|
"1.21.1": "9b3eb825a7bec05bb6f0138f77b45fadf896b83020178c34c5a2f531c38f4dee",
|
|
82
83
|
"1.22.0": "3515c663e908b2d6dc9a2a9cf42f2a5bf9a5b3a10c79d43e30cc8427e2ce209d",
|
|
83
|
-
"1.23.0": "dad6f677c85bf01760da6694afb7ead1439f0e1f0298ba8dac65de44ba031848"
|
|
84
|
+
"1.23.0": "dad6f677c85bf01760da6694afb7ead1439f0e1f0298ba8dac65de44ba031848",
|
|
85
|
+
"1.24.0": "9578b5141b417b10560a426086c0f8dad3bd6a302f2856bea4808be7d02ef0d3"
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
]
|
package/ai/skill.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kerf-app
|
|
3
3
|
description: Build UIs in the kerf reactive framework and its @kerfjs/ui component package (https://github.com/brianwestphal/kerf). Use this skill whenever the user is writing or modifying code that imports `kerfjs` or `@kerfjs/ui`, asks to add a feature to a kerf app, or asks "how do I do X in kerf?". Use it proactively the moment you spot a kerf import in the file you're editing.
|
|
4
|
-
kerf-skill-version: 1.
|
|
4
|
+
kerf-skill-version: 1.26.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Building apps with kerf
|
|
@@ -33,7 +33,7 @@ when the complete layer is intentional. Prefer a component before inventing a
|
|
|
33
33
|
parallel local primitive, but keep domain state, routing, commands, and tab/menu
|
|
34
34
|
policy in the app.
|
|
35
35
|
|
|
36
|
-
Use ListItem/ListActionRow/ListHeader/
|
|
36
|
+
Use ListItem/ListActionRow/ListHeader/TabBarItem `rootAttributes` only for application
|
|
37
37
|
`data-*` metadata. ListActionRow `trailingActionAttributes` and ListHeader
|
|
38
38
|
`triggerAttributes` additionally support native popover target/action and
|
|
39
39
|
`aria-controls`/`aria-haspopup`. Do not use these slots to override action,
|
|
@@ -42,14 +42,14 @@ semantics; one `role="menuitem"` does not make a complete menu widget.
|
|
|
42
42
|
`ListItem.trailing` is dormant. Use `ListActionRow` for sibling primary and
|
|
43
43
|
trailing native buttons, and keep its `label`, `icon`, and
|
|
44
44
|
`trailingActionIcon` SafeHtml slots free of controls.
|
|
45
|
-
|
|
46
|
-
attributes at runtime. Keep `
|
|
45
|
+
TabBarItem protects its component/action/identity/selection and transient drag/drop
|
|
46
|
+
attributes at runtime. Keep `TabBarItem.closeIcon` and
|
|
47
47
|
`ResizableRegion.handleIcon` decorative and free of controls; the existing
|
|
48
48
|
named controls and wiring retain interaction and disposal ownership.
|
|
49
49
|
|
|
50
50
|
Components emit stable `data-action` hooks; wire them at the mount root and
|
|
51
51
|
retain every disposer. `wireResizableRegions()` and `wireTabBars()` are the
|
|
52
|
-
explicit behavioral helpers and return disposers. Compose `
|
|
52
|
+
explicit behavioral helpers and return disposers. Compose `TabBarItem` inside a
|
|
53
53
|
controlled `TabBar`; `wireTabBars()` supplies horizontal edge autoscroll during
|
|
54
54
|
dragging. Apply reorder reports with `reorderTabs()`, and keep order,
|
|
55
55
|
selection, close policy, routing, panels, and persistence in the host.
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -655,6 +655,11 @@ interface HTMLTrackAttrs extends KerfBaseAttrs {
|
|
|
655
655
|
}
|
|
656
656
|
interface HTMLDetailsAttrs extends KerfBaseAttrs {
|
|
657
657
|
open?: AttrLike<boolean>;
|
|
658
|
+
/**
|
|
659
|
+
* Exclusive accordion group: opening one `<details>` closes the others
|
|
660
|
+
* that share this name.
|
|
661
|
+
*/
|
|
662
|
+
name?: AttrLike<string>;
|
|
658
663
|
}
|
|
659
664
|
interface HTMLDialogAttrs extends KerfBaseAttrs {
|
|
660
665
|
open?: AttrLike<boolean>;
|
package/package.json
CHANGED