@ethlete/components 1.0.0-next.32 → 1.0.0-next.33

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 CHANGED
@@ -1,11 +1,297 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0-next.33
4
+
5
+ ### Major Changes
6
+
7
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`df55f32`](https://github.com/ethlete-io/ethdk/commit/df55f3237f2fc7234165b83ed564df78060ea133) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: layouts are opt-in values you register, so an app bundles only the renderers it draws with.
8
+ Pass factories to `provideBracketConfig({ layouts })` or the `layouts` input on either host. The
9
+ `layout` input and `BracketConfig.swiss` are gone - mirrored is a layout, swiss options live on
10
+ `swissBracketLayout()` - and an unregistered mode throws `ET3413`.
11
+
12
+ ```diff
13
+ - provideBracketConfig({ swiss: { colors } });
14
+ - <et-bracket layout="mirrored" [source]="source()" />
15
+ + provideBracketConfig({ layouts: [mirroredSingleEliminationBracketLayout(), swissBracketLayout({ colors })] });
16
+ + <et-bracket [source]="source()" />
17
+ ```
18
+
19
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`beec05f`](https://github.com/ethlete-io/ethdk/commit/beec05f70be10fcded054d825320d93f96c6b414) Thanks [@github-actions](https://github.com/apps/github-actions)! - Breadcrumb: collapsing the trail is now opt-in. Import `BREADCRUMB_COLLAPSE_IMPORTS` and apply `etBreadcrumbCollapse` to the breadcrumb, the outlet, or any ancestor to keep the overflow control; without it the trail is clipped and the toggletip's overlay runtime stays out of your bundle.
20
+
21
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`beec05f`](https://github.com/ethlete-io/ethdk/commit/beec05f70be10fcded054d825320d93f96c6b414) Thanks [@github-actions](https://github.com/apps/github-actions)! - Grid: `GridDebugComponent` moved out of `GRID_IMPORTS` into `GRID_DEBUG_IMPORTS`, so the development-only overlay no longer ships in production bundles. Import that barrel where you use `<et-grid-debug />`.
22
+
23
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`caa8c92`](https://github.com/ethlete-io/ethdk/commit/caa8c9286c6e25c298995525e91159e9ad04cd0d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query error: labels default to English only — the German status tables are no longer bundled or auto-selected by locale. Keep the old behavior with `provideQueryErrorLabels(queryErrorLabelsForLocale)` (or `GERMAN_QUERY_ERROR_LABELS`); the `migrate-query-error-labels` generator finds affected sites.
24
+
25
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`6be90f2`](https://github.com/ethlete-io/ethdk/commit/6be90f28518a969607202ebc8d99365f3506bae5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the link editor popover is opt-in via `provideRichTextEditorLinkEditor()` — without
26
+ it the `link` tool falls back to `prompt()`. Run
27
+ `nx g @ethlete/components:migrate-rich-text-editor-link-editor` to find affected editors.
28
+
29
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`a0e5424`](https://github.com/ethlete-io/ethdk/commit/a0e5424be31a2031b566e4cdf150275ab7bd4f37) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the `'heading'` block-style menu is now an opt-in tool -
30
+ `provideRichTextEditorHeadingTool()`, like the align/table/image tools. It stays in the default toolbar,
31
+ so that call is all it takes; without it no block-style control renders (Markdown `#` autoformat is
32
+ unaffected). It was the only default tool needing the menu system, worth 8.5 kB gz to every editor.
33
+
34
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`2c0d3c9`](https://github.com/ethlete-io/ethdk/commit/2c0d3c9f78bfceed19dd49b01f934d1cfebc83c2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Scrollable: the buttons, dots, drag and snap are now opt-in directives on the `<et-scrollable>` itself, so a plain track no longer bundles them. Replace `renderButtons` / `buttonPosition` / `stickyButtons` with `[etScrollableButtons]` (`SCROLLABLE_NAVIGATION_IMPORTS`), `renderNavigation` with `etScrollableNavigation`, `snap` / `snapOrigin` / `cursorDragScroll` with `etScrollableSnap` / `etScrollableDrag` (`SCROLLABLE_DRAG_IMPORTS`), and `darkenNonIntersectingItems` with `etScrollableDarken` (`SCROLLABLE_DARKEN_IMPORTS`). `ScrollableMasksDirective` / `ScrollableButtonsDirective` / `ScrollableNavigationDirective` are renamed to `…Component`; the directive names now belong to the opt-ins.
35
+
36
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`beec05f`](https://github.com/ethlete-io/ethdk/commit/beec05f70be10fcded054d825320d93f96c6b414) Thanks [@github-actions](https://github.com/apps/github-actions)! - Stream: `STREAM_IMPORTS` now holds only the shared consent, loading, error and slot pieces. Add the barrel of each platform you embed (`STREAM_YOUTUBE_IMPORTS`, `STREAM_TWITCH_IMPORTS`, … `STREAM_SOOP_IMPORTS`) and `STREAM_PIP_IMPORTS` for picture-in-picture - or `STREAM_ALL_IMPORTS` to keep the old contents. A YouTube-only app saves ~5 kB gz.
37
+
38
+ ### Minor Changes
39
+
40
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`1f528bd`](https://github.com/ethlete-io/ethdk/commit/1f528bd629b9c4f1cc5160d87745ad927a02203d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Accordion: add `preventCloseLast` to the group - the header can no longer collapse the last open
41
+ panel, so paired with `autoCloseOthers` the group behaves like a radio set. `close()`, `closeAll()`
42
+ and `[(isOpen)]` still collapse it.
43
+
44
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`c796f12`](https://github.com/ethlete-io/ethdk/commit/c796f123982b7e93dc756b9926f8b5e6e1788a41) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: add `density="compact"` - narrower columns, and match cards that answer with a code and a
45
+ score, for a full bracket inside an article column. Layout inputs are now overrides on top of it, so
46
+ an unbound input resolves through the preset instead of a fixed default.
47
+
48
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`568e937`](https://github.com/ethlete-io/ethdk/commit/568e9379c7ba2d4176f29d7a7939d4c5a7e1bfa7) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: `mirroredDoubleEliminationBracketLayout()` draws double elimination as stacked winners and
49
+ losers blocks, each folded around its own centre on a shared middle column, with the deciding rounds
50
+ chained below. Also fixes hovering a card lighting the wrong participant's journey, and a mirrored
51
+ bracket drawing its way-back connectors backwards.
52
+
53
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`35d4f03`](https://github.com/ethlete-io/ethdk/commit/35d4f03e81d7f916e7057d8525372176fa463f27) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: journeys are now per participant. Hovering one side of a card lights that participant's path
54
+ alone and marks where they went out, and `[(focusedParticipantId)]` pins a path for touch and keyboard
55
+ - driven from a control of yours, cleared with `Escape`. Match cards mark each side with
56
+ `data-participant-id`.
57
+
58
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`a8dd388`](https://github.com/ethlete-io/ethdk/commit/a8dd388e8846cf6a19cac7645d8f9b24207401d3) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: add `<et-bracket-rounds-list>`, the same source drawn as a vertical round-by-round list
59
+ (sectioned for double elimination), plus `bracketNaturalWidth()` / `bracketFitsWidth()` to decide when
60
+ to swap to it on a narrow screen.
61
+
62
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`fba7ed8`](https://github.com/ethlete-io/ethdk/commit/fba7ed852d7f4bfb7791cce13f5062b8c4fa4c59) Thanks [@github-actions](https://github.com/apps/github-actions)! - Breadcrumb: add `etBreadcrumbSeo` (`BREADCRUMB_SEO_IMPORTS`) - opt-in `schema.org` **BreadcrumbList**
63
+ JSON-LD, which is what earns a site the breadcrumb line in a search result. Crumbs state their own
64
+ `name` and `url` through new inputs on `etBreadcrumbItemTemplate`; loading and unnamed crumbs are
65
+ skipped, and the last crumb needs no `url`.
66
+
67
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`06a6ba2`](https://github.com/ethlete-io/ethdk/commit/06a6ba2889124267c05f0b0432578aaa2c8794ca) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar: `comparisonStart` / `comparisonEnd` band a compared period under the selection - the
68
+ analytics "vs. the previous 30 days" pattern - and the date range input forwards them. It is
69
+ presentation only, so picking never writes to it. Cells expose `data-comparison-band`, and
70
+ comparisons band at the calendar's `precision`.
71
+
72
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`d97e71a`](https://github.com/ethlete-io/ethdk/commit/d97e71a9e0ee6f53cb71c2b05f8dae64fcdb92a5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar: the header is replaceable, and now moves with the grid it names.
73
+
74
+ - `ng-template etCalendarHeader` projected into `et-calendar` renders instead of the default header,
75
+ with the headless directive as its context; `et-calendar` also exposes it as `headless`.
76
+ - The label travels with the rows, the caret no longer swings with the label's width, grids crossfade
77
+ rather than cut, and the picker's bottom sheet keeps one height.
78
+ - Fixed: the calendar warned NG0956 twice per navigation in dev.
79
+
80
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`8ff5062`](https://github.com/ethlete-io/ethdk/commit/8ff506229e889dda5389404b187b517fe6158baa) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar: `monthsShown` renders several months side by side - the classic two-month range picker,
81
+ where a range spanning the turn of a month is one gesture. The span shares one keyboard scope, one
82
+ selection and a band that runs through the seam, and stepping moves by a single month. Headless:
83
+ `monthPages()`. The date inputs deliberately don't forward it.
84
+
85
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`8692c2c`](https://github.com/ethlete-io/ethdk/commit/8692c2c8d00577ec701e9fa50ac2487be8a54ef0) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar: `mode="multiple"` selects a set of unrelated dates into its own `multipleValue` model
86
+ (`Date[]`, kept ascending). Picking a date again removes it, nothing bands or previews, and the grid
87
+ is `aria-multiselectable`. It composes with `precision`. The date inputs have no equivalent - their
88
+ value is one wire string.
89
+
90
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`35c463c`](https://github.com/ethlete-io/ethdk/commit/35c463cc17c2a7ea1e0bfa791371c10cf92fbe18) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar and date inputs: `precision` (`'day' | 'month' | 'year'`) makes them month or year pickers -
91
+ picking in that grid writes the value (the start of the unit) instead of drilling further, and ranges
92
+ compare, band and complete at the same unit. On `et-date-input` / `et-date-range-input` it also
93
+ derives the text format, so `displayFormat` now defaults to `null`.
94
+
95
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`c41beec`](https://github.com/ethlete-io/ethdk/commit/c41beec18d6920eb154ffc84a1393fd0b18ea8b6) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar: `rangeSelectionStrategy` decides what a pick means in `range` mode, forwarded by the date
96
+ range input. A strategy is two pure functions of `(date, currentRange)` - `select`, and the optional
97
+ `preview` for what to band on hover. `createWeekRangeStrategy({ weekStartsOn })` snaps to whole weeks
98
+ and `createFixedLengthRangeStrategy({ days })` makes every pick a complete span.
99
+
100
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`d5012e1`](https://github.com/ethlete-io/ethdk/commit/d5012e10ce81514c62eb1c1b76784a30a6d6b6de) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `startAt` to the calendar: where an empty calendar opens and which day takes the
101
+ initial roving focus (e.g. next month for a booking form). A selection or an explicit
102
+ `activeMonth` still wins over it, and without any of the three the calendar opens on
103
+ today. `et-date-input`, `et-date-range-input` and `et-date-time-input` forward it to
104
+ their picker calendar.
105
+
106
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`d9b05fc`](https://github.com/ethlete-io/ethdk/commit/d9b05fc92ca568a4d57e0711a6a0bab6db3a0e0c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar: the header label is a button that zooms the day grid out to months and then years, and
107
+ picking one drills back in; `startView` decides where it opens, forwarded by the three date inputs. A
108
+ coarse pick only navigates, reported as `monthSelect` / `yearSelect`. `min`/`max`/`dateFilter` and the
109
+ keyboard model reach every view, and the new `dateClass` puts classes of your own on any cell.
110
+
111
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`cbd68e0`](https://github.com/ethlete-io/ethdk/commit/cbd68e0287667b9cfb9b3138d0508378fffea0b5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Calendar: `weekNumbers` renders a leading week-number column on the day grid, forwarded by the date,
112
+ date-range and date-time inputs. The numbering is localized rather than always ISO, so it names the
113
+ rows actually on screen. Each number is its row's `rowheader`, and `--et-calendar-week-number-size`
114
+ sizes the column.
115
+
116
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`62b03f9`](https://github.com/ethlete-io/ethdk/commit/62b03f937274d68139be12df3778ce7d316600ea) Thanks [@github-actions](https://github.com/apps/github-actions)! - Carousel & Scrollable: much smoother swiping on a phone - 85% less style recalculation and 88% less
117
+ paint with `transition="wipe"`, and no observer work during a scroll. Snapping is native CSS scroll
118
+ snap (`ScrollableDirective.suspendSnap()` holds it off while something writes an offset itself), and
119
+ the built-in transitions run as composited keyframes. New `transition="custom"` fills
120
+ `--et-carousel-slide-progress` without applying an effect, for CSS of your own; new
121
+ `--et-carousel-wipe-dim-color`; `signalElementChildren` / `signalElementScrollState` take a
122
+ `mutations` option to narrow their observers.
123
+
124
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`cb1c5b0`](https://github.com/ethlete-io/ethdk/commit/cb1c5b0ee5a4cf735b8846364fd06bed77b59018) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: the placeholder cards are now real - compact `et-match-card` cells, a hero final card with a
125
+ champion line, heading round headers (`roundHeaderLevel`) and a labelled continue cell. They need
126
+ `provideBracketConfig({ matchNormalizer })` to read your match data (`normalizeEthleteBracketMatch` ships
127
+ for Ethlete feeds), and `finalColumnWidth` / `finalMatchHeight` now default to `360` / `200` to fit them.
128
+
129
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`9057738`](https://github.com/ethlete-io/ethdk/commit/90577383b754af4789f034cee5199bf2b56f8203) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add the match domain behind `MATCH_CARD_IMPORTS`: `<et-match-card>` (one card, three container-query layouts -
130
+ dense row, featured card, wide row; `size` pins one; put it on an `<a>` to make the whole card the link),
131
+ `<et-match-participant>`, the headless `etMatchCard` directive with its score/meta/game-score parts,
132
+ `provideMatchLabels()`, and `normalizeEthleteMatch()` - cards take a `NormalizedMatch`, so any backend maps in
133
+ with a plain adapter.
134
+
135
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`0d30c38`](https://github.com/ethlete-io/ethdk/commit/0d30c385db868f70c92f2b0db670e99dd645177d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Match card: live scores now roll when they change - old value out, new value in, with a flash on the side
136
+ that scored - plus a `scoreChange` output carrying the side and delta for your own effects. Only while the
137
+ match is live, never on first render, instant under reduced motion; `animateScoreChanges` turns it off.
138
+
139
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`fd8ac2f`](https://github.com/ethlete-io/ethdk/commit/fd8ac2f546fd8ac8cab61b249dccf01089b4b18e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add the standings table behind `STANDINGS_IMPORTS`: `<et-standings>` draws a real `<table>` from
140
+ `NormalizedStandingRow`s (any backend maps in; `normalizeEthletePlacement` ships for Ethlete feeds), bands
141
+ position `zones` in your own color themes and draws their legend from the same config, drops columns rather
142
+ than scrolling on narrow widths, and can single out one row.
143
+
144
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`26a987f`](https://github.com/ethlete-io/ethdk/commit/26a987f9972d25156dfec4753170b06b79b74793) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form field: an `[etIcon]` projected into `[etInputPrefix]` / `[etInputSuffix]` is now sized by the
145
+ shell (`--et-form-field-affix-icon-size`, `16px`) - no size class needed, matching the other
146
+ in-field icons.
147
+
148
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`d97e71a`](https://github.com/ethlete-io/ethdk/commit/d97e71a9e0ee6f53cb71c2b05f8dae64fcdb92a5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Icon: add a `label` input. An icon stays `aria-hidden` by default - it usually repeats the text beside
149
+ it - but a lone status glyph is the content, and `label` turns the host into a named `role="img"` so
150
+ the meaning survives for a screen reader.
151
+
152
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`d97e71a`](https://github.com/ethlete-io/ethdk/commit/d97e71a9e0ee6f53cb71c2b05f8dae64fcdb92a5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Menu: add `loop` (default `true`, the current behaviour). Turn it off and the arrow keys stop at the
153
+ ends instead of wrapping, which reads better in a long menu. A menu with a search field is
154
+ unaffected - its ends hand focus back to the field either way.
155
+
156
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`f0082cd`](https://github.com/ethlete-io/ethdk/commit/f0082cd3a6e3ed20fc534b02d25e260f4e1d8600) Thanks [@github-actions](https://github.com/apps/github-actions)! - Notification upgrades:
157
+
158
+ - `manager.promise(work, { loading, success, error })` follows a promise, an observable or an `@ethlete/query` query in one toast.
159
+ - `id` in the config replaces a live notification instead of stacking a duplicate.
160
+ - Status icons (overridable per notification via `icon`), plus `secondaryAction` for an action pair.
161
+ - Swipe/flick a notification away; opt out with `swipeToDismiss: false`.
162
+
163
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`0e08bc2`](https://github.com/ethlete-io/ethdk/commit/0e08bc23450a58635dfae906d9fefc96f18a359b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Pagination: add `<et-page-size-select>` (`PAGE_SIZE_SELECT_IMPORTS`) - the "Items per page" control
164
+ that completes the Material-style controls row beside a compact paginator. A native `<select>`, so it
165
+ pulls in nothing; a separate component, because page size is the app's state rather than the
166
+ paginator's. Changing the size deliberately does not reset the page. Two new label keys, `pageSize`
167
+ and `pageSizeOption`.
168
+
169
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`38b3c2b`](https://github.com/ethlete-io/ethdk/commit/38b3c2b6c1f6f54efcac63f4f991b682dfd1485e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: undo/redo over the Markdown value, replacing the browser's native
170
+ `contenteditable` history (which could restore states the value never had). Ctrl/Cmd+Z, Ctrl+Y and
171
+ the platform's own undo all route into it, plus new `'undo'` / `'redo'` toolbar tools that lead the
172
+ default toolbar. Typing goes back word by word; a paste, autoformat or tool rewrite in one step.
173
+
174
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`1c7ad03`](https://github.com/ethlete-io/ethdk/commit/1c7ad0373cf8cf7845be1d3337bbafe71eec9fc0) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: `provideRichTextEditorImageTool({ upload })` embeds images as `![alt](url)` - pick,
175
+ paste or drop a file, uploaded by your handler (a promise, an observable, or a `createDropzoneUpload`
176
+ config for real progress), with a placeholder that never touches the value and a popover for alt text.
177
+ Tool definitions gained `paste`, `drop` and `click` content hooks; without the tool, pasted image
178
+ files are refused rather than becoming `blob:` URLs in the value.
179
+
180
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`48fbe62`](https://github.com/ethlete-io/ethdk/commit/48fbe62fefe815a59d1b41e6fbc7055c88537e58) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: pasted text that spells a token out - `#First name`, the trigger char plus an
181
+ item's label or id - comes back as a real chip, for HTML and plain-text clipboards alike (opt out with
182
+ `parsePastedTokens="false"`). A trigger with a static `items` list no longer needs `resolveItem` to
183
+ render chip labels.
184
+
185
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`7e444d6`](https://github.com/ethlete-io/ethdk/commit/7e444d6d11f65b00ae22b9d0f9d553ff3b45b733) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: block quote and fenced code block tools (`'blockquote'` / `'codeBlock'`, also
186
+ typed as `> ` / ` ``` `), both in the default toolbar. Quotes nest with Tab/Shift+Tab; a code block
187
+ holds literal text, so the marks that can't serialize inside one disable themselves. `htmlToMarkdown`
188
+ / `markdownToHtml` now round-trip nested quotes (`>>`).
189
+
190
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`b3673f3`](https://github.com/ethlete-io/ethdk/commit/b3673f32015277a57be0887e43775869dd72b3ca) Thanks [@github-actions](https://github.com/apps/github-actions)! - Selection lists: add `<et-checkbox-group-select-all>`, the prebuilt tri-state select-all row that had
191
+ to be hand-rolled until now - a real `role="checkbox"` with `aria-checked="mixed"`, taking its text
192
+ from the new shared `selectAll` form label. Also `orientation="horizontal"` on `et-checkbox-group` and
193
+ `et-radio-group`, flowing the options in a wrapping row.
194
+
195
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`84a8d00`](https://github.com/ethlete-io/ethdk/commit/84a8d005838660be71cac158769f659c670465e8) Thanks [@github-actions](https://github.com/apps/github-actions)! - Sliders: `orientation="vertical"` turns `et-slider` / `et-range-slider` (and the headless `etSlider` /
196
+ `etRangeSlider`) into a bottom→up slider, its length set by `--et-slider-vertical-size`. `marks`
197
+ renders ticks on the track - `true` for one per `step`, or an array of `{ value, label? }` stops - and
198
+ `snapToMarks` moves commits and keyboard steps mark to mark instead of along the `step` grid.
199
+
200
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`41c2683`](https://github.com/ethlete-io/ethdk/commit/41c268395cfa476024a3ef4680eacda0660cd9ba) Thanks [@github-actions](https://github.com/apps/github-actions)! - Table: add CSV export - `TABLE_CSV_EXPORT_IMPORTS` / `etTableCsvExport` for a button of your own, or
201
+ `injectTableCsvExport()` / `tableToCsv()` from TypeScript. It writes the visible columns and the
202
+ table's own rows by default (`exportValue` gives a column its text form), `rows` also takes a provider
203
+ function, `tableCsvRowsFromPages({ fetchPage })` walks a paginated endpoint, and `file` saves a CSV the
204
+ server built instead. A server-paginated table that would silently export a single page is a dev-mode
205
+ error (`ET3506`) unless you pass `partial: true`.
206
+
207
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`e5ffd4d`](https://github.com/ethlete-io/ethdk/commit/e5ffd4d031e956e12b0d32f9cdee9dc843832c32) Thanks [@github-actions](https://github.com/apps/github-actions)! - Table: add `etTableInlineEdit` (`TABLE_INLINE_EDIT_IMPORTS`) - inline cell editing. Mark a column
208
+ `editable` and give it an `etTableCellEdit` template, whose context is the draft as a signal-forms
209
+ field, so any of the library's controls is an editor with a plain `[formField]` binding. Double-click
210
+ or `Enter` starts, `Enter` saves, `Escape` restores, `Tab` saves and moves on; `cellCommit` reports
211
+ `{ row, column, previous, next }` and the mutation stays yours.
212
+
213
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`040bbb3`](https://github.com/ethlete-io/ethdk/commit/040bbb3559b2c1705b2358a5c7158f491dce4a67) Thanks [@github-actions](https://github.com/apps/github-actions)! - Table: add `etTableKeyboardNav` (`TABLE_KEYBOARD_NAV_IMPORTS`) - arrow-key navigation over the body's
214
+ cells following the ARIA grid pattern, with Home/End, Ctrl+Home/End and PageUp/PageDown. The body
215
+ becomes a single tab stop; `Enter` drills into a cell's own control and `Escape` comes back out.
216
+ Composes with virtual scrolling.
217
+
218
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`255bebc`](https://github.com/ethlete-io/ethdk/commit/255bebcad8a0db468093784c300a865d90c224e7) Thanks [@github-actions](https://github.com/apps/github-actions)! - Time picker: `etTimePicker` / `et-time-picker` take `min`, `max` and `timeFilter`, matching the
219
+ calendar's bounds, and `et-time-input` / `et-date-time-input` forward them as `minTime` / `maxTime` /
220
+ `timeFilter`. Availability is per column - an hour is disabled only when no minute inside it is
221
+ selectable - unselectable options stay in place and the keyboard steps over them, and picking a part
222
+ moves the finer ones to the first value that works, including the hour behind an AM/PM pick.
223
+
224
+ ### Patch Changes
225
+
226
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`6c9d38d`](https://github.com/ethlete-io/ethdk/commit/6c9d38d7e6b41586d7c9abb3296e5f45ccc3767c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay runtime: build anchored strategies with `anchoredOverlayPosition({ referenceElement, … })`
227
+ instead of a `{ kind: 'anchored', … }` literal - it is what pulls `@floating-ui/dom` in, so apps
228
+ that only center dialogs no longer bundle it (~7 kB gz). `autoResize`, `autoHide`,
229
+ `autoCloseIfReferenceHidden` and arrows additionally need `enableAnchoredOverlayPositionExtras()`.
230
+
231
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`d97e71a`](https://github.com/ethlete-io/ethdk/commit/d97e71a9e0ee6f53cb71c2b05f8dae64fcdb92a5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix `<et-carousel>` autoplaying by default: `autoplay` is the component's own input now and defaults
232
+ to `false`, which is what it always documented. Add `autoplay` to a carousel that should play. On the
233
+ headless directive, read the new `isEnabled()` for what is in effect.
234
+
235
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`833b579`](https://github.com/ethlete-io/ethdk/commit/833b579f42f413ae715e792d5aa40e14d3e95513) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et-match-participant` now takes an attribute form (`<a et-match-participant>` / `<button …>`), so a player or
236
+ team card can be the click target itself. On an interactive host it names itself after the participant - the
237
+ link would otherwise read "FC Berlin emblem FC Berlin" - takes the shared focus ring, and drops the button
238
+ chrome. `et-match-card` already worked this way.
239
+
240
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`8609171`](https://github.com/ethlete-io/ethdk/commit/8609171a498982cdde8b7ce2c600cf4d42031016) Thanks [@github-actions](https://github.com/apps/github-actions)! - Docs: add a Sport UI recipes guide - the today's-matches rail (built on `et-scrollable`, which is why
241
+ `et-match-list` was never shipped as a component) plus competition, team, player and nation cards, each with
242
+ a live story to copy from.
243
+
244
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`8f0e42a`](https://github.com/ethlete-io/ethdk/commit/8f0e42a8a436aba6a061968bfd6dc144344a896f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form field: the text-field shell, rich-text, textarea, hint and counter CSS now ships with the
245
+ control that uses it, so a field holding only a checkbox, switch or slider no longer pulls the
246
+ whole form-field stylesheet. No API change; chrome renders as before.
247
+
248
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`2c0d3c9`](https://github.com/ethlete-io/ethdk/commit/2c0d3c9f78bfceed19dd49b01f934d1cfebc83c2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Choice field's card variant, the carousel autoplay chrome and the cascader's bottom-sheet
249
+ presentation now inject their CSS only once that feature is actually used.
250
+
251
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`353777b`](https://github.com/ethlete-io/ethdk/commit/353777bb56e42ad1c02058a2ccf694f69c94b025) Thanks [@github-actions](https://github.com/apps/github-actions)! - Mark build-tooling peer dependencies (`vite`, `typescript`, `ts-morph`, `@nx/devkit`, `@analogjs/*`) and feature-scoped runtime peers (`date-fns` in components) as optional via `peerDependenciesMeta`. They are only needed when running the Nx generators or using the date/time components - consumers no longer have to install them just to use the libraries.
252
+
253
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`95c3d2f`](https://github.com/ethlete-io/ethdk/commit/95c3d2f096180119ed21937d5c41ed62a7b050e6) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: `--et-overlay-body-padding-block` now reserves real space at the end of a scrolling body. Its end value used to be swallowed by the scroll container, leaving the last child's border and focus ring clipped against the divider once scrolled to the bottom.
254
+
255
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`f59128f`](https://github.com/ethlete-io/ethdk/commit/f59128f23932f647f2653d2ee804cd474011915f) Thanks [@github-actions](https://github.com/apps/github-actions)! - `createOverlayUnsavedChangesGuard` stops vetoing closes once its tracker was abandoned (a logout), so the overlay closes instead of prompting over a page the user is being redirected away from. It also inherits the tracker's tab guard - the `beforeunload` lock is on by default, with the title marker / blink / favicon / badge extras available through the `tab` option.
256
+
257
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`2c0d3c9`](https://github.com/ethlete-io/ethdk/commit/2c0d3c9f78bfceed19dd49b01f934d1cfebc83c2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: the default enter/leave animation CSS now ships with the strategy that uses it
258
+ (`stylesComponent` on the breakpoint config), so an app only bundles the animations for the overlay
259
+ kinds it opens. Overlays that hand-roll a layout `containerClass` instead of using a built-in
260
+ strategy must now provide their own animation CSS.
261
+
262
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`8b13854`](https://github.com/ethlete-io/ethdk/commit/8b13854aa079196c84fc08da0aee685f728a441d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query client: multi-tab sync and response persistence are opt-in `features` instead of defaults - the
263
+ `multiTabSync` / `persistence` client options are gone and a client without the features ships neither
264
+ engine. Migrate with `nx g @ethlete/query:migrate-query-client-features`.
265
+
266
+ - `withMultiTabSync()` shares reads, polls a cache key in one tab for all of them and refreshes the
267
+ others after a mutation; per-query `multiTabSync: false` keeps a query tab-local.
268
+ - `withQueryPersistence()` keeps public reads in IndexedDB, so a reload renders the last known data
269
+ while it revalidates. Secure responses need an explicit opt-in and are removed on logout.
270
+ - `refreshQueriesInUse()` also refreshes GraphQL queries transported over POST; devtools gain Sync
271
+ and Disk columns.
272
+
273
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`8422cf0`](https://github.com/ethlete-io/ethdk/commit/8422cf09bcb4cdc07621d7a495004d8bf5e37d2c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: fix escaping a code block that sits flush against the start or end of the content,
274
+ where there is no line to move to. ArrowUp off the first line and ArrowDown off the last now create
275
+ the paragraph they would move to, and a second Enter on the empty last line leaves the block.
276
+
277
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`1c7ad03`](https://github.com/ethlete-io/ethdk/commit/1c7ad0373cf8cf7845be1d3337bbafe71eec9fc0) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the docked (touch) toolbar no longer leaves a gap between itself and the on-screen
278
+ keyboard, however much the browser over-reports the keyboard's height, and it re-checks while the
279
+ keyboard is up in case a viewport event never arrives. A page that opted into the VirtualKeyboard API
280
+ gets `env(keyboard-inset-height)` instead of the measurement.
281
+
282
+ - [#3041](https://github.com/ethlete-io/ethdk/pull/3041) [`42ec970`](https://github.com/ethlete-io/ethdk/commit/42ec970d6963bb5a3aa3af4e207ef2cac801c915) Thanks [@github-actions](https://github.com/apps/github-actions)! - DI: `createProvider` / `createRootProvider` / `createStaticProvider` / `createStaticRootProvider` /
283
+ `createLabels` are replaced by `defineProvider` & co., which return a definition you read with
284
+ `toProvideFn` / `toInjectFn` / `toToken`; `createQueryClient`, `createBearerAuthProvider` and
285
+ `createWebSocketClient` return that definition instead of a tuple. Every `provideX` / `injectX` /
286
+ token export keeps its name - run `nx g @ethlete/core:migrate-provider-shape` for your own call sites.
287
+ Cuts the `@ethlete/components` import floor from 89.9 to 2.4 kB gz.
288
+
3
289
  ## 1.0.0-next.32
4
290
 
5
291
  ### Major Changes
6
292
 
7
293
  - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`e052061`](https://github.com/ethlete-io/ethdk/commit/e0520614647b784f19ad55a4d7f6df47acec154e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Localization: one mechanism for every string the library renders. `createLabels` (core) backs a
8
- `provide<Domain>Labels` / `inject<Domain>Labels` pair per domain — 22 of them, all locale-reactive and
294
+ `provide<Domain>Labels` / `inject<Domain>Labels` pair per domain - 22 of them, all locale-reactive and
9
295
  signal-shaped. See the [localization guide](https://ethlete-sdk-docs-next.web.app/components/localization).
10
296
 
11
297
  - New tokens make the rich text editor, stream, grid, loader, chip, calendar, time picker, dropzone,
@@ -18,7 +304,7 @@
18
304
  ### Minor Changes
19
305
 
20
306
  - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`57494e0`](https://github.com/ethlete-io/ethdk/commit/57494e0834708ef1d397829074e20e35bc5d8acd) Thanks [@github-actions](https://github.com/apps/github-actions)! - Boolean and numeric inputs now coerce attribute values via `booleanAttribute` / `numberAttribute`,
21
- so static values need no binding — `<et-tab disabled>`, `<et-textarea rows="6">`. Inputs where
307
+ so static values need no binding - `<et-tab disabled>`, `<et-textarea rows="6">`. Inputs where
22
308
  `null`/`undefined` means "unset" (the slider's `min`/`max`, the overlay's `hasBackdrop`, …) are
23
309
  deliberately left untransformed.
24
310
 
@@ -29,28 +315,28 @@
29
315
  treatment now follows the frame and label instead of the whole field, so the hint/counter row no
30
316
  longer triggers it.
31
317
 
32
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`bc8aca7`](https://github.com/ethlete-io/ethdk/commit/bc8aca76900a47a3faed4ad2be2ce2ab7b70b27d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Filter overlay: new `provideFilterOverlay` / `injectFilterOverlay` — a filter panel that drafts the page's query
318
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`bc8aca7`](https://github.com/ethlete-io/ethdk/commit/bc8aca76900a47a3faed4ad2be2ce2ab7b70b27d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Filter overlay: new `provideFilterOverlay` / `injectFilterOverlay` - a filter panel that drafts the page's query
33
319
  form, reports how many results the draft would return on its submit button, and applies on submit or discards on
34
320
  dismiss. Replaces cdk's `FilterOverlayService`, rebuilt on signal forms and the current query client.
35
321
 
36
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`4fb18af`](https://github.com/ethlete-io/ethdk/commit/4fb18afb4159a1a301c66c98029e7af1d46a02ad) Thanks [@github-actions](https://github.com/apps/github-actions)! - Floating action: new `etFloatingAction` family — a trigger that pins itself to the viewport corner once its place
322
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`4fb18af`](https://github.com/ethlete-io/ethdk/commit/4fb18afb4159a1a301c66c98029e7af1d46a02ad) Thanks [@github-actions](https://github.com/apps/github-actions)! - Floating action: new `etFloatingAction` family - a trigger that pins itself to the viewport corner once its place
37
323
  in the page scrolls away, and stands down once the region it acts on is gone. Replaces cdk's `rich-filter`, which
38
324
  rendered no filter UI; the three states are published as one `data-state`.
39
325
 
40
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`c1db7e3`](https://github.com/ethlete-io/ethdk/commit/c1db7e3e8cf15d9dc192e51de699f0de8ee6fcbb) Thanks [@github-actions](https://github.com/apps/github-actions)! - Masonry: new `etMasonry` / `etMasonryItem` directives — column-balancing layout for variable-height cards.
326
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`c1db7e3`](https://github.com/ethlete-io/ethdk/commit/c1db7e3e8cf15d9dc192e51de699f0de8ee6fcbb) Thanks [@github-actions](https://github.com/apps/github-actions)! - Masonry: new `etMasonry` / `etMasonryItem` directives - column-balancing layout for variable-height cards.
41
327
  Items are measured continuously, so late-loading content reflows, and they keep their column when one grows.
42
328
  Gate infinite scroll on `isSettled()`.
43
329
 
44
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`3a6d9ad`](https://github.com/ethlete-io/ethdk/commit/3a6d9ad0130b6141add15c2660c976b61455e5a4) Thanks [@github-actions](https://github.com/apps/github-actions)! - Picture: new `et-picture` — responsive `<picture>` with art direction, format negotiation, `priority` hints,
330
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`3a6d9ad`](https://github.com/ethlete-io/ethdk/commit/3a6d9ad0130b6141add15c2660c976b61455e5a4) Thanks [@github-actions](https://github.com/apps/github-actions)! - Picture: new `et-picture` - responsive `<picture>` with art direction, format negotiation, `priority` hints,
45
331
  `aspectRatio` for reserving space, and `etPicturePlaceholder` / `etPictureError` slots. `providePictureConfig`
46
332
  prefixes relative srcsets per candidate.
47
333
 
48
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`38f6af1`](https://github.com/ethlete-io/ethdk/commit/38f6af115c7a5107b268c44597dc5b871503d9d9) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query error: new `<et-query-error>` and `[etQueryError]` — status title, message or violation list, and a retry
334
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`38f6af1`](https://github.com/ethlete-io/ethdk/commit/38f6af115c7a5107b268c44597dc5b871503d9d9) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query error: new `<et-query-error>` and `[etQueryError]` - status title, message or violation list, and a retry
49
335
  button when the retry policy says it's worth offering. Themed with the app's `type: 'error'` theme, localized via
50
336
  `injectLocale()`, with `etQueryErrorTitle` / `etQueryErrorActions` slots. `legacyQueryErrorSource` bridges a V2
51
337
  query.
52
338
 
53
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`d93dce3`](https://github.com/ethlete-io/ethdk/commit/d93dce3520e882a4cd4c6217d8a4cceedf74167c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form field: add `<et-counter />` — an `x / N` character counter in the support region, at the inline-end of the hint/error and persistent alongside them. It takes its limit from the bound field's schema `maxLength()`, or an explicit `[max]`, and counts array values (so it counts tags in an `et-tag-input`) via `lengthOf`.
339
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`d93dce3`](https://github.com/ethlete-io/ethdk/commit/d93dce3520e882a4cd4c6217d8a4cceedf74167c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form field: add `<et-counter />` - an `x / N` character counter in the support region, at the inline-end of the hint/error and persistent alongside them. It takes its limit from the bound field's schema `maxLength()`, or an explicit `[max]`, and counts array values (so it counts tags in an `et-tag-input`) via `lengthOf`.
54
340
 
55
341
  The field also shows a subtle busy spinner and `aria-busy` while an async validator is pending, plus `[busy]` on `et-form-field` to force it.
56
342
 
@@ -62,7 +348,7 @@
62
348
 
63
349
  - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`4624559`](https://github.com/ethlete-io/ethdk/commit/4624559c81ed9b6efffc539b8f1dd0db0556420c) Thanks [@github-actions](https://github.com/apps/github-actions)! - RTL and reduced-motion consistency pass:
64
350
 
65
- - Side sheets and the notification stack dock, animate and drag toward their logical inline edge under `dir="rtl"` — `dragToDismiss.direction` gains `'to-inline-start'` / `'to-inline-end'`.
351
+ - Side sheets and the notification stack dock, animate and drag toward their logical inline edge under `dir="rtl"` - `dragToDismiss.direction` gains `'to-inline-start'` / `'to-inline-end'`.
66
352
  - `createFlipAnimation` and the PiP animations now skip to their end state under `prefers-reduced-motion`; `ignoreReducedMotion` opts out, and `matchesReducedMotion()` is exported for helpers with no injection context.
67
353
  - The full-screen overlay animation throws `ET1209` when it has no origin element, instead of a bare `Error`.
68
354
 
@@ -76,19 +362,19 @@
76
362
 
77
363
  ### Patch Changes
78
364
 
79
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`894c821`](https://github.com/ethlete-io/ethdk/commit/894c821c80df962f4c3cce986fb68f88ae26955d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Breadcrumb: leaner chrome — a neutral `et-ellipsis` overflow button that stays neutral while open, menu-like
365
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`894c821`](https://github.com/ethlete-io/ethdk/commit/894c821c80df962f4c3cce986fb68f88ae26955d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Breadcrumb: leaner chrome - a neutral `et-ellipsis` overflow button that stays neutral while open, menu-like
80
366
  rows in its popover, and no flash of the full trail before it collapses on load. Adds
81
367
  `--et-breadcrumb-radius` and the `[data-toggletip-hug]` hook for content-width toggletips.
82
368
 
83
369
  Overlay: the anchored arrow now meets the pane's border line instead of leaving an unbordered wedge at its
84
- base — menus, tooltips and toggletips included.
370
+ base - menus, tooltips and toggletips included.
85
371
 
86
372
  - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`b06ed44`](https://github.com/ethlete-io/ethdk/commit/b06ed44db47a52d2a07a4d9a6b3bd3b04011decb) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: the anchored arrow no longer rides into a pane's rounded corner on aligned placements or when a pane
87
373
  shifts near a viewport edge. `arrowPadding` now measures the arrow's actual base, so it means "how close the
88
- arrow may get to the corners" — tooltip and toggletip default to `20` (was `8`), a bare anchored strategy to
374
+ arrow may get to the corners" - tooltip and toggletip default to `20` (was `8`), a bare anchored strategy to
89
375
  `12` (was `4`).
90
376
 
91
- - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`bd369da`](https://github.com/ethlete-io/ethdk/commit/bd369da0b898096411d65c352220a26b48ec7a67) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query devtools: arrays and objects in the value explorer now copy too — a container copies its
377
+ - [#3040](https://github.com/ethlete-io/ethdk/pull/3040) [`bd369da`](https://github.com/ethlete-io/ethdk/commit/bd369da0b898096411d65c352220a26b48ec7a67) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query devtools: arrays and objects in the value explorer now copy too - a container copies its
92
378
  subtree as JSON, a leaf copies the bare value. The toggle and close buttons print the platform's
93
379
  open/close shortcut, which now also fires on macOS. The inspect filter reads as a labelled banner
94
380
  instead of a bare pill.
@@ -97,9 +383,9 @@
97
383
  themselves (`overscroll-behavior: contain`), so reaching an end no longer scrolls the
98
384
  page behind them or triggers pull-to-refresh. Buttons, chips, menu items, select
99
385
  options, calendar cells and carousel dots drop the grey tap-highlight flash that
100
- duplicated their own `:active` state. Tooltips no longer open from touch input —
386
+ duplicated their own `:active` state. Tooltips no longer open from touch input -
101
387
  mobile browsers synthesize a hover around a tap, which popped a tooltip nobody asked
102
- for — and any open tooltip now closes on a press elsewhere.
388
+ for - and any open tooltip now closes on a press elsewhere.
103
389
 
104
390
  ## 1.0.0-next.31
105
391
 
@@ -116,7 +402,7 @@
116
402
  (`etBreadcrumbItemTemplate`, `loading` placeholders, `etBreadcrumbSeparator`) and measured overflow that
117
403
  moves the middle crumbs into a toggletip. In a routed app each view contributes only the crumbs it owns
118
404
  via `<ng-template etBreadcrumbSegment>`, and the single `<et-breadcrumb-outlet>` in the shell renders
119
- every registered segment as one trail — no view restates the path above it. Labels are localizable via
405
+ every registered segment as one trail - no view restates the path above it. Labels are localizable via
120
406
  `provideBreadcrumbLabels`.
121
407
 
122
408
  - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`b4eb950`](https://github.com/ethlete-io/ethdk/commit/b4eb9506b3c3beff52670115bf50b26ea45b0c22) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add the carousel: `<et-carousel>` with slides from data plus an `etCarouselSlide` template, seamless looping,
@@ -124,18 +410,18 @@
124
410
  `slideAlign`, opt-in `autoplay` with per-slide `autoplayTimeFor`, and the headless `etCarousel` /
125
411
  `etCarouselAutoplay` / `etCarouselItem` / control directives behind `CAROUSEL_IMPORTS`.
126
412
 
127
- - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`11ed986`](https://github.com/ethlete-io/ethdk/commit/11ed986c9391b6e4927312d166e8603bf1cefef8) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: new `<et-bracket>` tournament renderer — single/double-elimination and swiss layouts, SVG connectors, journey highlighting, and the `generateBracketDataForEthlete` data-source integration. Round-header, match, and continue cards render via barebones default components for now; supply custom cards through the `roundHeaderComponent` / `matchComponent` / `finalMatchComponent` / `continueComponent` inputs or `provideBracketConfig`.
413
+ - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`11ed986`](https://github.com/ethlete-io/ethdk/commit/11ed986c9391b6e4927312d166e8603bf1cefef8) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bracket: new `<et-bracket>` tournament renderer - single/double-elimination and swiss layouts, SVG connectors, journey highlighting, and the `generateBracketDataForEthlete` data-source integration. Round-header, match, and continue cards render via barebones default components for now; supply custom cards through the `roundHeaderComponent` / `matchComponent` / `finalMatchComponent` / `continueComponent` inputs or `provideBracketConfig`.
128
414
 
129
415
  This is the `@ethlete/cdk` `NewBracket` renderer moved here and renamed (`et-new-bracket` → `et-bracket`, `NewBracket*` → `Bracket*`), with colors now driven by the `--et-bracket-line-color` / `--et-bracket-swiss-group-border-color` tokens (default `--et-surface-border-solid`) and errors thrown as `RuntimeError` (ET34xx). The fifa.gg integration was not ported. See the guide's "Migrating from @ethlete/cdk" section.
130
416
 
131
- - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`875d22b`](https://github.com/ethlete-io/ethdk/commit/875d22bbde15669723cccf73c86983ad761c69b2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add a **Pagination** component (`et-pagination`, `PAGINATION_IMPORTS`) — responsive, localizable, with optional crawlable page links and SEO head tags. See the [pagination guide](https://ethlete-sdk-docs-next.web.app/components/pagination).
417
+ - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`875d22b`](https://github.com/ethlete-io/ethdk/commit/875d22bbde15669723cccf73c86983ad761c69b2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add a **Pagination** component (`et-pagination`, `PAGINATION_IMPORTS`) - responsive, localizable, with optional crawlable page links and SEO head tags. See the [pagination guide](https://ethlete-sdk-docs-next.web.app/components/pagination).
132
418
 
133
419
  - [`4b661b3`](https://github.com/ethlete-io/ethdk/commit/4b661b366682c18cf5371df03d3100d843146e5d) Thanks [@TomTomB](https://github.com/TomTomB)! - Scrollable: add `snapOrigin` for where a snapped child comes to rest (`'center'` suits a peeking layout), and
134
- stop snapping while a pointer is held on the track — it used to scroll out from under a paused drag.
420
+ stop snapping while a pointer is held on the track - it used to scroll out from under a paused drag.
135
421
 
136
- - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`36c7119`](https://github.com/ethlete-io/ethdk/commit/36c71192663e3b491de0e7210887852012308c4e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add a **Skeleton** component (`et-skeleton`, `SKELETON_IMPORTS`) for loading placeholders — see the [skeleton guide](https://ethlete-sdk-docs-next.web.app/components/skeleton).
422
+ - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`36c7119`](https://github.com/ethlete-io/ethdk/commit/36c71192663e3b491de0e7210887852012308c4e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add a **Skeleton** component (`et-skeleton`, `SKELETON_IMPORTS`) for loading placeholders - see the [skeleton guide](https://ethlete-sdk-docs-next.web.app/components/skeleton).
137
423
 
138
- - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`3c09f1d`](https://github.com/ethlete-io/ethdk/commit/3c09f1dd0c87ca366fe8f6c45fd138f4e8645402) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add a type-safe **Table** component (`et-table`, `TABLE_IMPORTS`) with a lean base and opt-in features for filtering, column menus, resizing, reordering, selection, virtual scrolling and state persistence — see the [table guide](https://ethlete-sdk-docs-next.web.app/components/table).
424
+ - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`3c09f1d`](https://github.com/ethlete-io/ethdk/commit/3c09f1dd0c87ca366fe8f6c45fd138f4e8645402) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add a type-safe **Table** component (`et-table`, `TABLE_IMPORTS`) with a lean base and opt-in features for filtering, column menus, resizing, reordering, selection, virtual scrolling and state persistence - see the [table guide](https://ethlete-sdk-docs-next.web.app/components/table).
139
425
 
140
426
  ### Patch Changes
141
427
 
@@ -157,7 +443,7 @@
157
443
  `box`/`filled` skins need, so the rule sits directly under the value instead of at the
158
444
  bottom of a taller frame. A `size="sm"` field previously left ~12px of dead space
159
445
  between its value and the underline (most visible on a compact control like a table
160
- footer's page-size select) — that is now the field's own
446
+ footer's page-size select) - that is now the field's own
161
447
  `--et-form-field-control-padding-block`, and the frame is content-height (27px instead of
162
448
  42px at `sm`).
163
449
 
@@ -165,12 +451,12 @@
165
451
  `--et-form-field-control-font-size` / `-line-height` / `-padding-block`, and a floating
166
452
  label still grows the frame past it. `box` and `filled` appearances are unchanged.
167
453
 
168
- Note this makes underline fields shorter on touch as well — reach for `box`/`filled` or
454
+ Note this makes underline fields shorter on touch as well - reach for `box`/`filled` or
169
455
  a larger `size` where a full-size tap target matters more than density.
170
456
 
171
457
  - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`dab7346`](https://github.com/ethlete-io/ethdk/commit/dab73460c22b47cf88106d3435cb95f78f756273) Thanks [@github-actions](https://github.com/apps/github-actions)! - Load more now dead-ends properly when the response can't state the end exactly: a page that comes back
172
- empty — or that repeats the previous page, which is what an API asked for a page past the end usually
173
- serves — is dropped instead of appended, and `hasMore` turns off regardless of `toHasMore`. Affects
458
+ empty - or that repeats the previous page, which is what an API asked for a page past the end usually
459
+ serves - is dropped instead of appended, and `hasMore` turns off regardless of `toHasMore`. Affects
174
460
  `selectOptionsFromQuery`, `selectOptionsFromV2Query` and both table rows adapters, so a load-more
175
461
  control no longer survives one page too long or duplicates the tail of the list.
176
462
 
@@ -178,24 +464,24 @@
178
464
 
179
465
  - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`5616552`](https://github.com/ethlete-io/ethdk/commit/56165523fa96b6aef6feffd4302d73f18f094155) Thanks [@github-actions](https://github.com/apps/github-actions)! - Menu: a checkbox/radio item's check, dot or custom icon is pinned to the item's trailing edge again.
180
466
  Its label's layout was declared in the plain menu item's stylesheet, which is only injected once that
181
- component renders — so in a menu built entirely from selection items (a filter menu, the rich text
467
+ component renders - so in a menu built entirely from selection items (a filter menu, the rich text
182
468
  editor's heading and alignment menus) the label didn't grow and the indicator sat against the text
183
469
  instead of the edge.
184
470
 
185
471
  - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`3151b7a`](https://github.com/ethlete-io/ethdk/commit/3151b7a253d14e38e22e20d67bf0191f141c144e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `ethlete/no-template-literal-before-inline-template`, and restructure the files it flagged.
186
472
 
187
- The Angular VS Code extension decides **client-side** whether the cursor sits inside an inline `template:` before it forwards completion, hover, go-to-definition or signature-help to the language server. That check (`isNotTypescriptOrSupportedDecoratorField`) walks the file with a bare `ts.createScanner()` loop, which cannot re-scan `}` as `TemplateMiddle`/`TemplateTail` — that needs the parser's `reScanTemplateToken()`. So the first template literal containing a `${…}` substitution desynchronises both the token stream and the brace counter, the scanner never recognises `template` `:` again, and every template request below it is dropped. The language server answers those requests correctly; the editor just never asks, so the template silently has no IntelliSense at all.
473
+ The Angular VS Code extension decides **client-side** whether the cursor sits inside an inline `template:` before it forwards completion, hover, go-to-definition or signature-help to the language server. That check (`isNotTypescriptOrSupportedDecoratorField`) walks the file with a bare `ts.createScanner()` loop, which cannot re-scan `}` as `TemplateMiddle`/`TemplateTail` - that needs the parser's `reScanTemplateToken()`. So the first template literal containing a `${…}` substitution desynchronises both the token stream and the brace counter, the scanner never recognises `template` `:` again, and every template request below it is dropped. The language server answers those requests correctly; the editor just never asks, so the template silently has no IntelliSense at all.
188
474
 
189
- The new rule reproduces that scanner verbatim, so it reports exactly the templates the extension would abandon — no heuristic. Twenty inline templates across `components`, `cdk` and the playground were affected, all of them behind a fixture or helper that happened to use an interpolated template literal. Story fixtures moved into sibling `*-storybook.data.ts` files; spec fixtures and in-class helpers that must stay above their component (because a later `@Component` references the class in `imports`) were rewritten without the interpolation.
475
+ The new rule reproduces that scanner verbatim, so it reports exactly the templates the extension would abandon - no heuristic. Twenty inline templates across `components`, `cdk` and the playground were affected, all of them behind a fixture or helper that happened to use an interpolated template literal. Story fixtures moved into sibling `*-storybook.data.ts` files; spec fixtures and in-class helpers that must stay above their component (because a later `@Component` references the class in `imports`) were rewritten without the interpolation.
190
476
 
191
- No public API changed — the `components` and `cdk` bumps are story/spec restructuring plus moving `signalVisibilityChangeClasses` below `RichFilterHostComponent` in the same module.
477
+ No public API changed - the `components` and `cdk` bumps are story/spec restructuring plus moving `signalVisibilityChangeClasses` below `RichFilterHostComponent` in the same module.
192
478
 
193
479
  - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`d666dcd`](https://github.com/ethlete-io/ethdk/commit/d666dcd73055e0044a2e635eef15c24849cf1751) Thanks [@github-actions](https://github.com/apps/github-actions)! - Log the logout-wide secure unbind in the query devtools event log. A logout drops every secure cache
194
480
  entry at once; without a row of its own, the requests disappearing from the cache view had no visible
195
481
  cause.
196
482
 
197
- - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`d85c58a`](https://github.com/ethlete-io/ethdk/commit/d85c58a84fc857847a03e4b736e27cd70fb5ee14) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the anchored link popover enters and leaves like a toggletip — a
198
- short fade plus a small nudge away from the selection it points at — instead of the
483
+ - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`d85c58a`](https://github.com/ethlete-io/ethdk/commit/d85c58a84fc857847a03e4b736e27cd70fb5ee14) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the anchored link popover enters and leaves like a toggletip - a
484
+ short fade plus a small nudge away from the selection it points at - instead of the
199
485
  anchored-dialog spring scale, which was far too much movement for a card sitting on
200
486
  top of the text being edited. The phone-sized top sheet is unchanged.
201
487
 
@@ -208,7 +494,7 @@
208
494
  - [#3037](https://github.com/ethlete-io/ethdk/pull/3037) [`88cf3af`](https://github.com/ethlete-io/ethdk/commit/88cf3af9e61f9cc5ea7e6f547430246327c88f96) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix `et-select` not forwarding the headless `mirrorPanelWidth` input, which made the
209
495
  documented escape hatch for compact triggers unreachable from the default component.
210
496
  With `[mirrorPanelWidth]="false"` the panel sizes to its own content (capped at
211
- `min(400px, 100vw - 24px)`) instead of the field's width — needed whenever the trigger
497
+ `min(400px, 100vw - 24px)`) instead of the field's width - needed whenever the trigger
212
498
  is narrower than an option row, e.g. a page-size select where the value plus the
213
499
  selected-check indicator no longer fit and the label was squeezed to a few pixels.
214
500
 
@@ -217,7 +503,7 @@
217
503
  ### Minor Changes
218
504
 
219
505
  - [#3036](https://github.com/ethlete-io/ethdk/pull/3036) [`aa4bdde`](https://github.com/ethlete-io/ethdk/commit/aa4bdde586615ed13735ed9c970831b91323ebad) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `<et-query-devtools>` (`QUERY_DEVTOOLS_IMPORTS`): a floating, dockable panel
220
- that inspects the signals-first `@ethlete/query` system — queries, stacks,
506
+ that inspects the signals-first `@ethlete/query` system - queries, stacks,
221
507
  sequences, GraphQL queries, bearer auth providers, web socket clients, the
222
508
  repository cache and a rolling event log. Enable instrumentation with
223
509
  `provideQueryDevtools()` from `@ethlete/query`.
@@ -242,14 +528,14 @@
242
528
 
243
529
  ### Patch Changes
244
530
 
245
- - [`90dad92`](https://github.com/ethlete-io/ethdk/commit/90dad922e8985b76e5f5ad67727333de6f5b9431) Thanks [@TomTomB](https://github.com/TomTomB)! - Overlays now elevate one level above the surface their **trigger** actually sits on, resolved from the trigger's nearest surface ancestor in the DOM rather than from dependency injection. The overlay container previously read its parent surface from the injector context (`SURFACE_PROVIDER`), which is wrong across the portal boundary: an overlay's trigger keeps the injector of where it was _declared_, and the anchored panel overlays (select, cascader, date-picker, menu) mount with no DI link to the trigger at all — so they always landed at elevation 1.
531
+ - [`90dad92`](https://github.com/ethlete-io/ethdk/commit/90dad922e8985b76e5f5ad67727333de6f5b9431) Thanks [@TomTomB](https://github.com/TomTomB)! - Overlays now elevate one level above the surface their **trigger** actually sits on, resolved from the trigger's nearest surface ancestor in the DOM rather than from dependency injection. The overlay container previously read its parent surface from the injector context (`SURFACE_PROVIDER`), which is wrong across the portal boundary: an overlay's trigger keeps the injector of where it was _declared_, and the anchored panel overlays (select, cascader, date-picker, menu) mount with no DI link to the trigger at all - so they always landed at elevation 1.
246
532
 
247
533
  This fixes two cases:
248
534
 
249
535
  - A `select` (or any anchored panel) opened from **inside a dialog** now mounts at elevation 2 instead of matching the dialog's elevation 1.
250
536
  - A picker anchored to a field inside an **elevated card** (e.g. a date input in a card at elevation 1) now elevates above the card instead of staying at elevation 1.
251
537
 
252
- Nested content (submenus elevating above their parent menu) and the plain non-nested case (an overlay opened from the base page mounts at elevation 1) are unchanged. Modal dialogs still always mount at elevation 1 — a backdrop resets the visual context.
538
+ Nested content (submenus elevating above their parent menu) and the plain non-nested case (an overlay opened from the base page mounts at elevation 1) are unchanged. Modal dialogs still always mount at elevation 1 - a backdrop resets the visual context.
253
539
 
254
540
  ## 1.0.0-next.28
255
541
 
@@ -257,7 +543,7 @@
257
543
 
258
544
  - [`b9fd6c2`](https://github.com/ethlete-io/ethdk/commit/b9fd6c2cc9dfac8211b33c4eed7039538257c2ef) Thanks [@TomTomB](https://github.com/TomTomB)! - Rename the module import arrays to SCREAMING_SNAKE_CASE for consistency with the rest of the library: `StreamImports` → `STREAM_IMPORTS`, `TabImports` → `TAB_IMPORTS`, `NavTabImports` → `NAV_TAB_IMPORTS` and `GridImports` → `GRID_IMPORTS`. Update your `imports` arrays accordingly.
259
545
 
260
- - [#3034](https://github.com/ethlete-io/ethdk/pull/3034) [`deccbdd`](https://github.com/ethlete-io/ethdk/commit/deccbdda82d0df9984cdcdac1ab3485d7e080759) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: give the boxed overlay kinds (`dialog`, `anchoredDialog`, the four sheets and the full-screen dialog) a default themed pane surface — `--et-surface-background-solid` background, a `0.1rem` `--et-surface-border-solid` border (all around for dialogs; every edge but the docked one for bottom/top sheets; only the exposed inner edge for side sheets, whose block edges sit flush against the viewport), and a radius on the exposed corners (`1.6rem` dialogs/sheets, `1.2rem` anchored dialog; full-screen stays square). Plain overlay content no longer needs to paint its own surface. Overridable per instance via the new `--et-overlay-surface-background`, `--et-overlay-surface-color`, `--et-overlay-surface-border-color`, `--et-overlay-surface-border-width` and `--et-overlay-radius` tokens. Anchored/centered panes (menu, tooltip, select, date-picker) are unaffected — they still paint their own surface.
546
+ - [#3034](https://github.com/ethlete-io/ethdk/pull/3034) [`deccbdd`](https://github.com/ethlete-io/ethdk/commit/deccbdda82d0df9984cdcdac1ab3485d7e080759) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: give the boxed overlay kinds (`dialog`, `anchoredDialog`, the four sheets and the full-screen dialog) a default themed pane surface - `--et-surface-background-solid` background, a `0.1rem` `--et-surface-border-solid` border (all around for dialogs; every edge but the docked one for bottom/top sheets; only the exposed inner edge for side sheets, whose block edges sit flush against the viewport), and a radius on the exposed corners (`1.6rem` dialogs/sheets, `1.2rem` anchored dialog; full-screen stays square). Plain overlay content no longer needs to paint its own surface. Overridable per instance via the new `--et-overlay-surface-background`, `--et-overlay-surface-color`, `--et-overlay-surface-border-color`, `--et-overlay-surface-border-width` and `--et-overlay-radius` tokens. Anchored/centered panes (menu, tooltip, select, date-picker) are unaffected - they still paint their own surface.
261
547
 
262
548
  ## 1.0.0-next.27
263
549
 
@@ -281,22 +567,22 @@
281
567
 
282
568
  ### Minor Changes
283
569
 
284
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`08ccfb4`](https://github.com/ethlete-io/ethdk/commit/08ccfb406db0269237ce3d026036c3400dff01d6) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `createV2DropzoneUpload` — a legacy `V2QueryClient` flavor of the dropzone `upload` config, mirroring `createDropzoneUpload`. Apps that haven't migrated to the new `@ethlete/query` API can now drive the dropzone from a legacy v2 creator (`client.post(...)` or a `createLegacyQueryCreator` interop wrapper); it slots into the same `upload` input and supports the full lifecycle (progress, success, failure, retry, existing values). Internally the per-file query lifecycle now runs behind an upload-handle abstraction, so both flavors share the directive/entry code and the failure display handles both `QueryErrorResponse` and `RequestError`.
570
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`08ccfb4`](https://github.com/ethlete-io/ethdk/commit/08ccfb406db0269237ce3d026036c3400dff01d6) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `createV2DropzoneUpload` - a legacy `V2QueryClient` flavor of the dropzone `upload` config, mirroring `createDropzoneUpload`. Apps that haven't migrated to the new `@ethlete/query` API can now drive the dropzone from a legacy v2 creator (`client.post(...)` or a `createLegacyQueryCreator` interop wrapper); it slots into the same `upload` input and supports the full lifecycle (progress, success, failure, retry, existing values). Internally the per-file query lifecycle now runs behind an upload-handle abstraction, so both flavors share the directive/entry code and the failure display handles both `QueryErrorResponse` and `RequestError`.
285
571
 
286
- - [`edb1f14`](https://github.com/ethlete-io/ethdk/commit/edb1f146792c308a0b80e8108d48934369d27b1d) Thanks [@TomTomB](https://github.com/TomTomB)! - Form field: the label is now truly optional — the label-mode layouts (`static`,
572
+ - [`edb1f14`](https://github.com/ethlete-io/ethdk/commit/edb1f146792c308a0b80e8108d48934369d27b1d) Thanks [@TomTomB](https://github.com/TomTomB)! - Form field: the label is now truly optional - the label-mode layouts (`static`,
287
573
  `floating-outside`) no longer reserve the label band when no `<et-label>` is
288
574
  projected.
289
575
  - Text-field controls (`et-input`, `et-number-input`, `et-password-input`,
290
576
  `et-color-input`, `et-textarea`) now accept `aria-label` / `aria-labelledby`,
291
577
  forwarded onto the native control; a consumer `aria-labelledby` overrides the
292
578
  projected `<et-label>`.
293
- - In dev mode a form field whose control has no accessible name — no `<et-label>`
294
- and no `aria-label`/`aria-labelledby` — now throws (`ET2201`). A placeholder is
579
+ - In dev mode a form field whose control has no accessible name - no `<et-label>`
580
+ and no `aria-label`/`aria-labelledby` - now throws (`ET2201`). A placeholder is
295
581
  not an accessible name.
296
582
 
297
583
  - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`0ecb9db`](https://github.com/ethlete-io/ethdk/commit/0ecb9dbe116b566beab61391b2cb92f3439c07f6) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: public API to insert a token chip at the caret from your own UI.
298
584
  - `RichTextEditorDirective.insertToken(type, id, opts?)` inserts a `{{type:id}}` token chip at the
299
- caret (or the end when unfocused), resolving its label via the trigger's `resolveItem` — the same
585
+ caret (or the end when unfocused), resolving its label via the trigger's `resolveItem` - the same
300
586
  result as picking it from the `#`/`@` popup. `insertTokenItem(type, item, opts?)` does the same
301
587
  when you already hold the resolved `{ id, label }`. The directive now also exports as
302
588
  `etRichTextEditor`.
@@ -305,40 +591,40 @@
305
591
 
306
592
  - [#3029](https://github.com/ethlete-io/ethdk/pull/3029) [`129c3c9`](https://github.com/ethlete-io/ethdk/commit/129c3c97c8b2e62fd4532ba03e7cf9bf6aaee764) Thanks [@EliasPapavlassopoulos](https://github.com/EliasPapavlassopoulos)! - Add a two-way `mixed` bulk-edit state (plus `mixedLabel` where the control has a text display slot) across the form controls: select (single, multi, searchable, headless, virtualized), cascader, input, number-input, password-input, textarea, color-input, date-input, time-input, date-time-input, date-range-input, duration-input, tag-input, phone-input, slider, range-slider, rating, and the selection-list groups (radio, checkbox-group, segmented). While `mixed` is set the raw form value stays untouched and masked; the first user commit replaces it and resolves the state. All implementations follow one executable contract (shared conformance suite); checkbox keeps expressing the concept via its platform-named `indeterminate`, and switch deliberately stays two-state (ARIA forbids a mixed switch).
307
593
 
308
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`b5c0207`](https://github.com/ethlete-io/ethdk/commit/b5c0207db2af40b15f8575e3f6c721d07cf81b2f) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et-select` (and the headless `[etSelect]`) gains the `[etSelectOptions]` directive: bind the bundle returned by `selectOptionsFromQuery` or `selectOptionsFromV2Query` with a single attribute and it wires the async plumbing for you — forwarding `loading`, `error` and `hasMoreItems`, forcing `filterMode` to `external`, and driving the bundle's `setQuery`/`loadMore` from the select's `(queryChange)`/`(loadMore)` outputs. You only render the options. Both factories return the same shape, so one directive serves the current query client and the legacy `V2QueryClient` alike. The manual per-input wiring stays fully supported.
594
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`b5c0207`](https://github.com/ethlete-io/ethdk/commit/b5c0207db2af40b15f8575e3f6c721d07cf81b2f) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et-select` (and the headless `[etSelect]`) gains the `[etSelectOptions]` directive: bind the bundle returned by `selectOptionsFromQuery` or `selectOptionsFromV2Query` with a single attribute and it wires the async plumbing for you - forwarding `loading`, `error` and `hasMoreItems`, forcing `filterMode` to `external`, and driving the bundle's `setQuery`/`loadMore` from the select's `(queryChange)`/`(loadMore)` outputs. You only render the options. Both factories return the same shape, so one directive serves the current query client and the legacy `V2QueryClient` alike. The manual per-input wiring stays fully supported.
309
595
 
310
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`5fc9aa4`](https://github.com/ethlete-io/ethdk/commit/5fc9aa4316390c2db908c6dcd3c2118945a11089) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et-select` (and the headless `[etSelect]`) gains an `pickOption` output and a `pickOnly` input. `pickOption` emits the picked value whenever a single-select option is committed — a "the user actively picked this" signal distinct from `valueChange`. With `pickOnly`, committing an option emits `pickOption` without ever writing `value`, so the select stays empty: a fire-and-forget "add" picker that feeds an external list without the set-then-clear dance (and its race with the `[(value)]` write-back). `pickOnly` has no effect in multi-select.
596
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`5fc9aa4`](https://github.com/ethlete-io/ethdk/commit/5fc9aa4316390c2db908c6dcd3c2118945a11089) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et-select` (and the headless `[etSelect]`) gains an `pickOption` output and a `pickOnly` input. `pickOption` emits the picked value whenever a single-select option is committed - a "the user actively picked this" signal distinct from `valueChange`. With `pickOnly`, committing an option emits `pickOption` without ever writing `value`, so the select stays empty: a fire-and-forget "add" picker that feeds an external list without the set-then-clear dance (and its race with the `[(value)]` write-back). `pickOnly` has no effect in multi-select.
311
597
 
312
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`6605423`](https://github.com/ethlete-io/ethdk/commit/6605423235364f06c07e827205de2c3a351a538f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Switch now supports an `indeterminate` state (two-way `[(indeterminate)]`), mirroring checkbox — the first toggle resolves it to on. Since `role="switch"` cannot carry `aria-checked="mixed"`, it's presentational only (thumb parks mid-track behind `data-indeterminate`; `aria-checked` stays boolean). The mixed/indeterminate state on the graphical controls (rating, slider, range-slider, checkbox-group, radio-group, switch) now uses a consistent dashed "provisional" treatment so it reads as "values differ" rather than empty.
598
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`6605423`](https://github.com/ethlete-io/ethdk/commit/6605423235364f06c07e827205de2c3a351a538f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Switch now supports an `indeterminate` state (two-way `[(indeterminate)]`), mirroring checkbox - the first toggle resolves it to on. Since `role="switch"` cannot carry `aria-checked="mixed"`, it's presentational only (thumb parks mid-track behind `data-indeterminate`; `aria-checked` stays boolean). The mixed/indeterminate state on the graphical controls (rating, slider, range-slider, checkbox-group, radio-group, switch) now uses a consistent dashed "provisional" treatment so it reads as "values differ" rather than empty.
313
599
 
314
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`d738771`](https://github.com/ethlete-io/ethdk/commit/d738771a05b4505616defab52359870892bae171) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `createOverlayUnsavedChangesGuard` — the overlay flavor of the `unsavedChanges` family. Called from an overlay content component's injection context, it injects the current `OVERLAY_REF` and vetoes a dismissal (outside pointer, escape, drag, or a programmatic `close()`) while the watched form has unsaved changes, runs the `confirm`, and only then re-issues the close. Per-source opt-out via `dismissSources`, honors `disableClose`, and auto-cleans up on injector destroy.
600
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`d738771`](https://github.com/ethlete-io/ethdk/commit/d738771a05b4505616defab52359870892bae171) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `createOverlayUnsavedChangesGuard` - the overlay flavor of the `unsavedChanges` family. Called from an overlay content component's injection context, it injects the current `OVERLAY_REF` and vetoes a dismissal (outside pointer, escape, drag, or a programmatic `close()`) while the watched form has unsaved changes, runs the `confirm`, and only then re-issues the close. Per-source opt-out via `dismissSources`, honors `disableClose`, and auto-cleans up on injector destroy.
315
601
 
316
602
  Also exposes the underlying close-veto seam on `OverlayRef`: `registerCloseGuard(guard)` and `forceClose(source?, result?)`.
317
603
 
318
604
  ### Patch Changes
319
605
 
320
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`b5b037e`](https://github.com/ethlete-io/ethdk/commit/b5b037e6e4e1c1d1ecef9c4c13edab01e40a1d0f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix anchored panels (`select`, `cascader`, the date/time pickers) closing when a popover opened from inside them is clicked. A nested overlay (a select body, menu or tooltip) mounts as a sibling pane in the overlay root, not a DOM descendant, so the panel's outside-pointer check treated a click in the child as an outside dismissal and closed itself. The check now resolves the whole nested overlay tree — anchored by each pane's `origin` — so a pointerdown anywhere inside a descendant popover no longer dismisses the panel that opened it.
606
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`b5b037e`](https://github.com/ethlete-io/ethdk/commit/b5b037e6e4e1c1d1ecef9c4c13edab01e40a1d0f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix anchored panels (`select`, `cascader`, the date/time pickers) closing when a popover opened from inside them is clicked. A nested overlay (a select body, menu or tooltip) mounts as a sibling pane in the overlay root, not a DOM descendant, so the panel's outside-pointer check treated a click in the child as an outside dismissal and closed itself. The check now resolves the whole nested overlay tree - anchored by each pane's `origin` - so a pointerdown anywhere inside a descendant popover no longer dismisses the panel that opened it.
321
607
 
322
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`4d70fb1`](https://github.com/ethlete-io/ethdk/commit/4d70fb1fd173e7e9d25031551f752196abb6f94e) Thanks [@github-actions](https://github.com/apps/github-actions)! - `etAutoSurface` now elevates correctly for content rendered inside an overlay. Projected/portaled content keeps the injector of where it was _declared_ (the trigger location), not the pane it renders into, so an `etAutoSurface` inside a select body, menu, date-picker, etc. resolved its parent surface from the outer trigger context and came out one elevation too low — the same level as the overlay's own panel instead of one above it.
608
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`4d70fb1`](https://github.com/ethlete-io/ethdk/commit/4d70fb1fd173e7e9d25031551f752196abb6f94e) Thanks [@github-actions](https://github.com/apps/github-actions)! - `etAutoSurface` now elevates correctly for content rendered inside an overlay. Projected/portaled content keeps the injector of where it was _declared_ (the trigger location), not the pane it renders into, so an `etAutoSurface` inside a select body, menu, date-picker, etc. resolved its parent surface from the outer trigger context and came out one elevation too low - the same level as the overlay's own panel instead of one above it.
323
609
 
324
- `AutoSurfaceDirective` now also consults the root surface-context tracker (which records the innermost open overlay's surface across the portal boundary) and takes whichever parent surface sits higher. Overlay panels that are themselves the overlay's surface (menu, select/date/cascader panels, tooltip, toggletip) opt out via the new `AutoSurfaceDirective.ignoreOverlaySurfaceContext()` so they keep adopting their overlay's elevation rather than stacking above it — their rendered surface is unchanged.
610
+ `AutoSurfaceDirective` now also consults the root surface-context tracker (which records the innermost open overlay's surface across the portal boundary) and takes whichever parent surface sits higher. Overlay panels that are themselves the overlay's surface (menu, select/date/cascader panels, tooltip, toggletip) opt out via the new `AutoSurfaceDirective.ignoreOverlaySurfaceContext()` so they keep adopting their overlay's elevation rather than stacking above it - their rendered surface is unchanged.
325
611
 
326
612
  - [`995eab1`](https://github.com/ethlete-io/ethdk/commit/995eab158002c0e36779cbd54dbbaf7da9355f58) Thanks [@TomTomB](https://github.com/TomTomB)! - Forms: clear ("×") buttons now fade in/out (opacity only) instead of appearing abruptly, consistently across date, time, date-time, duration, phone, select, and cascader. Respects `prefers-reduced-motion`. `et-date-range-input` gains the same clear button (new `clearable`/`clearLabel` inputs).
327
613
 
328
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`43e8711`](https://github.com/ethlete-io/ethdk/commit/43e8711f49ca995a4fdb95d95359219bd8298407) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form fields now keep their focused styling (accent border, lit label/affix) while a control's popup is open. Opening a date/time/date-range picker, select or cascader panel moves focus into the detached overlay, so `:focus-visible` no longer matched the field and it visibly dropped back to its resting look — controls now report an `expanded` state the field reflects as `[data-expanded]`.
614
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`43e8711`](https://github.com/ethlete-io/ethdk/commit/43e8711f49ca995a4fdb95d95359219bd8298407) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form fields now keep their focused styling (accent border, lit label/affix) while a control's popup is open. Opening a date/time/date-range picker, select or cascader panel moves focus into the detached overlay, so `:focus-visible` no longer matched the field and it visibly dropped back to its resting look - controls now report an `expanded` state the field reflects as `[data-expanded]`.
329
615
 
330
616
  Also fixes a flicker on the date-picker trigger button: clicking it while the field was focused briefly blurred the input (hiding the clear button and dropping the focused style) one frame before the picker opened. The trigger now prevents the mousedown default, matching the clear button, so focus stays on the field through the toggle.
331
617
 
332
618
  - [`246bb5e`](https://github.com/ethlete-io/ethdk/commit/246bb5ee26d6c28adacea316426a5af19b248a17) Thanks [@TomTomB](https://github.com/TomTomB)! - Form field: text-field controls (`et-input`, `et-number-input`,
333
619
  `et-password-input`, `et-textarea`) no longer render an empty `autocomplete=""`
334
- attribute when no autocomplete is set — the attribute is now omitted, clearing
620
+ attribute when no autocomplete is set - the attribute is now omitted, clearing
335
621
  Chrome's "Incorrect use of autocomplete attribute" warning.
336
622
 
337
623
  - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`b712197`](https://github.com/ethlete-io/ethdk/commit/b712197005495bc180e86d9645f77032da9fb266) Thanks [@github-actions](https://github.com/apps/github-actions)! - Date/time/date-range pickers, select and cascader now flip their alignment on the same side before flipping vertically: their anchored fallback placements changed from `['top-start']` to `['bottom-end', 'top-start', 'top-end']`. A field near the right viewport edge now opens right-aligned under the field (`bottom-end`) instead of being cross-axis shifted, matching the fallback behaviour menus already use.
338
624
 
339
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`62dbf77`](https://github.com/ethlete-io/ethdk/commit/62dbf77444238841fcd22a1c39467fd7f577d707) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor content no longer retints when the editor gains focus. The field frame is an `et-color-interactive--has-focus` ancestor that re-resolves the accent tokens on focus, and rendered content reading the accent — token chips (their outline and fill), links and the caret — inherited that shift. The content root now re-anchors the accent tokens to their resting value, insulating it from the field's interaction state (the same immunity the interactive toolbar buttons already have from carrying `et-color-interactive`).
625
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`62dbf77`](https://github.com/ethlete-io/ethdk/commit/62dbf77444238841fcd22a1c39467fd7f577d707) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor content no longer retints when the editor gains focus. The field frame is an `et-color-interactive--has-focus` ancestor that re-resolves the accent tokens on focus, and rendered content reading the accent - token chips (their outline and fill), links and the caret - inherited that shift. The content root now re-anchors the accent tokens to their resting value, insulating it from the field's interaction state (the same immunity the interactive toolbar buttons already have from carrying `et-color-interactive`).
340
626
 
341
- - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`5fc9aa4`](https://github.com/ethlete-io/ethdk/commit/5fc9aa4316390c2db908c6dcd3c2118945a11089) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et-select`: a searchable single select with a custom value template (`etSelectValue`) now swaps the rich display for the option's editable plain-text label inside the search input while the field is focused (edit mode), and restores the rich template on blur. Keyboard editing is now at parity with a plain searchable single select — the label is selected on open, Backspace edits the visible text, and erasing it clears the selection. Previously the input stayed empty in this case, so a single Backspace silently deleted the whole selected value with nothing visible to edit.
627
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`5fc9aa4`](https://github.com/ethlete-io/ethdk/commit/5fc9aa4316390c2db908c6dcd3c2118945a11089) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et-select`: a searchable single select with a custom value template (`etSelectValue`) now swaps the rich display for the option's editable plain-text label inside the search input while the field is focused (edit mode), and restores the rich template on blur. Keyboard editing is now at parity with a plain searchable single select - the label is selected on open, Backspace edits the visible text, and erasing it clears the selection. Previously the input stayed empty in this case, so a single Backspace silently deleted the whole selected value with nothing visible to edit.
342
628
 
343
629
  - [`139d734`](https://github.com/ethlete-io/ethdk/commit/139d73474ec710834a28df50160c2cce1e795c1c) Thanks [@TomTomB](https://github.com/TomTomB)! - Form field: trigger-based controls (select, date pickers) keep their focused frame after a pointer-driven commit, so the frame and the clear affordance no longer disagree about whether the field is focused.
344
630
 
@@ -354,29 +640,29 @@
354
640
 
355
641
  ### Patch Changes
356
642
 
357
- - [#3028](https://github.com/ethlete-io/ethdk/pull/3028) [`d8f50c5`](https://github.com/ethlete-io/ethdk/commit/d8f50c530b976390a8e655f3b1a4c0b9eaaae6ab) Thanks [@github-actions](https://github.com/apps/github-actions)! - Hover styles across all interactive components (buttons, chips, form controls, selects, cascader, menu, tabs, calendar, time picker, notification) no longer stick after tapping on touch devices — including the `etColorInteractive`/`etSurfaceInteractive` hover token resolution (guarded by `@media (hover: hover)`).
643
+ - [#3028](https://github.com/ethlete-io/ethdk/pull/3028) [`d8f50c5`](https://github.com/ethlete-io/ethdk/commit/d8f50c530b976390a8e655f3b1a4c0b9eaaae6ab) Thanks [@github-actions](https://github.com/apps/github-actions)! - Hover styles across all interactive components (buttons, chips, form controls, selects, cascader, menu, tabs, calendar, time picker, notification) no longer stick after tapping on touch devices - including the `etColorInteractive`/`etSurfaceInteractive` hover token resolution (guarded by `@media (hover: hover)`).
358
644
 
359
645
  ## 1.0.0-next.23
360
646
 
361
647
  ### Minor Changes
362
648
 
363
- - [`221c878`](https://github.com/ethlete-io/ethdk/commit/221c878d5f3e382ffed074bf93ab30afeda9d63f) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: flat search across all levels. Implement the optional `search(query)` hook on the `CascaderDataSource` (returning root → match path chains) and the panel gains a search input that swaps the columns for a flat, breadcrumb-labelled result list — committing a match closes, while a branch-only match jumps the columns to it. New headless pieces `etCascaderSearch` and `etCascaderSearchOption`; `et-cascader` renders the input automatically (`searchPlaceholder` input) and Escape now clears an active query before closing the panel.
649
+ - [`221c878`](https://github.com/ethlete-io/ethdk/commit/221c878d5f3e382ffed074bf93ab30afeda9d63f) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: flat search across all levels. Implement the optional `search(query)` hook on the `CascaderDataSource` (returning root → match path chains) and the panel gains a search input that swaps the columns for a flat, breadcrumb-labelled result list - committing a match closes, while a branch-only match jumps the columns to it. New headless pieces `etCascaderSearch` and `etCascaderSearchOption`; `et-cascader` renders the input automatically (`searchPlaceholder` input) and Escape now clears an active query before closing the panel.
364
650
 
365
- - [`221c878`](https://github.com/ethlete-io/ethdk/commit/221c878d5f3e382ffed074bf93ab30afeda9d63f) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: `cascaderFromQuery` builds a `CascaderDataSource` from `@ethlete/query` creators — per-level loads (concurrent, deduped/cached by the client), optional flat-search wiring with debounce and `minQueryLength`, and a `resolvePath` passthrough. The cascader's default `toErrorMessage` now shows an `Error`'s `message` verbatim (falling back to the generic text), so query failure messages surface without extra wiring.
651
+ - [`221c878`](https://github.com/ethlete-io/ethdk/commit/221c878d5f3e382ffed074bf93ab30afeda9d63f) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: `cascaderFromQuery` builds a `CascaderDataSource` from `@ethlete/query` creators - per-level loads (concurrent, deduped/cached by the client), optional flat-search wiring with debounce and `minQueryLength`, and a `resolvePath` passthrough. The cascader's default `toErrorMessage` now shows an `Error`'s `message` verbatim (falling back to the generic text), so query failure messages surface without extra wiring.
366
652
 
367
- - [`221c878`](https://github.com/ethlete-io/ethdk/commit/221c878d5f3e382ffed074bf93ab30afeda9d63f) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: multi-select via the new `multiple` input — activations toggle values (the form value becomes a `T[]`), the panel stays open, rows gain check squares, ancestors of a partial selection show an indeterminate dash and promote to a full checkmark once all their loaded descendants are selected. Search results toggle in place (keeping the result list), the trigger joins the selected labels, and programmatic values resolve their chains through `resolvePath`. The `value` model is now typed `T | T[] | null`.
653
+ - [`221c878`](https://github.com/ethlete-io/ethdk/commit/221c878d5f3e382ffed074bf93ab30afeda9d63f) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: multi-select via the new `multiple` input - activations toggle values (the form value becomes a `T[]`), the panel stays open, rows gain check squares, ancestors of a partial selection show an indeterminate dash and promote to a full checkmark once all their loaded descendants are selected. Search results toggle in place (keeping the result list), the trigger joins the selected labels, and programmatic values resolve their chains through `resolvePath`. The `value` model is now typed `T | T[] | null`.
368
654
 
369
- - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: new `et-cascader` / `[etCascader]` (`CASCADER_IMPORTS`) — a generic hierarchy value control that browses an abstract `CascaderDataSource<T>` level by level (sync array, `Promise` or `Observable`, each level lazy-loaded). Miller columns on desktop, single-column drill in a bottom sheet on mobile; `selectableLevels` (`'leaf'` | `'any'`), `path`/`pathValue` chain, per-column loading/empty/error states with retry, full ARIA tree keyboard navigation, and signal-forms integration. Error block `ET3300`–`ET3399`.
655
+ - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Cascader: new `et-cascader` / `[etCascader]` (`CASCADER_IMPORTS`) - a generic hierarchy value control that browses an abstract `CascaderDataSource<T>` level by level (sync array, `Promise` or `Observable`, each level lazy-loaded). Miller columns on desktop, single-column drill in a bottom sheet on mobile; `selectableLevels` (`'leaf'` | `'any'`), `path`/`pathValue` chain, per-column loading/empty/error states with retry, full ARIA tree keyboard navigation, and signal-forms integration. Error block `ET3300`–`ET3399`.
370
656
 
371
- Deep hierarchies stay compact: the desktop panel shows at most `maxVisibleColumns` (default 3) columns side by side, showing the whole drilled trail as a breadcrumb row below the columns once it overflows. All drilled levels ride a sliding track, so collapsing into a crumb (and navigating back out of one) is a coordinated slide rather than a pop. Navigating back is non-destructive — a crumb click or Arrow Left past the window edge slides the column window without discarding the deeper drill. Headless: `visibleColumns()`, `breadcrumbPath()`, `visibleColumnStart()`, `showColumn()`.
657
+ Deep hierarchies stay compact: the desktop panel shows at most `maxVisibleColumns` (default 3) columns side by side, showing the whole drilled trail as a breadcrumb row below the columns once it overflows. All drilled levels ride a sliding track, so collapsing into a crumb (and navigating back out of one) is a coordinated slide rather than a pop. Navigating back is non-destructive - a crumb click or Arrow Left past the window edge slides the column window without discarding the deeper drill. Headless: `visibleColumns()`, `breadcrumbPath()`, `visibleColumnStart()`, `showColumn()`.
372
658
 
373
- - [#3027](https://github.com/ethlete-io/ethdk/pull/3027) [`0a62001`](https://github.com/ethlete-io/ethdk/commit/0a6200181b706828bc8b228afb0743a269bd7e8e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: add `et-date-time-input` (+ headless `[etDateTimeInput]`), a combined date & time control with a string wire value — one field with a combined display format (strict-then-lenient typed entry, bare dates commit at midnight) and a picker overlay hosting calendar and time picker side by side (Date/Time tabs in the bottom sheet). A first day pick in the picker also commits at midnight — never the current wall-clock time.
659
+ - [#3027](https://github.com/ethlete-io/ethdk/pull/3027) [`0a62001`](https://github.com/ethlete-io/ethdk/commit/0a6200181b706828bc8b228afb0743a269bd7e8e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: add `et-date-time-input` (+ headless `[etDateTimeInput]`), a combined date & time control with a string wire value - one field with a combined display format (strict-then-lenient typed entry, bare dates commit at midnight) and a picker overlay hosting calendar and time picker side by side (Date/Time tabs in the bottom sheet). A first day pick in the picker also commits at midnight - never the current wall-clock time.
374
660
 
375
661
  - [`8bfe3ed`](https://github.com/ethlete-io/ethdk/commit/8bfe3ed805a760f13a5cef11125473b1342d747c) Thanks [@TomTomB](https://github.com/TomTomB)! - Date, time, date-time and date range inputs: new opt-in `mask` input. With a fixed-width numeric `displayFormat` (`dd.MM.yyyy`, `HH:mm`, …) typing gets guide placeholders (`__.__.____`), auto-inserted separators, paste filtering and a numeric soft keyboard; the lenient blur/Enter commit parsers stay authoritative. Formats a mask can't represent (locale formats like the default `P`/`p`, variable-width or text tokens) are refused with a dev-mode warning and typing stays unmasked. On the date range input each side is its own mask host, so the guide follows the focused field. The duration input deliberately gets no mask (unbounded first segment, right-anchored lenient entry). Supporting API: `[etInputMask]` now accepts `null` to disable the mask conditionally, and `InputMaskHost` grew an optional `resumeNativeSync()` for hosts whose mask can toggle off again.
376
662
 
377
- - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Duration input: new `et-duration-input` / `[etDurationInput]` (`DURATION_INPUT_IMPORTS`) — a duration control whose value is total elapsed **milliseconds** (`number | null`), kept out of the `Date` system. Configurable segment layout (`durationFormat`, e.g. `mm:ss`, `hh:mm:ss`, `hh:mm:ss.SSS`) with a lenient typed parse (`130` → `1:30`) committing on blur/Enter. Error code `ET3050` inside the shared date-time block.
663
+ - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Duration input: new `et-duration-input` / `[etDurationInput]` (`DURATION_INPUT_IMPORTS`) - a duration control whose value is total elapsed **milliseconds** (`number | null`), kept out of the `Date` system. Configurable segment layout (`durationFormat`, e.g. `mm:ss`, `hh:mm:ss`, `hh:mm:ss.SSS`) with a lenient typed parse (`130` → `1:30`) committing on blur/Enter. Error code `ET3050` inside the shared date-time block.
378
664
 
379
- - [`4c6b6d0`](https://github.com/ethlete-io/ethdk/commit/4c6b6d000ba568d73c8b191c52fed3206b6a00a6) Thanks [@TomTomB](https://github.com/TomTomB)! - Chip: filter-chip support — `etSelectionList` + `etSelectionOption` compose directly onto `et-chip` for selectable chip groups (single or multiple), with a color-theme tonal selected state and hover/focus affordances. Selection options now tolerate late-bound `value` inputs (directive compositions no longer throw NG0950).
665
+ - [`4c6b6d0`](https://github.com/ethlete-io/ethdk/commit/4c6b6d000ba568d73c8b191c52fed3206b6a00a6) Thanks [@TomTomB](https://github.com/TomTomB)! - Chip: filter-chip support - `etSelectionList` + `etSelectionOption` compose directly onto `et-chip` for selectable chip groups (single or multiple), with a color-theme tonal selected state and hover/focus affordances. Selection options now tolerate late-bound `value` inputs (directive compositions no longer throw NG0950).
380
666
 
381
667
  - [`04ffa53`](https://github.com/ethlete-io/ethdk/commit/04ffa53bf3b65977bd4f87d312781faa93057d1f) Thanks [@TomTomB](https://github.com/TomTomB)! - Forms: fix bugs and accessibility issues across the form controls, and add a few
382
668
  opt-in APIs.
@@ -399,31 +685,31 @@
399
685
  password `hideLabel`, phone `countryLabel`, date-picker-panel `dialogLabel`.
400
686
  - **Note:** the checkbox now toggles on `keydown` Space (matching switch and the
401
687
  selection options), and the select panel renders its listbox as an inner
402
- element — restyle if you targeted the panel host as the listbox.
688
+ element - restyle if you targeted the panel host as the listbox.
403
689
 
404
690
  - [`888ce8a`](https://github.com/ethlete-io/ethdk/commit/888ce8a504c7001f2fb50ae83302483d7148486a) Thanks [@TomTomB](https://github.com/TomTomB)! - Forms consistency: `readonly` and one-click clearing across more controls.
405
- - Checkbox, switch and the three selection-list groups now honor `readonly` (e.g. from a `readonly(...)` schema): normal look, still focusable (`aria-readonly`), toggling/selecting blocked — arrows in a readonly radio group move focus without selecting.
691
+ - Checkbox, switch and the three selection-list groups now honor `readonly` (e.g. from a `readonly(...)` schema): normal look, still focusable (`aria-readonly`), toggling/selecting blocked - arrows in a readonly radio group move focus without selecting.
406
692
  - Date, time, date-time, duration and phone inputs render a clear (×) button while the focused field holds a value (`clearable`, default on; label via `clearLabel`), backed by a public `clearValue()` on their headless directives.
407
693
 
408
694
  - [`85d7332`](https://github.com/ethlete-io/ethdk/commit/85d73327be9a5fc2154c5a0f0f2defe25e657a55) Thanks [@TomTomB](https://github.com/TomTomB)! - Masked input: the mask now attaches through a public `INPUT_MASK_HOST` contract (provided by `et-input` out of the box), so custom field directives can host `[etInputMask]` too. Pattern masks additionally expose `complete()` on the directive (`0`/`a`/`*` slots required, `9` optional; `null` for masks without completeness) via a new optional `MaskSpec.isComplete`.
409
695
 
410
- - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Masked input: new `[etInputMask]` directive layering input masking onto `et-input` — pattern-string masks (`00-00-0000` style grammar) or `MaskSpec` objects, with `createCurrencyMask` / `createIbanMask` / `createCardMask` factories, raw-or-masked form values (`maskValueMode`, raw by default), focused-state guide placeholders (`placeholderChar`) and full caret handling (`MASKED_INPUT_IMPORTS`).
696
+ - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Masked input: new `[etInputMask]` directive layering input masking onto `et-input` - pattern-string masks (`00-00-0000` style grammar) or `MaskSpec` objects, with `createCurrencyMask` / `createIbanMask` / `createCardMask` factories, raw-or-masked form values (`maskValueMode`, raw by default), focused-state guide placeholders (`placeholderChar`) and full caret handling (`MASKED_INPUT_IMPORTS`).
411
697
 
412
698
  - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Number input: new `stepper` input on `et-number-input` rendering −/+ buttons with press-and-hold auto-repeat, `min`/`max` clamping and bound-aware disabling; the headless `NumberInputDirective` gains `stepBy(direction)` / `canStepUp` / `canStepDown`. Adds the `et-minus` built-in icon.
413
699
 
414
- - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Password input: new `et-password-input` / `[etPasswordInput]` (`PASSWORD_INPUT_IMPORTS`) — reveal toggle (`revealed` model, `revealable`, `aria-pressed`), opt-in Caps Lock warning (`capsLockWarning`), and a `strength` signal (0–4 typing-feedback heuristic) for composing strength meters. Adds `et-eye` / `et-eye-slash` built-in icons.
700
+ - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Password input: new `et-password-input` / `[etPasswordInput]` (`PASSWORD_INPUT_IMPORTS`) - reveal toggle (`revealed` model, `revealable`, `aria-pressed`), opt-in Caps Lock warning (`capsLockWarning`), and a `strength` signal (0–4 typing-feedback heuristic) for composing strength meters. Adds `et-eye` / `et-eye-slash` built-in icons.
415
701
 
416
702
  - [`36ac99d`](https://github.com/ethlete-io/ethdk/commit/36ac99db8ccf70597d2dda3e845effe4e0687ba9) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: full tag-input ergonomics in custom-value mode (`allowCustomValues`).
417
- - A "Create …" listbox row (label via `createLabel`) now offers the query as a custom value even while options still match — keyboard-reachable via virtual focus; headless compositions use `customValueCandidate()` + `customValueOption`.
418
- - New inputs: `customValueSeparators` (characters that commit while typing and split pastes), `commitCustomValueOnClose` (pending text commits on Tab/outside-click close instead of being discarded), `normalizeCustomValue` (map/reject raw text), and `maxSelection` (caps multi selection and locks the search input while full, exposed as `isFull()`; unselected options render disabled while full — deselecting frees them again).
703
+ - A "Create …" listbox row (label via `createLabel`) now offers the query as a custom value even while options still match - keyboard-reachable via virtual focus; headless compositions use `customValueCandidate()` + `customValueOption`.
704
+ - New inputs: `customValueSeparators` (characters that commit while typing and split pastes), `commitCustomValueOnClose` (pending text commits on Tab/outside-click close instead of being discarded), `normalizeCustomValue` (map/reject raw text), and `maxSelection` (caps multi selection and locks the search input while full, exposed as `isFull()`; unselected options render disabled while full - deselecting frees them again).
419
705
  - `commitCustomValue(raw)` is now public for imperative commits.
420
706
 
421
- - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: new `et-select-option-group` / `[etSelectOptionGroup]` for labelled listbox sections. Grouping is presentational — options stay flat for keyboard navigation and typeahead — and a group hides itself once all its options are filtered out under `filterMode="internal"`. `role="group"` + `aria-labelledby`; token `--et-select-option-group-label-font-size`. Error code `ET1009`.
707
+ - [`f005c94`](https://github.com/ethlete-io/ethdk/commit/f005c944f7edf67842d0a3e635d7e35e8de44445) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: new `et-select-option-group` / `[etSelectOptionGroup]` for labelled listbox sections. Grouping is presentational - options stay flat for keyboard navigation and typeahead - and a group hides itself once all its options are filtered out under `filterMode="internal"`. `role="group"` + `aria-labelledby`; token `--et-select-option-group-label-font-size`. Error code `ET1009`.
422
708
 
423
- - [`b61ad0f`](https://github.com/ethlete-io/ethdk/commit/b61ad0fbe61ed1b0e7e8cd98e8d673ae91f10ff1) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: new `selectOptionsFromV2Query` feeds the async select from a legacy `V2QueryClient` query (or a `createLegacyQueryCreator` interop wrapper) — the `V2QueryClient` counterpart of `selectOptionsFromQuery`, returning the same signal bundle.
709
+ - [`b61ad0f`](https://github.com/ethlete-io/ethdk/commit/b61ad0fbe61ed1b0e7e8cd98e8d673ae91f10ff1) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: new `selectOptionsFromV2Query` feeds the async select from a legacy `V2QueryClient` query (or a `createLegacyQueryCreator` interop wrapper) - the `V2QueryClient` counterpart of `selectOptionsFromQuery`, returning the same signal bundle.
424
710
 
425
711
  - [`4f34f1f`](https://github.com/ethlete-io/ethdk/commit/4f34f1fa2ef1809f6b281d52fdc0f037923e88db) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: new data-driven `options` input with built-in virtualization for large option lists.
426
- - `options` takes `SelectOptionData[]` (`{ value, label, disabled? }`) — the select renders the rows itself and windows them, so only the rows near the viewport exist in the DOM (2000 options ≈ 15 rendered nodes). Internal filtering, keyboard navigation, typeahead and closed-panel label resolution work across the full data set.
712
+ - `options` takes `SelectOptionData[]` (`{ value, label, disabled? }`) - the select renders the rows itself and windows them, so only the rows near the viewport exist in the DOM (2000 options ≈ 15 rendered nodes). Internal filtering, keyboard navigation, typeahead and closed-panel label resolution work across the full data set.
427
713
  - `etSelectOptionTemplate` customizes the row content of data-driven options, with the source entry (extra fields included) as template context.
428
714
  - Headless: `etSelectViewport` marks the scroll container to window against, `etSelectVirtualOption` renders one windowed item, and `virtualizedItems()` / `virtualWindow` on `[etSelect]` expose the window state.
429
715
  - Breaking for headless consumers of `SelectItem`: `elementRef` is now `element: Signal<HTMLElement | null>` (`null` for a data-driven option outside the rendered window).
@@ -450,7 +736,7 @@
450
736
 
451
737
  - [`f1841b7`](https://github.com/ethlete-io/ethdk/commit/f1841b7ec3a4f6e280c961d072a90fd2ceba75d7) Thanks [@TomTomB](https://github.com/TomTomB)! - Phone input: picking a country prefix now moves focus to the number field instead of back to the prefix toggle (closing the picker with Escape still refocuses the toggle).
452
738
 
453
- - [`57a5104`](https://github.com/ethlete-io/ethdk/commit/57a5104d3805824cf6b28725c5d9aae670af9626) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: rubber-band overscroll (macOS) no longer drags the panel background along with the list, exposing the page behind the overlay — the panel chrome now sits on a non-scrolling element around an inner `.et-select-panel-scroller`.
739
+ - [`57a5104`](https://github.com/ethlete-io/ethdk/commit/57a5104d3805824cf6b28725c5d9aae670af9626) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: rubber-band overscroll (macOS) no longer drags the panel background along with the list, exposing the page behind the overlay - the panel chrome now sits on a non-scrolling element around an inner `.et-select-panel-scroller`.
454
740
 
455
741
  - [`fa0e118`](https://github.com/ethlete-io/ethdk/commit/fa0e1189f46a5359f5018fba15fbb405af646314) Thanks [@TomTomB](https://github.com/TomTomB)! - Select option checkmarks and menu radio/checkbox item indicators now render on the right (trailing) edge of their row instead of the left, so option labels align flush with the row start. Standalone form controls (checkbox, radio, switch, selection lists, cascader check squares) keep their leading position.
456
742
 
@@ -472,11 +758,11 @@
472
758
  - Calendar: month navigation slides the new grid in from the travel direction (skipped under `prefers-reduced-motion`); the headless `[etCalendar]` exposes `navigationDirection` and `visibleMonthKey` for custom transitions. In the bottom sheet the calendar reserves the 6-week height so the sheet never resizes.
473
759
  - Calendar / time picker: keyboard focus is no longer lost when the focused cell/option is re-created mid-interaction (month crossing, an off-step option leaving the list).
474
760
 
475
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`d651c4c`](https://github.com/ethlete-io/ethdk/commit/d651c4ccacb309db808f71ebc6ceda8e5e0ffe82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: new `et-otp-input` control (`OTP_INPUT_IMPORTS`) — segmented one-time-code/PIN entry backed by a single invisible native input for reliable SMS autofill (`autocomplete="one-time-code"`) and native paste. `length`/`charset` (numeric, alphanumeric or RegExp)/`masked` inputs, a `completed` output per full entry, separator-stripping paste handling, and tokens `--et-otp-input-segment-size/-gap/-radius`. Typed characters pop in and the active segment shows a blinking synthetic caret (both respect `prefers-reduced-motion`).
761
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`d651c4c`](https://github.com/ethlete-io/ethdk/commit/d651c4ccacb309db808f71ebc6ceda8e5e0ffe82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: new `et-otp-input` control (`OTP_INPUT_IMPORTS`) - segmented one-time-code/PIN entry backed by a single invisible native input for reliable SMS autofill (`autocomplete="one-time-code"`) and native paste. `length`/`charset` (numeric, alphanumeric or RegExp)/`masked` inputs, a `completed` output per full entry, separator-stripping paste handling, and tokens `--et-otp-input-segment-size/-gap/-radius`. Typed characters pop in and the active segment shows a blinking synthetic caret (both respect `prefers-reduced-motion`).
476
762
 
477
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`d651c4c`](https://github.com/ethlete-io/ethdk/commit/d651c4ccacb309db808f71ebc6ceda8e5e0ffe82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: new `et-rating` control (star rating, `RATING_IMPORTS`) — `FormValueControl<number | null>` implementing the slider pattern: hover preview, drag/swipe rating (mouse and touch, commits on release), half steps (`allowHalf`), click-again/Backspace to clear, arrow-key stepping, and a custom icon slot (`ng-template[etRatingIcon]`). The fill animates as one continuous sweep. Tokens `--et-rating-icon-size` / `--et-rating-gap`.
763
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`d651c4c`](https://github.com/ethlete-io/ethdk/commit/d651c4ccacb309db808f71ebc6ceda8e5e0ffe82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: new `et-rating` control (star rating, `RATING_IMPORTS`) - `FormValueControl<number | null>` implementing the slider pattern: hover preview, drag/swipe rating (mouse and touch, commits on release), half steps (`allowHalf`), click-again/Backspace to clear, arrow-key stepping, and a custom icon slot (`ng-template[etRatingIcon]`). The fill animates as one continuous sweep. Tokens `--et-rating-icon-size` / `--et-rating-gap`.
478
764
 
479
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`d651c4c`](https://github.com/ethlete-io/ethdk/commit/d651c4ccacb309db808f71ebc6ceda8e5e0ffe82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: new `et-tag-input` control (`TAG_INPUT_IMPORTS`) — free-text tags as removable chips with an inline field inside the `et-form-field` shell. Commits on configurable `separators` (Enter/comma by default) and blur, `normalizeTag`/`allowDuplicates`/`maxTags`, Backspace removes the last tag, and pastes split on separators and newlines. For tags with suggestions, compose the select (`multiple` + search + `allowCustomValues`) instead.
765
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`d651c4c`](https://github.com/ethlete-io/ethdk/commit/d651c4ccacb309db808f71ebc6ceda8e5e0ffe82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: new `et-tag-input` control (`TAG_INPUT_IMPORTS`) - free-text tags as removable chips with an inline field inside the `et-form-field` shell. Commits on configurable `separators` (Enter/comma by default) and blur, `normalizeTag`/`allowDuplicates`/`maxTags`, Backspace removes the last tag, and pastes split on separators and newlines. For tags with suggestions, compose the select (`multiple` + search + `allowCustomValues`) instead.
480
766
 
481
767
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: three new form-field controls and a small headless API addition.
482
768
  - `et-textarea` (+ headless `TextareaDirective`): multi-line plain-text control with autosize on by default (`rows`, `minRows`, `maxRows`, `resize`).
@@ -484,17 +770,17 @@
484
770
  - `et-color-input` (+ headless `ColorInputDirective`): native color picker as a swatch + hex value, form value `'#rrggbb' | null`; tokens `--et-color-input-swatch-size` / `--et-color-input-swatch-radius`.
485
771
  - `InputDirective` (and the new input directives) now expose a public `nativeControl` signal referencing the native element, for integrations such as input masking.
486
772
 
487
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`e0b71b1`](https://github.com/ethlete-io/ethdk/commit/e0b71b19a3a14c2c2250d7a217299f7956bb5c3b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `provideIconOverrides()` to swap the built-in `et-*` icons app-wide (or per subtree) — e.g. with your own Font Awesome set. Overrides are keyed by name/variant and merged on top of each component's own `provideIcons()`, so they reach into components that self-register the same name while leaving unlisted icons on their default. The override `name` autocompletes to the built-in set via the new `ET_BUILT_IN_ICON_NAMES` / `EtBuiltInIconName` exports, and any other string still registers a brand-new icon.
773
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`e0b71b1`](https://github.com/ethlete-io/ethdk/commit/e0b71b19a3a14c2c2250d7a217299f7956bb5c3b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `provideIconOverrides()` to swap the built-in `et-*` icons app-wide (or per subtree) - e.g. with your own Font Awesome set. Overrides are keyed by name/variant and merged on top of each component's own `provideIcons()`, so they reach into components that self-register the same name while leaving unlisted icons on their default. The override `name` autocompletes to the built-in set via the new `ET_BUILT_IN_ICON_NAMES` / `EtBuiltInIconName` exports, and any other string still registers a brand-new icon.
488
774
 
489
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`f168303`](https://github.com/ethlete-io/ethdk/commit/f168303bf0a78c559d6733d04c92a1a1c632d42a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: new `et-multi-language-rich-text-editor` — authors the same content in several consumer-defined `languages`, switching between them from a toolbar dropdown that flags which languages are still empty. Its value is a `Record<languageCode, markdown>`, so every translation persists in one form field; bind it with `[formField]` and use the exported `requiredLanguages` validator to require specific translations.
775
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`f168303`](https://github.com/ethlete-io/ethdk/commit/f168303bf0a78c559d6733d04c92a1a1c632d42a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: new `et-multi-language-rich-text-editor` - authors the same content in several consumer-defined `languages`, switching between them from a toolbar dropdown that flags which languages are still empty. Its value is a `Record<languageCode, markdown>`, so every translation persists in one form field; bind it with `[formField]` and use the exported `requiredLanguages` validator to require specific translations.
490
776
 
491
- - [#3024](https://github.com/ethlete-io/ethdk/pull/3024) [`144832a`](https://github.com/ethlete-io/ethdk/commit/144832ae74abfdbe8f084c14d6a903ee2eda18cf) Thanks [@TomTomB](https://github.com/TomTomB)! - Forms: new `et-phone-input` control (`PHONE_INPUT_IMPORTS`) — tel entry with a searchable country picker built on the select's headless core. Value is normalized `+<dial><national>`.
777
+ - [#3024](https://github.com/ethlete-io/ethdk/pull/3024) [`144832a`](https://github.com/ethlete-io/ethdk/commit/144832ae74abfdbe8f084c14d6a903ee2eda18cf) Thanks [@TomTomB](https://github.com/TomTomB)! - Forms: new `et-phone-input` control (`PHONE_INPUT_IMPORTS`) - tel entry with a searchable country picker built on the select's headless core. Value is normalized `+<dial><national>`.
492
778
  - Typing/pasting `+…` (or a `00…` international prefix) re-derives the country by longest dial-code match; manual picks survive shared codes like `+1`, switching countries keeps the national number, and a leading national trunk `0` is stripped (`0171…` → `+49171…`).
493
779
  - Digits are grouped for display while unfocused (cosmetic only); the country picker searches names and dial codes, shows an empty state, keeps a fixed panel width, and takes custom flag art via `ng-template[etPhoneInputFlag]`.
494
780
  - Zero runtime dependency: ISO + dial codes shipped, names via `Intl.DisplayNames`, emoji flags.
495
781
  - The underlying select gained a `mirrorPanelWidth` input (off for compact triggers), with the panel capped at `min(400px, 100vw - 24px)`.
496
782
 
497
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the link flow is now a responsive popover (arrow-anchored on wider screens, a keyboard-pinned top sheet on touch) to edit a link's text and URL, with an open-in-new-tab toggle — replacing the browser `prompt()`. New-tab links persist through the Markdown value as raw HTML (`<a target="_blank" rel="noopener noreferrer">`); ordinary links stay `[text](url)`. `htmlToMarkdown` / `markdownToHtml` in `@ethlete/core` now round-trip `target="_blank"` anchors (sanitized href + forced `rel`). After applying a link the caret moves just past it, with a trailing space added when the link ends the line.
783
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the link flow is now a responsive popover (arrow-anchored on wider screens, a keyboard-pinned top sheet on touch) to edit a link's text and URL, with an open-in-new-tab toggle - replacing the browser `prompt()`. New-tab links persist through the Markdown value as raw HTML (`<a target="_blank" rel="noopener noreferrer">`); ordinary links stay `[text](url)`. `htmlToMarkdown` / `markdownToHtml` in `@ethlete/core` now round-trip `target="_blank"` anchors (sanitized href + forced `rel`). After applying a link the caret moves just past it, with a trailing space added when the link ends the line.
498
784
 
499
785
  - [#3024](https://github.com/ethlete-io/ethdk/pull/3024) [`144832a`](https://github.com/ethlete-io/ethdk/commit/144832ae74abfdbe8f084c14d6a903ee2eda18cf) Thanks [@TomTomB](https://github.com/TomTomB)! - Rich text editor: mobile toolbar and editing fixes.
500
786
  - On touch devices the static toolbar docks above the on-screen keyboard while editing (tracked via `visualViewport`, staying pinned as the page scrolls and inside a same-origin iframe) instead of sitting at the top under the platform's selection menu; it fades in only once the editor is active and its menus open without stealing keyboard focus. With a mouse/trackpad it stays at the top as before.
@@ -505,19 +791,19 @@
505
791
  - `OverlayRef` gained `afterClosedEvent()`, which also reports how the overlay was closed (`escape`, `outside-pointer`, `api`, …).
506
792
 
507
793
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor:
508
- - Table tool: the grid-size picker supports touch — drag across the grid to size the table and release to insert; when a table's header row was deleted the menu offers **Insert header row**, and inserting a row from the header now lands in the table body.
794
+ - Table tool: the grid-size picker supports touch - drag across the grid to size the table and release to insert; when a table's header row was deleted the menu offers **Insert header row**, and inserting a row from the header now lands in the table body.
509
795
  - The link editor and floating toolbar anchor to the selected text (not the full-width block) so the arrow points at the text, and the link editor now opens correctly in an empty editor.
510
796
  - The trailing space inserted after atomic tokens (mentions, merge fields) and line-ending links is now a no-break space (Chrome dropped the plain one, gluing the next word); it still serializes as a regular space.
511
797
  - Form field: the `inline` label mode now lays out correctly around rich text editors.
512
- - `RichTextEditorToolDefinition` gains an optional `keydown` hook; table caret navigation now ships with `provideRichTextEditorTableTool` via that hook instead of being bundled into every editor (`editorDom.tableExit` / `tableEnter` are removed) — provide the table tool if your content can contain tables.
798
+ - `RichTextEditorToolDefinition` gains an optional `keydown` hook; table caret navigation now ships with `provideRichTextEditorTableTool` via that hook instead of being bundled into every editor (`editorDom.tableExit` / `tableEnter` are removed) - provide the table tool if your content can contain tables.
513
799
 
514
800
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`1f03013`](https://github.com/ethlete-io/ethdk/commit/1f03013609e8a734788db5b3b7657973fb430b87) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: toolbar accessibility and pressed-state polish.
515
801
  - Toolbar buttons that open a menu or popover (heading, alignment, table, link) now show their pressed state while the popover is open.
516
802
  - The toolbar is now a single tab stop following the ARIA toolbar pattern: Tab enters it, `ArrowLeft`/`ArrowRight` (plus `Home`/`End`) move focus between buttons, and the next Tab moves on to the editor content.
517
803
  - `et-icon-button` now forwards the `emitAriaPressed` input, so `aria-pressed` can be suppressed on pressed-styled buttons that already expose `aria-expanded`.
518
804
 
519
- - [#3024](https://github.com/ethlete-io/ethdk/pull/3024) [`144832a`](https://github.com/ethlete-io/ethdk/commit/144832ae74abfdbe8f084c14d6a903ee2eda18cf) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: new `et-select` form control — a combobox-pattern trigger opening an anchored, width-mirrored listbox panel (`SELECT_IMPORTS`, plus the headless `[etSelect]` / `[etSelectTrigger]` / `ng-template[etSelectSurface]` / `[etSelectListbox]` / `[etSelectOption]` graph and `et-select-panel` / `et-select-option`). Integrates with `et-form-field` (new `select` control type, all label modes).
520
- - Single select: full keyboard model — arrows/Home/End move virtual focus via `aria-activedescendant`, Enter/Space commit, typeahead while open, printable keys commit directly while closed; resolves a preselected value's label without ever opening the panel.
805
+ - [#3024](https://github.com/ethlete-io/ethdk/pull/3024) [`144832a`](https://github.com/ethlete-io/ethdk/commit/144832ae74abfdbe8f084c14d6a903ee2eda18cf) Thanks [@TomTomB](https://github.com/TomTomB)! - Select: new `et-select` form control - a combobox-pattern trigger opening an anchored, width-mirrored listbox panel (`SELECT_IMPORTS`, plus the headless `[etSelect]` / `[etSelectTrigger]` / `ng-template[etSelectSurface]` / `[etSelectListbox]` / `[etSelectOption]` graph and `et-select-panel` / `et-select-option`). Integrates with `et-form-field` (new `select` control type, all label modes).
806
+ - Single select: full keyboard model - arrows/Home/End move virtual focus via `aria-activedescendant`, Enter/Space commit, typeahead while open, printable keys commit directly while closed; resolves a preselected value's label without ever opening the panel.
521
807
  - Multi select (`multiple`): array value, options toggle without closing (`aria-multiselectable`), selection shown as removable `et-chip`s; `deselectOption(...)` and a customizable `ng-template[etSelectValue]`.
522
808
  - Search (`input[etSelectSearch]`): inline searchable combobox; `filterMode` `'internal'` (default) or `'external'` (via the `queryChange` output), `allowCustomValues`, and `selectOptionsFromQuery(...)` to feed options from an `@ethlete/query` query (debounce, `minQueryLength`, `toHasMore` pagination).
523
809
  - Async state inputs `loading` / `error` / `hasMoreItems` render default panel rows (spinner / alert / load-more via `loadMoreRequested`), each overridable through `ng-template[etSelectLoading]` / `[etSelectError]` / `[etSelectEmpty]`.
@@ -527,28 +813,28 @@
527
813
  - Form field exposes `controlFrameElement` on its contract so overlay-based controls can anchor their panels to the visible box.
528
814
 
529
815
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`bd8ec82`](https://github.com/ethlete-io/ethdk/commit/bd8ec8205d080bbfad58760dab13d346159b7a1c) Thanks [@github-actions](https://github.com/apps/github-actions)! - New time controls:
530
- - `et-time-picker` (+ headless `[etTimePicker]` column/option directives): inline column-list time picker on `Date` values — columns derive from a date-fns format (12/24h, optional seconds, AM/PM), `minuteStep`/`secondStep`, roving-focus listbox columns with wrapping arrows and type-to-jump.
816
+ - `et-time-picker` (+ headless `[etTimePicker]` column/option directives): inline column-list time picker on `Date` values - columns derive from a date-fns format (12/24h, optional seconds, AM/PM), `minuteStep`/`secondStep`, roving-focus listbox columns with wrapping arrows and type-to-jump.
531
817
  - `et-time-input` (+ headless `[etTimeInput]`): string-valued form control (`TIME_FORMAT` token, default `HH:mm`) with lenient typed parsing (`930` → 09:30, `9pm`, `9.30`) and an anchored time-picker overlay that stays open across part picks.
532
818
 
533
819
  ### Patch Changes
534
820
 
535
821
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`56a38d5`](https://github.com/ethlete-io/ethdk/commit/56a38d5f68c3f4a5d866757de23e06d0662aae25) Thanks [@github-actions](https://github.com/apps/github-actions)! - Date & time inputs: the picker trigger buttons now have a 44px tap target (invisible hit-area extension, no visual change). Time picker: options gain visual hierarchy (muted until interacted, tinted roving anchor, column separators) and the columns keep a half-faded number at each edge as a scroll cue.
536
822
 
537
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`1d8b757`](https://github.com/ethlete-io/ethdk/commit/1d8b7570f7d65a59616b99a93243b4ba7a9c9d53) Thanks [@github-actions](https://github.com/apps/github-actions)! - Icons: the `@ethlete/components:icons` generator no longer emits a `GENERATED_ICONS` aggregate array — spreading it into `provideIcons()` registered every icon and defeated tree shaking. Import the individual `IconDefinition` constants instead; re-running the generator removes the array from the generated file.
823
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`1d8b757`](https://github.com/ethlete-io/ethdk/commit/1d8b7570f7d65a59616b99a93243b4ba7a9c9d53) Thanks [@github-actions](https://github.com/apps/github-actions)! - Icons: the `@ethlete/components:icons` generator no longer emits a `GENERATED_ICONS` aggregate array - spreading it into `provideIcons()` registered every icon and defeated tree shaking. Import the individual `IconDefinition` constants instead; re-running the generator removes the array from the generated file.
538
824
 
539
825
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: anchored arrows (menu, tooltip, toggletip) now match the pane's actual background and border, so an arrow no longer stays a surface elevation too low when its pane sits on a raised surface (e.g. a menu opened from a filled form-field).
540
826
 
541
827
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlays and menus now open on insecure origins (plain-HTTP pages on a LAN IP, not just `localhost`/HTTPS). Id generation used `crypto.randomUUID()`, which is `undefined` outside a secure context, so opening any dialog, sheet, anchored overlay or menu threw and only the backdrop appeared. A new `randomId()` helper in `@ethlete/core` uses `crypto.randomUUID()` when available and falls back to `getRandomValues` otherwise.
542
828
 
543
829
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`00b7c33`](https://github.com/ethlete-io/ethdk/commit/00b7c337e5ae0ac1bfc7186237b1ac2879eb018d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Theming: overlay panes (menu, select) now resolve their color context through passive providers and apply it before the first painted frame.
544
- - `ProvideColorDirective` gains `resolvedColor` — the color that actually applies at the provider's location, falling through passive providers like the CSS cascade does. `syncWithProvider` uses it, so a passive in-between provider (e.g. a form field's) no longer erases the theme inside a detached overlay pane.
830
+ - `ProvideColorDirective` gains `resolvedColor` - the color that actually applies at the provider's location, falling through passive providers like the CSS cascade does. `syncWithProvider` uses it, so a passive in-between provider (e.g. a form field's) no longer erases the theme inside a detached overlay pane.
545
831
  - The menu and select panels install the context sync during construction instead of in an effect, eliminating a wrong-theme flash during the enter animation.
546
832
 
547
- - [#3025](https://github.com/ethlete-io/ethdk/pull/3025) [`416cfb8`](https://github.com/ethlete-io/ethdk/commit/416cfb8c3f370783a96b2fe59b827e981cac7b17) Thanks [@TomTomB](https://github.com/TomTomB)! - Overlay sheets: fix the black gap that appeared at the docked edge while a sheet sprang into view. The enter spring overshoots slightly past the docked edge, and the filler meant to cover that gap was an `::after` strip positioned just outside the host — which sheets clip away with their `overflow: hidden` (kept for the rounded corners), so nothing painted and the page background showed through (most visible with sheets whose surface is painted on nested content, e.g. the date picker). The filler is now a solid offset `box-shadow`, which is not clipped by the host's own overflow and needs no change to the corner clipping. Its color is measured from the sheet's actually-painted surface at open time, so it matches even when that surface sits on nested content one elevation above the container host (where the host's own surface token would be a shade off).
833
+ - [#3025](https://github.com/ethlete-io/ethdk/pull/3025) [`416cfb8`](https://github.com/ethlete-io/ethdk/commit/416cfb8c3f370783a96b2fe59b827e981cac7b17) Thanks [@TomTomB](https://github.com/TomTomB)! - Overlay sheets: fix the black gap that appeared at the docked edge while a sheet sprang into view. The enter spring overshoots slightly past the docked edge, and the filler meant to cover that gap was an `::after` strip positioned just outside the host - which sheets clip away with their `overflow: hidden` (kept for the rounded corners), so nothing painted and the page background showed through (most visible with sheets whose surface is painted on nested content, e.g. the date picker). The filler is now a solid offset `box-shadow`, which is not clipped by the host's own overflow and needs no change to the corner clipping. Its color is measured from the sheet's actually-painted surface at open time, so it matches even when that surface sits on nested content one elevation above the container host (where the host's own surface token would be a shade off).
548
834
 
549
835
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`1fa8e45`](https://github.com/ethlete-io/ethdk/commit/1fa8e4543c976658d0fbee5902ce43b9418932c3) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: the sidebar page component no longer triggers an `NG0912` component ID collision when `@ethlete/cdk` is loaded in the same app.
550
836
 
551
- - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the selection (floating) toolbar is now a pointer-device-only enhancement. On touch it fought the platform's native selection menu (Copy/Paste/…) and appeared unreliably, so it is suppressed there — the always-visible static toolbar covers formatting on touch. Mouse/trackpad behavior is unchanged.
837
+ - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`9431073`](https://github.com/ethlete-io/ethdk/commit/9431073bb693aa10bbb84d5196597cb2c4b7463f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the selection (floating) toolbar is now a pointer-device-only enhancement. On touch it fought the platform's native selection menu (Copy/Paste/…) and appeared unreliably, so it is suppressed there - the always-visible static toolbar covers formatting on touch. Mouse/trackpad behavior is unchanged.
552
838
 
553
839
  - [#3022](https://github.com/ethlete-io/ethdk/pull/3022) [`428f971`](https://github.com/ethlete-io/ethdk/commit/428f9718c96038a4aa9fee603b11ea341c7fe99b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor fixes:
554
840
  - The table size picker now supports arrow-key navigation (Enter/Space inserts the selected size, Escape/Tab close the menu from a focused cell).
@@ -564,7 +850,7 @@
564
850
 
565
851
  - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`1d7aaca`](https://github.com/ethlete-io/ethdk/commit/1d7aacaec10f3d3d7278733ebf5d834e8a89b1f7) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: add opt-in, tree-shakeable building-block autocomplete. Add the
566
852
  `etRichTextEditorTriggers` directive (with `RICH_TEXT_EDITOR_TRIGGERS_IMPORTS`) and pass triggers
567
- built with `createRichTextEditorTrigger` — typing a trigger char (e.g. `#`, `@`) opens a
853
+ built with `createRichTextEditorTrigger` - typing a trigger char (e.g. `#`, `@`) opens a
568
854
  caret-anchored, menu-styled popup, and picking an item inserts an atomic `{{type:id}}` token chip.
569
855
  Item sources can be static, `Promise`, or `Observable`. Use `provideRichTextEditorTokenRendering(...)`
570
856
  to render stored token values as chips in read-only contexts, or `createRichTextEditorTriggerWithQuery(...)`
@@ -582,7 +868,7 @@
582
868
 
583
869
  `@ethlete/core`: `markdownToHtml`/`htmlToMarkdown` now round-trip **nested** lists (two-space indentation per level), instead of flattening them.
584
870
 
585
- - [`c829986`](https://github.com/ethlete-io/ethdk/commit/c82998628a487effe34d2061811f3cee0fa4f7bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Rich text editor: Markdown autoformat while typing (opt out with `autoformat=false`). Line-start prefixes convert on space — `-`/`*`/`+` into a bulleted list, `1.` into a numbered list, `#`–`###` into a heading — and closing an inline run (`**bold**`, `*italic*`, `` `code` ``, `~~strike~~`, `__`/`_`) converts it into its mark with the caret placed after it. Autoformat is token-aware: registered trigger characters are reserved (a `#` trigger keeps opening its autocomplete instead of becoming a heading) and conversion is suspended while a trigger popup is open.
871
+ - [`c829986`](https://github.com/ethlete-io/ethdk/commit/c82998628a487effe34d2061811f3cee0fa4f7bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Rich text editor: Markdown autoformat while typing (opt out with `autoformat=false`). Line-start prefixes convert on space - `-`/`*`/`+` into a bulleted list, `1.` into a numbered list, `#`–`###` into a heading - and closing an inline run (`**bold**`, `*italic*`, `` `code` ``, `~~strike~~`, `__`/`_`) converts it into its mark with the caret placed after it. Autoformat is token-aware: registered trigger characters are reserved (a `#` trigger keeps opening its autocomplete instead of becoming a heading) and conversion is suspended while a trigger popup is open.
586
872
 
587
873
  - [`c829986`](https://github.com/ethlete-io/ethdk/commit/c82998628a487effe34d2061811f3cee0fa4f7bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Rich text editor: pasted HTML is now normalized into the editor's own schema (foreign tags, inline styles, classes and scripts never enter the editable DOM; token chips keep their identity), and pressing Enter at the edge of a heading starts a plain paragraph instead of continuing the heading. Shift+Enter always stays a soft line break.
588
874
 
@@ -594,7 +880,7 @@
594
880
 
595
881
  - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`af660e3`](https://github.com/ethlete-io/ethdk/commit/af660e346204d18ad39cc700c8698bb897fba339) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: the toolbar is now configurable. A new `tools` input takes an ordered list of tool tokens (`'bold' | 'italic' | 'strike' | 'heading' | 'bulletedList' | 'numberedList' | 'link' | 'divider'`), and `provideRichTextEditorTools(...)` sets the default for a scope. The block style is now picked from a `heading` menu (Normal / Heading 1–3) shown first in the toolbar, and toolbar buttons are larger and squarer.
596
882
 
597
- Form field: read-only text controls (`et-input`, `et-rich-text-editor`) now keep their normal box but drop all interactive affordances — no hover/focus border change, default cursor — so read-only reads as view-only content, distinct from disabled.
883
+ Form field: read-only text controls (`et-input`, `et-rich-text-editor`) now keep their normal box but drop all interactive affordances - no hover/focus border change, default cursor - so read-only reads as view-only content, distinct from disabled.
598
884
 
599
885
  Icon button: added an `--et-icon-button-border-radius` custom property so an ancestor context (e.g. a toolbar) can square off the otherwise fully-round button.
600
886
 
@@ -602,22 +888,22 @@
602
888
 
603
889
  ### Patch Changes
604
890
 
605
- - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`1d7aaca`](https://github.com/ethlete-io/ethdk/commit/1d7aacaec10f3d3d7278733ebf5d834e8a89b1f7) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `injectAnimatedBlockSize` — a core util that smoothly animates an element's `block-size` as its
891
+ - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`1d7aaca`](https://github.com/ethlete-io/ethdk/commit/1d7aacaec10f3d3d7278733ebf5d834e8a89b1f7) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `injectAnimatedBlockSize` - a core util that smoothly animates an element's `block-size` as its
606
892
  content resizes (baseline captured on first render so the initial layout never plays as a
607
893
  grow-from-0, interruption-safe, respects `prefers-reduced-motion`). `et-menu` and the rich text
608
894
  editor's trigger popup now share it, giving a more consistent, smoother resize.
609
895
 
610
- - [`c829986`](https://github.com/ethlete-io/ethdk/commit/c82998628a487effe34d2061811f3cee0fa4f7bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Form field: the disabled treatment (dimmed frame, blocked pointer events, hint color) is now driven by the registered control's disabled state via a `data-disabled` host attribute instead of `:has(:disabled)` — a composite control like the rich text editor can disable individual toolbar buttons without the whole field being dimmed and made unclickable.
896
+ - [`c829986`](https://github.com/ethlete-io/ethdk/commit/c82998628a487effe34d2061811f3cee0fa4f7bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Form field: the disabled treatment (dimmed frame, blocked pointer events, hint color) is now driven by the registered control's disabled state via a `data-disabled` host attribute instead of `:has(:disabled)` - a composite control like the rich text editor can disable individual toolbar buttons without the whole field being dimmed and made unclickable.
611
897
 
612
- - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`7e4c883`](https://github.com/ethlete-io/ethdk/commit/7e4c8832493b8c8b505efd80acfa147d90bc9523) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form field: only a `filled` field raises the surface elevation for its contents — a `transparent` field now stays flush with its parent surface instead of bumping elevation without a painted background.
898
+ - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`7e4c883`](https://github.com/ethlete-io/ethdk/commit/7e4c8832493b8c8b505efd80acfa147d90bc9523) Thanks [@github-actions](https://github.com/apps/github-actions)! - Form field: only a `filled` field raises the surface elevation for its contents - a `transparent` field now stays flush with its parent surface instead of bumping elevation without a painted background.
613
899
 
614
900
  Rich text editor: the autocomplete popup no longer renders one elevation too high (it now matches menus), and its "source failed" error state is a centered icon-and-message panel instead of a stray line in an empty box.
615
901
 
616
- Rich text editor: token chips (merge fields, mentions) now render as a tonal accent pill with a hairline ring — and keep their trigger char (`@`, `#`, …) visible as a de-emphasized prefix — so they read clearly as distinct entities in the prose, instead of a faint neutral highlight.
902
+ Rich text editor: token chips (merge fields, mentions) now render as a tonal accent pill with a hairline ring - and keep their trigger char (`@`, `#`, …) visible as a de-emphasized prefix - so they read clearly as distinct entities in the prose, instead of a faint neutral highlight.
617
903
 
618
- Rich text editor: the selection formatting toolbar now mounts through the overlay system (like the autocomplete popup) instead of a manually-positioned fixed element — so it shares the same anchoring, stacking, theming, and enter/leave animation.
904
+ Rich text editor: the selection formatting toolbar now mounts through the overlay system (like the autocomplete popup) instead of a manually-positioned fixed element - so it shares the same anchoring, stacking, theming, and enter/leave animation.
619
905
 
620
- - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`d362747`](https://github.com/ethlete-io/ethdk/commit/d3627470bddd16a6b76577ac8d3dc43d9d7fdd2e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: the anchored arrow now matches the pane it points at — it paints the
906
+ - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`d362747`](https://github.com/ethlete-io/ethdk/commit/d3627470bddd16a6b76577ac8d3dc43d9d7fdd2e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Overlay: the anchored arrow now matches the pane it points at - it paints the
621
907
  pane's actual background and mirrors its border (including no border when the
622
908
  pane has none), instead of re-deriving a color from surface tokens that could
623
909
  diverge from a custom `panelClass` or themed pane.
@@ -626,7 +912,7 @@
626
912
 
627
913
  - [`c829986`](https://github.com/ethlete-io/ethdk/commit/c82998628a487effe34d2061811f3cee0fa4f7bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Rich text editor: the alignment tool now applies to the whole table column (GFM alignment is per column, so a single aligned cell would not survive serialization) and disables itself inside lists, where alignment has no serialized form. Lists swept up by a cross-block selection are skipped instead of receiving a lost `text-align`.
628
914
 
629
- - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`bf72655`](https://github.com/ethlete-io/ethdk/commit/bf7265505ecaf77f2bc239fd945f763655af5b82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: toggling an inline format (bold, italic, underline, strike, code) with **no selection** now works as expected — it sets a pending "stored mark" so the next typed text picks up (or drops) that formatting, instead of doing nothing. The pending state shows in the toolbar and is cleared when you move the caret.
915
+ - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`bf72655`](https://github.com/ethlete-io/ethdk/commit/bf7265505ecaf77f2bc239fd945f763655af5b82) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: toggling an inline format (bold, italic, underline, strike, code) with **no selection** now works as expected - it sets a pending "stored mark" so the next typed text picks up (or drops) that formatting, instead of doing nothing. The pending state shows in the toolbar and is cleared when you move the caret.
630
916
 
631
917
  - [`c829986`](https://github.com/ethlete-io/ethdk/commit/c82998628a487effe34d2061811f3cee0fa4f7bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Rich text editor: block alignment is no longer lost when re-tagging between paragraph and heading, and the heading menu now disables itself inside list items (where a heading has no serialized form), matching the table-cell behavior.
632
918
 
@@ -634,7 +920,7 @@
634
920
 
635
921
  - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`c68d2b2`](https://github.com/ethlete-io/ethdk/commit/c68d2b2e2e64316bb67bf58ec16d3aad9bd84f34) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: pressing ArrowRight at the end of an inline code span (or ArrowLeft at its start) now steps the caret outside the code, so continuing to type isn't code.
636
922
 
637
- - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`c68d2b2`](https://github.com/ethlete-io/ethdk/commit/c68d2b2e2e64316bb67bf58ec16d3aad9bd84f34) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: table editing polish — arrow keys now step the caret cleanly across table edges (into the nearest cell when entering, onto a real line when exiting, adding one only when the table is flush against the editor's top/bottom) instead of stranding it at the table border; an empty line directly above a table can be removed with Backspace; and applying an inline format across multiple selected cells now wraps each cell's content within its own cell instead of tearing the table apart.
923
+ - [#3019](https://github.com/ethlete-io/ethdk/pull/3019) [`c68d2b2`](https://github.com/ethlete-io/ethdk/commit/c68d2b2e2e64316bb67bf58ec16d3aad9bd84f34) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rich text editor: table editing polish - arrow keys now step the caret cleanly across table edges (into the nearest cell when entering, onto a real line when exiting, adding one only when the table is flush against the editor's top/bottom) instead of stranding it at the table border; an empty line directly above a table can be removed with Backspace; and applying an inline format across multiple selected cells now wraps each cell's content within its own cell instead of tearing the table apart.
638
924
 
639
925
  ## 1.0.0-next.20
640
926
 
@@ -652,7 +938,7 @@
652
938
  - [#3018](https://github.com/ethlete-io/ethdk/pull/3018) [`e8f9bcd`](https://github.com/ethlete-io/ethdk/commit/e8f9bcd65b40724b266aff8949951649afafea36) Thanks [@github-actions](https://github.com/apps/github-actions)! - Move all component styles into the `components` CSS cascade layer (`@layer components`).
653
939
 
654
940
  Component CSS was previously injected unlayered, which meant it beat Tailwind
655
- utility classes (in `@layer utilities`) regardless of specificity — forcing
941
+ utility classes (in `@layer utilities`) regardless of specificity - forcing
656
942
  consumers to reach for `!important` (e.g. `flex!`) to override layout, spacing or
657
943
  sizing on components. Because layer precedence is resolved before specificity,
658
944
  `:where()` could not fix this.
@@ -682,7 +968,7 @@
682
968
  - Overlay configs now merge additively across definition → opener → per-open layers: `bindings`, `providers`, `hostClass`, `backdropClass` and `panelClass` are concatenated instead of the most specific layer silently replacing the rest; scalar options still follow most-specific-wins. The merge is exposed as `mergeOverlayConfigs(...configs)`.
683
969
  - Inside the overlay component, access the typed ref via `definition.injectRef()` (replaces the handler's `injectOverlayRef`). It throws an actionable `RuntimeError` when called outside an open overlay.
684
970
  - `defineQueryParamOverlay` requires the component to expose an `overlayQueryParam` model at compile time (previously a silent runtime requirement), and the opener's `open(value)` is typed from that model's value type. Definition- and opener-level `bindings`/`providers` are now applied on every URL-driven open, so components with additional inputs work with query-param overlays.
685
- - `OverlayHandlerLinkDirective` (`etOverlayHandlerLink` + `etOverlayHandlerQueryParamName`) is replaced by `QueryParamOverlayLinkDirective`: `<a [etQueryParamOverlayLink]="definition" etQueryParamOverlayLinkValue="42">` — the link takes the definition object, so the query param key is no longer duplicated as a string.
971
+ - `OverlayHandlerLinkDirective` (`etOverlayHandlerLink` + `etOverlayHandlerQueryParamName`) is replaced by `QueryParamOverlayLinkDirective`: `<a [etQueryParamOverlayLink]="definition" etQueryParamOverlayLinkValue="42">` - the link takes the definition object, so the query param key is no longer duplicated as a string.
686
972
 
687
973
  Migration:
688
974
 
@@ -710,15 +996,15 @@
710
996
 
711
997
  - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`2f18e43`](https://github.com/ethlete-io/ethdk/commit/2f18e4344759dbbcd17ba0dbeca138f1f7043cdf) Thanks [@github-actions](https://github.com/apps/github-actions)! - Anchored overlays: the `shift` option now also accepts `{ crossAxis?: boolean }` in addition to a boolean. With `crossAxis: true`, an overlay that fits on neither side of its reference is shifted along the placement's cross axis to stay inside the viewport (it may then overlap the reference) instead of overflowing off-screen.
712
998
 
713
- Menus enable this by default: a nested submenu near the viewport edge first flips to the other side and, when neither side fits, slides over its parent menu — matching native OS menu behavior — instead of being cut off by the viewport.
999
+ Menus enable this by default: a nested submenu near the viewport edge first flips to the other side and, when neither side fits, slides over its parent menu - matching native OS menu behavior - instead of being cut off by the viewport.
714
1000
 
715
1001
  The `size` middleware (`autoResize`) now runs after `shift` instead of before it, so `--et-overlay-max-width` / `--et-overlay-max-height` are measured from the pane's shifted position. Previously a cross-axis-shifted pane had its max size capped to the unshifted leftover space, squeezing e.g. a submenu to a sliver instead of letting it keep its width while overlapping its parent.
716
1002
 
717
1003
  - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`789d765`](https://github.com/ethlete-io/ethdk/commit/789d765e1342f92d1269f1d8a1dbb64e28415708) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: new `et-dropzone` file-upload control with a built-in `@ethlete/query` upload workflow. Import `DROPZONE_IMPORTS`.
718
- - Files are picked via click or drag & drop and uploaded through a consumer-provided query, one query per file. Configure with `createDropzoneUpload({ queryCreator, selectValue, createArgs?, resolveExisting? })` — `selectValue` maps the upload response to the form control value (e.g. `(media) => media.uuid`).
719
- - Signal-forms native (`[formField]`): the control value holds the values of successful uploads (and existing entries) in entry order — `TValue | null` in single mode, `TValue[]` with `multiple`. In-flight and failed uploads never enter the value; block submits via the headless `anyUploading` signal.
1004
+ - Files are picked via click or drag & drop and uploaded through a consumer-provided query, one query per file. Configure with `createDropzoneUpload({ queryCreator, selectValue, createArgs?, resolveExisting? })` - `selectValue` maps the upload response to the form control value (e.g. `(media) => media.uuid`).
1005
+ - Signal-forms native (`[formField]`): the control value holds the values of successful uploads (and existing entries) in entry order - `TValue | null` in single mode, `TValue[]` with `multiple`. In-flight and failed uploads never enter the value; block submits via the headless `anyUploading` signal.
720
1006
  - Built-in UI: per-file progress bars (requires `reportProgress: true` on the query creator and the XHR `HttpClient` backend; degrades to indeterminate otherwise), image previews via object URLs, remove/replace/retry via regular icon buttons, and enter/leave animations (FLIP shift plus scale-out on delete, disabled under `prefers-reduced-motion`). In single mode a successful upload replaces the drop area with a same-size preview (no layout shift).
721
- - Validation lives in the form schema: `required()`/`minLength()`/`maxLength()` cover emptiness and file count, and the new `dropzoneFiles()` schema rule declares file constraints (`accept`, `maxFileSize`, `minFileSize`). Violating files never upload — each violation becomes a regular validation error on the field (customizable via the rule's `message` function) and is emitted via `filesRejected`. Upload failures render as validation-style messages below the field (`uploadErrorMessage` input).
1007
+ - Validation lives in the form schema: `required()`/`minLength()`/`maxLength()` cover emptiness and file count, and the new `dropzoneFiles()` schema rule declares file constraints (`accept`, `maxFileSize`, `minFileSize`). Violating files never upload - each violation becomes a regular validation error on the field (customizable via the rule's `message` function) and is emitted via `filesRejected`. Upload failures render as validation-style messages below the field (`uploadErrorMessage` input).
722
1008
  - Edit forms: values already present in the control render as entries via the `resolveExisting` display resolver.
723
1009
  - Full behavior is available headlessly via the `etDropzone` directive (`entries()`, `lastRejections()`, `selectFiles()`, `removeEntry()`, `retryEntry()`, `clear()`, `isDragOver`, …). Error codes `ET2400`–`ET2499`.
724
1010
 
@@ -728,10 +1014,10 @@
728
1014
 
729
1015
  - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`300afe3`](https://github.com/ethlete-io/ethdk/commit/300afe3f9115f2ff18ca097975a8101690613d24) Thanks [@github-actions](https://github.com/apps/github-actions)! - Grid & Tabs: the previously allocated error codes are now actually enforced, and a nav-tabs composition bug is fixed.
730
1016
  - Tabs (dev mode): `ET2000` when a tab trigger has no enclosing tab bar, `ET2001` when `<et-tab>` / `etTabPanel` sit outside a tab group (an orphan `<et-tab>` used to disappear silently), `ET2002` when a headless tab group has triggers but no panels, `ET2003` when nav-tab pieces are used without `et-nav-tabs`.
731
- - Grid (dev mode): `ET1900` for items outside a grid, `ET1901` for drag/resize handles outside a grid item, `ET1902` for duplicate item ids, `ET1903` when `restoreState()` receives unknown breakpoint names, and the new `GRID_ERROR_CODES.UNKNOWN_ITEM_TYPE` (`ET1904`) when an item's `type` has no registration — previously such items were silently dropped.
1017
+ - Grid (dev mode): `ET1900` for items outside a grid, `ET1901` for drag/resize handles outside a grid item, `ET1902` for duplicate item ids, `ET1903` when `restoreState()` receives unknown breakpoint names, and the new `GRID_ERROR_CODES.UNKNOWN_ITEM_TYPE` (`ET1904`) when an item's `type` has no registration - previously such items were silently dropped.
732
1018
  - Fixed: `<et-nav-tabs-outlet>` placed as a sibling of `<et-nav-tabs>` (the documented composition) crashed with a DI error. It now resolves the tab bar that labels it automatically when exactly one `et-nav-tabs` exists on the page, and still prefers an ancestor tab bar when nested.
733
1019
 
734
- - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`1d324c2`](https://github.com/ethlete-io/ethdk/commit/1d324c2cbdd749cd8b01d52548a5a457a7e462df) Thanks [@github-actions](https://github.com/apps/github-actions)! - Menu: trigger-anchored root menus now render a floating arrow pointing at their trigger, matching the tooltip and toggletip look. The new `arrow` input on `[etMenu]` (default `true`) controls it — set `[arrow]="false"` to opt out — and `arrowPadding` (default `8`) tunes how close the arrow may get to the panel corners. Submenus and context menus (point-anchored) never render an arrow.
1020
+ - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`1d324c2`](https://github.com/ethlete-io/ethdk/commit/1d324c2cbdd749cd8b01d52548a5a457a7e462df) Thanks [@github-actions](https://github.com/apps/github-actions)! - Menu: trigger-anchored root menus now render a floating arrow pointing at their trigger, matching the tooltip and toggletip look. The new `arrow` input on `[etMenu]` (default `true`) controls it - set `[arrow]="false"` to opt out - and `arrowPadding` (default `8`) tunes how close the arrow may get to the panel corners. Submenus and context menus (point-anchored) never render an arrow.
735
1021
  - With the arrow enabled, the `'auto'` offset resolves to `10` so the arrow has room between the panel and its trigger; disabling the arrow restores the previous tight spacing. Submenu and context menu spacing is unchanged.
736
1022
  - The arrow picks up the menu surface theme (`--et-surface-background-solid` / `--et-surface-border-solid`) and can be overridden via `--et-overlay-arrow-background` and `--et-overlay-arrow-border`.
737
1023
 
@@ -739,29 +1025,29 @@
739
1025
  - Borders, separators, muted text (group labels, shortcuts, the search placeholder/spinner) and the search input fill now derive from the surface tokens (`--et-surface-border-solid`, `--et-surface-color-muted-solid`, `--et-surface-interaction-solid`).
740
1026
  - The active menu item highlight is now a `color-mix` tint of `--et-surface-interaction-solid` instead of a fixed white overlay.
741
1027
  - The menu panel resolves its surface via `AutoSurfaceDirective`, automatically picking the next elevation relative to the trigger's surface context.
742
- - Destructive menu items and the search error message now use the app's registered `error` color theme (via `injectErrorTheme()`), so `--et-theme-color-primary-*` resolves to the error palette inside them. The `--et-menu-item-destructive-color` token has been removed — theme the error color theme instead. Like `et-form-field`, `et-menu` now requires color themes (including one with `type: 'error'`) to be registered.
1028
+ - Destructive menu items and the search error message now use the app's registered `error` color theme (via `injectErrorTheme()`), so `--et-theme-color-primary-*` resolves to the error palette inside them. The `--et-menu-item-destructive-color` token has been removed - theme the error color theme instead. Like `et-form-field`, `et-menu` now requires color themes (including one with `type: 'error'`) to be registered.
743
1029
  - Selection item check/radio marks and the search input focus border now use `--et-theme-color-primary-solid` from the surrounding color theme context.
744
- - The active-item highlight now only shows for an actual hover or `:focus-visible` (keyboard) interaction — opening a menu with the mouse no longer highlights the first item, while keyboard-opened menus still do. A trigger item whose submenu is open stays highlighted via `[data-menu-open]`.
745
- - The menu animates its block size (160ms) when its content changes while open — e.g. search filtering items away or the search error line appearing — instead of snapping to the new size. Respects `prefers-reduced-motion`.
746
- - Menu items now have a pressed (`:active`) state — a stronger tint of the surface interaction color (20% vs the 12% highlight) — and transition `background`, `color` and `opacity` (120ms) between their rest, highlighted, pressed and disabled states. The search input transitions its `border-color` and `background`, matching the button's interaction feel.
1030
+ - The active-item highlight now only shows for an actual hover or `:focus-visible` (keyboard) interaction - opening a menu with the mouse no longer highlights the first item, while keyboard-opened menus still do. A trigger item whose submenu is open stays highlighted via `[data-menu-open]`.
1031
+ - The menu animates its block size (160ms) when its content changes while open - e.g. search filtering items away or the search error line appearing - instead of snapping to the new size. Respects `prefers-reduced-motion`.
1032
+ - Menu items now have a pressed (`:active`) state - a stronger tint of the surface interaction color (20% vs the 12% highlight) - and transition `background`, `color` and `opacity` (120ms) between their rest, highlighted, pressed and disabled states. The search input transitions its `border-color` and `background`, matching the button's interaction feel.
747
1033
 
748
1034
  - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`8d5c7dc`](https://github.com/ethlete-io/ethdk/commit/8d5c7dce47c0b04592ebe366354871f177d55f0a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Forms: visual refresh and new options for the selection controls (checkbox group, radio group, segmented button group, switch, choice field).
749
1035
  - Checkbox options and radios: option labels now render in the regular text color at a fixed size, boxes/circles gained hover tint fills, press feedback and a draw-in checkmark animation; the group label is styled like a form-field label (new `--et-<group>-group-label-font-size` tokens).
750
- - Selection-list groups (`et-checkbox-group`, `et-radio-group`, `et-segmented-button-group`) now support a projected `<et-label>` as group label — it shows the required marker (`*`) and wires `aria-labelledby` automatically. The plain `.et-<group>-label` span still works for label text without the marker.
1036
+ - Selection-list groups (`et-checkbox-group`, `et-radio-group`, `et-segmented-button-group`) now support a projected `<et-label>` as group label - it shows the required marker (`*`) and wires `aria-labelledby` automatically. The plain `.et-<group>-label` span still works for label text without the marker.
751
1037
  - Segmented button group: redesigned as a tonal track with a filled active pill that animates between options (flip animation). `--et-segmented-button-border-width` was removed; new tokens `--et-segmented-button-border-radius`, `--et-segmented-button-group-track-padding`, `--et-segmented-button-group-track-radius` and `--et-segmented-button-group-label-font-size`.
752
- - Switch: reworked visuals — the off state uses a neutral tinted track with a smaller muted thumb that grows and slides on toggle, plus a press-stretch effect. Default dimensions changed to a 40×22px track with a 16px thumb.
1038
+ - Switch: reworked visuals - the off state uses a neutral tinted track with a smaller muted thumb that grows and slides on toggle, plus a press-stretch effect. Default dimensions changed to a 40×22px track with a 16px thumb.
753
1039
  - New `size` input (`'sm' | 'md' | 'lg'`, default `'md'`) on `et-checkbox-group`, `et-radio-group`, `et-segmented-button-group` and `et-choice-field`, scaling controls, labels and gaps in line with `et-form-field` sizes.
754
1040
  - Group error states now tint the unchecked control borders with the error color (previously only the error message was colored).
755
1041
  - The control CSS tokens (`--et-checkbox-*`, `--et-checkbox-option-*`, `--et-radio-*`, `--et-segmented-button-*`, `--et-switch-*`) are now registered as inheriting custom properties, so overriding them on the component or a wrapper actually reaches the inner elements that consume them.
756
1042
 
757
- - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`6e9693a`](https://github.com/ethlete-io/ethdk/commit/6e9693a9352d19775f46ab5424cbdea455a14ee5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Button: new split button. `<et-split-button>` groups an action segment (`etSplitButtonAction`) and a trigger segment (`etSplitButtonTrigger`) — both regular surface/icon buttons — into one `role="group"` control with joined corners and a divider between the segments.
1043
+ - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`6e9693a`](https://github.com/ethlete-io/ethdk/commit/6e9693a9352d19775f46ab5424cbdea455a14ee5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Button: new split button. `<et-split-button>` groups an action segment (`etSplitButtonAction`) and a trigger segment (`etSplitButtonTrigger`) - both regular surface/icon buttons - into one `role="group"` control with joined corners and a divider between the segments.
758
1044
  - The segments keep the full button API (variant, size, color, disabled, loading); the trigger typically also carries `etMenuTrigger` to open a menu with related actions.
759
1045
  - The divider color is themeable via `--et-split-button-divider-color` (defaults to `currentColor` at 32%).
760
1046
  - The headless `SplitButtonDirective` (`[etSplitButton]`) plus the segment directives are exported for custom-styled split buttons.
761
1047
  - Missing or misplaced segments throw dev-mode errors in the new `ET23xx` range.
762
1048
 
763
1049
  - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`300afe3`](https://github.com/ethlete-io/ethdk/commit/300afe3f9115f2ff18ca097975a8101690613d24) Thanks [@github-actions](https://github.com/apps/github-actions)! - Stream: theming overhaul and cleanups.
764
- - The PiP chrome now provides a surface theme scope (`type: 'dark'`, elevation 1) — it is mounted into `document.body` and previously had no theme context at all.
1050
+ - The PiP chrome now provides a surface theme scope (`type: 'dark'`, elevation 1) - it is mounted into `document.body` and previously had no theme context at all.
765
1051
  - The PiP window glass background derives from the surface theme (`60%` of `--et-surface-background-solid`) instead of hardcoded `rgba(0, 0, 0, 0.6)`; `--et-pip-bg` remains as an override hook but is no longer a registered `@property`.
766
1052
  - The featured-cell ring in PiP grid mode uses `--et-theme-color-primary-solid` instead of hardcoded `#3b82f6`; `--et-stream-pip-chrome-featured-ring-color` remains as an override hook (no longer a registered `@property`). The hover ring and resize handles now derive from surface tokens too.
767
1053
  - Scrollable: `ScrollableErrorCode` is removed in favor of `SCROLLABLE_ERROR_CODES`, matching every other domain's naming.
@@ -783,7 +1069,7 @@
783
1069
  same fix is applied to the window control button icon.
784
1070
 
785
1071
  - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`7110a06`](https://github.com/ethlete-io/ethdk/commit/7110a068208586f5906da1fc387c5181b2d1ec1a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Menu: the floating arrow no longer affects or overlaps the panel content.
786
- - The overlay arrow is now clipped at the panel edge (it only keeps the outer tip plus the border seam), so the menu no longer adds extra clearance padding on the arrow side — padding is identical regardless of placement.
1072
+ - The overlay arrow is now clipped at the panel edge (it only keeps the outer tip plus the border seam), so the menu no longer adds extra clearance padding on the arrow side - padding is identical regardless of placement.
787
1073
  - `arrowPadding` on `[etMenu]` now defaults to `14` (was `8`) so the arrow can no longer slide into the panel's rounded corners.
788
1074
 
789
1075
  - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`90eeba1`](https://github.com/ethlete-io/ethdk/commit/90eeba1e6dbac11cfaef7cd4c2f0a5fa6234d642) Thanks [@github-actions](https://github.com/apps/github-actions)! - Menu: the anchor arrow no longer overlaps the panel's edge content. The rotated
@@ -797,7 +1083,7 @@
797
1083
  - The iframes created by the Kick, SOOP, Dailymotion and TikTok players now carry a descriptive `title` (`"<Platform> player"`). YouTube, Vimeo, Twitch and Facebook iframes are created by the platform SDKs and cannot be titled from the library.
798
1084
  - The loading overlay is now a `role="status"` region labelled "Loading", the error overlay announces itself via `role="alert"`, and the consent gate is a `role="group"` labelled by its heading.
799
1085
 
800
- - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`1d324c2`](https://github.com/ethlete-io/ethdk/commit/1d324c2cbdd749cd8b01d52548a5a457a7e462df) Thanks [@github-actions](https://github.com/apps/github-actions)! - Text button: the underline is no longer shown in the resting state — it now animates in on hover, focus and press, and sits tight under the label (link-style) instead of hanging below the button's line box. Resting text buttons now align optically with neighboring buttons of the same size.
1086
+ - [#3016](https://github.com/ethlete-io/ethdk/pull/3016) [`1d324c2`](https://github.com/ethlete-io/ethdk/commit/1d324c2cbdd749cd8b01d52548a5a457a7e462df) Thanks [@github-actions](https://github.com/apps/github-actions)! - Text button: the underline is no longer shown in the resting state - it now animates in on hover, focus and press, and sits tight under the label (link-style) instead of hanging below the button's line box. Resting text buttons now align optically with neighboring buttons of the same size.
801
1087
 
802
1088
  ## 1.0.0-next.17
803
1089
 
@@ -812,10 +1098,10 @@
812
1098
 
813
1099
  - [`11ce5e1`](https://github.com/ethlete-io/ethdk/commit/11ce5e1795249a6b975dab2eab7e8e2a9c9bc979) Thanks [@TomTomB](https://github.com/TomTomB)! - Fix icon directive typing and improve the icon generator config.
814
1100
  - `IconDirective` now explicitly annotates its inputs as `InputSignal<RegisteredIconName>` and `InputSignal<RegisteredIconVariant | undefined>`. Without the annotation the d.ts bundler inlined the registry aliases to `string`, so consumer-side `declare module` augmentation of `EthleteIconNameRegistry` / `EthleteIconVariantRegistry` had no effect. `etIcon`/`variant` are now actually narrowed to the registered names.
815
- - The `@ethlete/components:icons` generator config takes a top-level `variants` list (replacing the singular `defaultVariant`). Bare string entries — and object entries without their own `variant`/`variants` — inherit it, so a set of icons that all share a style no longer needs the variant repeated on every entry.
1101
+ - The `@ethlete/components:icons` generator config takes a top-level `variants` list (replacing the singular `defaultVariant`). Bare string entries - and object entries without their own `variant`/`variants` - inherit it, so a set of icons that all share a style no longer needs the variant repeated on every entry.
816
1102
  - The generator's `source: "auto"` sentinel is now honored when set in the config file (previously only the CLI default auto-detected; a config `"auto"` was treated as a package literally named "auto").
817
1103
 
818
- - [`11ce5e1`](https://github.com/ethlete-io/ethdk/commit/11ce5e1795249a6b975dab2eab7e8e2a9c9bc979) Thanks [@TomTomB](https://github.com/TomTomB)! - Overlay routing: a shell that wraps only the router outlet (each route carries its own `et-overlay-main` with header/body/footer) now reliably bounds the outlet to the pane. The shell content grid pins both axes (`grid-template-columns`/`grid-template-rows: minmax(0, 1fr)`), so the outlet fills a fixed-height dialog and the routed page's body scrolls with its header and footer pinned — instead of the whole overlay scrolling. The `minmax(0, ...)` column also stops a wide child (e.g. a rich-text editor) from blowing the grid past the pane width.
1104
+ - [`11ce5e1`](https://github.com/ethlete-io/ethdk/commit/11ce5e1795249a6b975dab2eab7e8e2a9c9bc979) Thanks [@TomTomB](https://github.com/TomTomB)! - Overlay routing: a shell that wraps only the router outlet (each route carries its own `et-overlay-main` with header/body/footer) now reliably bounds the outlet to the pane. The shell content grid pins both axes (`grid-template-columns`/`grid-template-rows: minmax(0, 1fr)`), so the outlet fills a fixed-height dialog and the routed page's body scrolls with its header and footer pinned - instead of the whole overlay scrolling. The `minmax(0, ...)` column also stops a wide child (e.g. a rich-text editor) from blowing the grid past the pane width.
819
1105
 
820
1106
  ## 0.1.0-next.16
821
1107
 
@@ -841,7 +1127,7 @@
841
1127
 
842
1128
  - [`efe9cc3`](https://github.com/ethlete-io/ethdk/commit/efe9cc30b61245fd3c7fd1eaeedc3be7b85ed275) Thanks [@TomTomB](https://github.com/TomTomB)! - Grid: prevent text selection inside a grid item when dragging it in
843
1129
  non-readonly mode. `user-select` is now disabled on the item content whenever the
844
- grid is editable, instead of only after a drag has committed — so the initial
1130
+ grid is editable, instead of only after a drag has committed - so the initial
845
1131
  pointer movement before the drag threshold no longer selects the item's text.
846
1132
 
847
1133
  - [`70308a7`](https://github.com/ethlete-io/ethdk/commit/70308a7e0ce81d97c91d55fb7f619f1384a0e3bc) Thanks [@TomTomB](https://github.com/TomTomB)! - Overlay routing: support routes that nest their own `et-overlay-header`/`et-overlay-body`/`et-overlay-footer` (a full `et-overlay-main`) directly inside the router outlet, without a shared shell or sidebar. Previously the active route grew past the overlay, pushing the footer off-screen and preventing the body from scrolling.
@@ -884,13 +1170,13 @@
884
1170
 
885
1171
  ### Minor Changes
886
1172
 
887
- - [`b323ef6`](https://github.com/ethlete-io/ethdk/commit/b323ef66130d196e5c893e844d50ecfc85487373) Thanks [@TomTomB](https://github.com/TomTomB)! - Grid: replace the built-in `✕` remove button and its `showDefaultRemoveAction` config option with `GridItemDefaultActionsComponent` (`et-grid-item-default-actions`) — a toolbar with an icon remove button that is now rendered by default. It is used automatically when the grid config leaves `actionsComponent` unset; set `actionsComponent` to your own component to replace it, or to `null` to render no actions. Its aria label is configurable via the new `removeActionAriaLabel` grid config option (defaults to `'Remove item'`, run through `transformer`).
1173
+ - [`b323ef6`](https://github.com/ethlete-io/ethdk/commit/b323ef66130d196e5c893e844d50ecfc85487373) Thanks [@TomTomB](https://github.com/TomTomB)! - Grid: replace the built-in `✕` remove button and its `showDefaultRemoveAction` config option with `GridItemDefaultActionsComponent` (`et-grid-item-default-actions`) - a toolbar with an icon remove button that is now rendered by default. It is used automatically when the grid config leaves `actionsComponent` unset; set `actionsComponent` to your own component to replace it, or to `null` to render no actions. Its aria label is configurable via the new `removeActionAriaLabel` grid config option (defaults to `'Remove item'`, run through `transformer`).
888
1174
 
889
- Also removes the now-redundant drag-handle slot: the `dragHandleComponent` config option, the `dragHandleAriaLabel` config option, and the `etGridItemDragHandle` projection slot are gone. With whole-item drag the item content is the drag surface, so a dedicated handle is no longer needed — project a decorative grip into the item content instead.
1175
+ Also removes the now-redundant drag-handle slot: the `dragHandleComponent` config option, the `dragHandleAriaLabel` config option, and the `etGridItemDragHandle` projection slot are gone. With whole-item drag the item content is the drag surface, so a dedicated handle is no longer needed - project a decorative grip into the item content instead.
890
1176
 
891
1177
  - [`b323ef6`](https://github.com/ethlete-io/ethdk/commit/b323ef66130d196e5c893e844d50ecfc85487373) Thanks [@TomTomB](https://github.com/TomTomB)! - Grid: add `GridItemToolbarComponent` (`et-grid-item-toolbar`), a themeable container for per-item controls (edit, remove, …). Drop it into an item's action slot and project action buttons (e.g. `IconButtonComponent`) into it. It stops pointerdown so the toolbar is never a drag surface even when the whole item is draggable, and is themeable via the `--et-grid-item-toolbar-background` / `-gap` / `-padding` / `-radius` custom properties. Exported from the grid entrypoint and included in `GridImports`.
892
1178
 
893
- - [`b323ef6`](https://github.com/ethlete-io/ethdk/commit/b323ef66130d196e5c893e844d50ecfc85487373) Thanks [@TomTomB](https://github.com/TomTomB)! - Grid: in edit mode the whole item is now a drag surface — a pointerdown anywhere on the item content starts a drag, instead of only the drag handle slot. Interactive overlays (the actions slot, resize handles, or anything that stops propagation such as `GridItemToolbarComponent`) still win, and read-only grids keep their content inert. Also fixes the `et-grid--readonly` class never being applied to the grid host, so the intended read-only styles (non-interactive drag handle, hidden resize handles) now take effect, and adds a grab/grabbing cursor on the content while editing.
1179
+ - [`b323ef6`](https://github.com/ethlete-io/ethdk/commit/b323ef66130d196e5c893e844d50ecfc85487373) Thanks [@TomTomB](https://github.com/TomTomB)! - Grid: in edit mode the whole item is now a drag surface - a pointerdown anywhere on the item content starts a drag, instead of only the drag handle slot. Interactive overlays (the actions slot, resize handles, or anything that stops propagation such as `GridItemToolbarComponent`) still win, and read-only grids keep their content inert. Also fixes the `et-grid--readonly` class never being applied to the grid host, so the intended read-only styles (non-interactive drag handle, hidden resize handles) now take effect, and adds a grab/grabbing cursor on the content while editing.
894
1180
 
895
1181
  ## 0.1.0-next.12
896
1182