@jungherz-de/glasskit-elements 1.19.0 → 1.19.2

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 ADDED
@@ -0,0 +1,738 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ---
9
+
10
+ ## [1.19.2] – 2026-09-26
11
+
12
+ ### Fixed
13
+
14
+ - **`<glk-date-strip>` and `<glk-calendar>` name days in the page's language, not the browser's.** Without `locale` they went straight to `navigator.language`, so a German page opened on a phone set to English showed "SUN MON TUE" in the strip and started the calendar on Sunday — next to German text everywhere else. They now take the `lang` of the nearest ancestor, usually `<html lang>`, looked up across shadow roots through their hosts, so an element inside another component's shadow tree — a hybrids view, say — reaches the page's language, and a `<section lang="en">` in a German page stays English. Only without any `lang` does the browser language follow, then English; an empty `lang=""` means "unknown" in HTML and falls through to the browser. `locale` still wins over all of it. The page language decides weekday and month names, the chips' and days' `aria-label`s and the calendar's first day of the week. Measured in Chromium and WebKit with an `en-US` browser on `<html lang="de">`: "So Mo Di" and "Sonntag, 27. September 2026" instead of "Sun Mon Tue" and "Sunday, September 27, 2026", the calendar starts on Monday; a page without `lang` looks as before. Compatibility: a page whose `lang` differs from its visitors' browsers now shows its own language in these two elements — set `locale` to keep another. NotionKit Elements falls back to `<html lang>` since 1.17; this looks at the nearest ancestor instead. (EhrenPfoten, Elements finding 10.)
15
+
16
+ ---
17
+
18
+ ## [1.19.1] – 2026-09-26
19
+
20
+ ### Fixed
21
+
22
+ - **The package carries `SKILL.md` and `CHANGELOG.md`.** `files` in package.json listed `dist/`, `src/` and `LICENSE` only, so no release up to 1.19.0 had them — an agent that reads `SKILL.md` from `node_modules`, or a developer looking up what changed, found nothing there and had to go to GitHub. The same gap NotionKit Elements closed in its 1.11.1; the question came up there.
23
+ - **Rebuilt against GlassKit 1.19.1**, whose `glasskit-styles.js` no longer embeds the `sourceMappingURL` comment of the minified sheet: all three bundles carried it inside their CSS text, where it pointed at a map that does not exist next to them. The peer dependency moves to `>=1.19.1`; no element changed.
24
+
25
+ ### Added
26
+
27
+ - **`npm run check:package`, in CI and before every publish.** The release workflow runs it before it publishes, so a package that misses a file it points to no longer goes out; it reads the output of npm 10 and npm 12 alike (npm 12, which the release workflow installs, prints an object keyed by package name instead of a list). It packs the package without publishing and fails when an entry point of package.json (`main`, `module`, every `exports` target and pattern), `README.md`, `LICENSE`, `CHANGELOG.md`, `SKILL.md` or a source map named by a shipped file is missing — run against 1.19.0 it reports exactly the two missing documents and the three embedded map comments.
28
+
29
+ ---
30
+
31
+ ## [1.19.0] – 2026-09-26
32
+
33
+ Versions realign with GlassKit at 1.19.0.
34
+
35
+ ### Added
36
+
37
+ - **`<glk-toast>` can offer something: a button and an ×.** It took `message`, `variant`, `duration` and `visible`; with `duration="0"` it stayed, but only code could close it, and there was no button — an offer like "A new version · Reload" had to live in a banner in the page. Now: `action-label` and `action-value`, or `show(message, { action: { label, value } })`, add GlassKit's `.glass-toast__action`, and with it an × (`.glass-toast__close`, named by `close-label`, "Close" by default); `dismissible` gives the × alone. A toast with an action stays until one of them is used, unless a `duration` is set, and it does not time out while the pointer or the focus is on it. The action emits `glk-action { action, label }` and closes the toast — unless a listener calls `preventDefault()`, or shows the next message from the handler ("Undo" → `show('Restored')`), both of which keep it up; the × and Escape emit `glk-close`; running out of time still emits `glk-dismiss`. `show()` keeps its old signature and gains an options form, `show(message, { variant, duration, action, dismissible })`: keys that are left out keep their attribute, except `action` — a message without one shows no button. The same shape as NotionKit Elements 1.19, with `glk-` names. (EhrenPfoten, Elements finding 9.)
38
+
39
+ - **An `icon` slot on `<glk-toast>`** replaces the built-in icon — an offer to reload wants a refresh icon, not the success check a toast without a variant shows. Leave the slotted icon's stroke unset and it takes the variant colour.
40
+
41
+ - **The toast is a live region.** `role="status"` and `aria-live="polite"` on the toast, so the message is announced; it was silent before. While hidden, its buttons are inert; closing it from the keyboard hands the focus back to where it came from.
42
+
43
+ - **`emit(name, detail, { cancelable: true })`** on `GlkElement` — the event can be cancelled with `preventDefault()`, and `emit()` returns `false` then. Without the option nothing changes.
44
+
45
+ ### Fixed
46
+
47
+ - **The toast's icon never took the variant colour.** The built-in icons carried `stroke="currentColor"`, which wins over the colour GlassKit sets on `.glass-toast__icon`, so success, error and warning toasts all showed a white icon — unlike the CSS toast. The icons now inherit their stroke: green, red, yellow.
48
+ - **Changing `variant` on a visible toast hid it.** The class list was rebuilt without `is-visible` while the `visible` attribute stayed.
49
+ - **A second `show()` while the toast was up did not restart its timer**, so the second message disappeared early — at 400 ms, a second `show(…, 600)` was gone 200 ms later. It now runs its full duration.
50
+ - Rebuilt against GlassKit 1.19.0; the peer dependency moves to `>=1.19.0`.
51
+
52
+ Verified in Chromium and WebKit: the old `show(message, variant, duration)` still hides after its duration and emits `glk-dismiss`; an offer is still up after 3.5 s; the action emits `glk-action { action: "reload" }` and closes; `preventDefault()` and a `show()` in the handler keep the toast up; × and Escape emit `glk-close`, and Escape hands the focus back; a toast with a 600 ms duration is still up after 900 ms under the pointer and hides 600 ms after the pointer leaves; hidden buttons refuse focus; on a 390 px phone the offer is 358 px wide with both buttons inside.
53
+
54
+ ---
55
+
56
+ ## [1.18.0] – 2026-09-23
57
+
58
+ Versions realign with GlassKit at 1.18.0.
59
+
60
+ ### Added
61
+
62
+ - **`<glk-badge variant="warning">`.** The element accepted `primary`, `success` and `error` and turned every other value into the neutral badge without a word, so `variant="warning"` — a state that waits for someone, like a booking still to be assigned — looked exactly like a cancelled one. It now maps to GlassKit 1.18.0's `.glass-badge--warning`, with its own tinted fill, border and text, and works with `interactive` and `selected`: a selected warning chip deepens its own yellow. A value outside the four still falls back to the neutral badge, as an unknown value of an enumerated attribute does. Rebuilt against GlassKit 1.18.0; the peer dependency moves to `>=1.18.0`. (EhrenPfoten, Elements finding 8.)
63
+
64
+ ---
65
+
66
+ ## [1.17.0] – 2026-09-22
67
+
68
+ Versions realign with GlassKit at 1.17.0.
69
+
70
+ ### Added
71
+
72
+ - **`<glk-segmented overflow="scroll" | "wrap">` for more options than fit.** Seven areas in `<glk-segmented full>` did not fit on a phone: the row ran past its edge and the last area could not be reached. `overflow="scroll"` keeps one row that scrolls sideways (GlassKit's `.glass-segmented--scroll`, scrollbar hidden) and keeps the chosen option in view — centred in the row after the first layout, on every value change and when the row's width changes, through the row's own scrolling, so the page never moves; a value change glides unless reduced motion is asked for, a change of size snaps. `overflow="wrap"` breaks the row into lines (`--wrap`). Without the attribute the row stays one line, as before. Deviation from the proposal, which had two booleans `scroll` and `wrap`: `scroll` is a method of every element, and a framework that sets a property whenever the element has one — hybrids 9 checks `name in element`, Vue and React 19 do the same — would overwrite the method instead of setting the attribute, so `scroll="${…}"` would silently do nothing; one enumerated `overflow` also rules out asking for both at once. Verified in Chromium and WebKit, LTR and RTL: with the seventh option chosen it is visible after load; picking the first scrolls back to the start; `.value = 'd'` centres the fourth to the pixel; the page's scroll position never changes; keyboard focus scrolls the focused option into view. (EhrenPfoten, Elements finding 7.)
73
+
74
+ ### Fixed
75
+
76
+ - **`<glk-input>` did not pass `min`, `max` and `step` to its field.** The element observed nine attributes, and `min`, `max`, `step`, `minlength`, `maxlength`, `pattern`, `autocomplete` and `inputmode` on the host never reached the inner `<input>` — a date field with `min` set to today still offered every past day in its picker. All eight are now handed down unchanged when present and removed when they go. The inner field's validity is still not reported to the surrounding form: like `required`, `pattern` and `min` constrain the field and its picker but do not block a submit. (EhrenPfoten, Elements finding 6.)
77
+
78
+ - **Rebuilt against GlassKit 1.17.0**, which the elements bundle: `<glk-input type="date">` (and `time`, `datetime-local`, `month`) keeps its column width on iOS — measured in the iOS 26.3 and 27.0 simulators at 402 px, the field sat 35 px past its column before and flush after, with the value at the start like every other field; several buttons in `<glk-empty>`'s `action` slot stand side by side with an 8 px gap instead of touching. The peer dependency moves to `>=1.17.0`.
79
+
80
+ ### Changed
81
+
82
+ - `<glk-date-strip>` and `<glk-segmented>` share one helper for centring the chosen item (`src/reveal.js`, a shared chunk of the per-component build). It scrolls by a relative distance, so the strip now also centres in right-to-left layouts, where the absolute `scrollLeft` it used before runs negative.
83
+
84
+ ---
85
+
86
+ ## [1.16.1] – 2026-09-22
87
+
88
+ ### Fixed
89
+
90
+ - **`title` on the elements that take a heading showed as a browser tooltip.** `<glk-sheet>`, `<glk-modal>`, `<glk-list-item>`, `<glk-accordion-item>` and `<glk-empty>` take their heading as `title` — which is also the global HTML attribute, so hovering a sheet floated its heading over the form, and a list showed a tooltip on every row. The elements now read the attribute and take it off the host (`GlkElement.takeTitle()`): a later `setAttribute('title', …)` is consumed the same way, `el.title` answers from the stored value and setting it never touches the attribute, and a framework that binds `title` as a property — hybrids, lit's `.title` — never puts one on the host at all. The API is unchanged, `title="…"` stays the documented attribute; what changes is that `getAttribute('title')` returns `null` after upgrade. Every other element keeps the native `title` tooltip. The proposal was a new `heading` attribute with `title` removed after reading; the second half is what happened, the first would have given one thing two names across five elements. (EhrenPfoten, Elements finding 5.)
91
+
92
+ ---
93
+
94
+ ## [1.16.0] – 2026-09-22
95
+
96
+ ### Added
97
+
98
+ - **Three elements from EhrenPfoten: `<glk-date-strip>`, `<glk-calendar>`, `<glk-image-picker>`.** The ones that waited until real data had settled their attributes — the strip and the calendar run in booking (29-day horizon), in the team's day view and for schedule exceptions, the picker in the dog and profile photo upload. Built there as `GlkElement` subclasses by the rules in SKILL.md and reviewed here class by class. They arrive as copies with what the project proposed from the field, plus the deviations named below, which the project mirrors. Needs GlassKit 1.16.0 for the three CSS blocks; the peer dependency moves to `>=1.16.0`.
99
+
100
+ `<glk-date-strip>` (navigation): `start`, `days`, `value`, `today`, `marks`, plus `locale` and `label`. Against the project's element: the chips are a `role="group"` of `aria-pressed` buttons like `<glk-segmented>`, not a `role="listbox"` — `aria-pressed` on a `role="option"` is invalid, and the CSS hangs on `aria-pressed`; every chip is named with its full date from `Intl` ("Sonntag, 11. Oktober 2026") instead of the visible "So 11"; weekday names come from `Intl.DateTimeFormat` for the `locale` (the browser language by default) — the German constants are gone, and so is the German `aria-label`: `label` sets one, there is none without it; the strip is one tab stop with arrow keys, Home and End, where 29 chips were 29 tab stops; the chosen chip is centred in the strip after the first layout and on every value change, computed from client rects and applied to the strip's own `scrollLeft` (`scrollIntoView` would scroll every ancestor, the page included) and re-centred when the strip's width changes — a parent that upgrades later and adds its padding, a resize; `marks` takes a tone (`primary` / `success` / `warning` / `error`) or `{ tone, disabled }`, where `disabled` makes the chip unpickable — the project's `closed` becomes `{ "tone": "error", "disabled": true }`, or just `"error"` when a closed day should stay tappable; `glk-change` only on an actual change.
101
+
102
+ `<glk-calendar>` (forms): `month`, `value`, `today`, `marks`, plus `min`, `max`, `locale`, `week-start`, `label`, `prev-label`, `next-label` and `name`. Against the project's element: arrows only move focus and Enter or Space picks — the APG grid pattern — so a calendar that opens a sheet on every pick stays quiet while the user looks around, where the project's version picked on every arrow step; `min`/`max` mark days outside as `aria-disabled="true"`: in the arrow path and announced, never picked and never in `glk-change` — `disabled` would have taken them out of the arrow path, since a disabled button cannot take focus; the days are a `role="group"`, not `role="grid"` (a grid demands rows and cells with `aria-selected`); PageUp/PageDown move by a month, Home/End to the ends of the week; month title and weekday names come from `Intl`, and so does the first day of the week (`Intl.Locale.prototype.getWeekInfo()`, Monday where a browser cannot say, `week-start` overrides) — the German constants and labels are gone, `prev-label` / `next-label` default to English; the nav buttons carry SVG chevrons; the title is `aria-live="polite"`, so a new month is announced; a value set to another month flips the calendar there, also when `month` was set; form-associated like every other element in the forms group (`name`, `setFormValue`, reset restores the initial value); `glk-change` only on an actual change — a project that reopens a sheet by picking the same day again clears `value` when the sheet closes.
103
+
104
+ `<glk-image-picker>` (forms) — the project's photo picker, renamed with its CSS block because it takes any image: `src`, `label`, `round`, `max`, plus `hint`, `type`, `quality`, `accept`, `choose-label`, `change-label`, `remove-label`. Against the project's element: Choose is a real `<button>` that opens the hidden file input — the project's `<label>` around a hidden input could not be reached by keyboard at all; a file the browser cannot decode (Chrome and HEIC, a corrupt file) emits `glk-error { message, name }`, where the project's version rejected silently; the remove button is really hidden — `hidden` on a `.glass-btn` lost to its `display: flex` until GlassKit 1.16.0, which is why the project's picker shows Remove without an image; after remove, focus moves to Choose instead of falling off the vanished button; the German texts are gone, and there is no default hint at all, since what is accepted depends on `accept` and on the browser; a JPEG is drawn on white first, so a transparent PNG does not come out on black; `size` counts the base64 payload without prefix and padding; `label` names the group (`aria-labelledby`), `hint` describes it. Not form-associated, as proposed: the form value would be either the original file, which is not what gets uploaded, or a data URL of megabytes. The `glk-file` with a preview slot that the plan foresaw does not exist; this element is the answer to that need.
105
+
106
+ Verified in Chromium and WebKit: 29 chips with a deep link to the 20th day — the chosen chip inside the strip's visible range, centred to the pixel, page scroll unchanged; arrows on the calendar from 22 September across the month's edge to 7 October emit one `glk-month`, Enter on a `min`-blocked day emits nothing, Enter on the 23rd emits `glk-change`; a 200 × 100 JPEG with EXIF orientation 6 comes out 100 × 200 with the left half on top; `max="50"` on the same file gives 25 × 50; a bogus `.heic` emits `glk-error`; `FormData` carries the calendar's value and reset restores it.
107
+
108
+ Shared code: `src/dates.js` (ISO dates, `Intl` formatters, first weekday) becomes a shared chunk of the per-component build, `dist/components/shared/dates-<hash>.js`; the full bundles inline it.
109
+
110
+ ---
111
+
112
+ ## [1.15.2] – 2026-09-21
113
+
114
+ ### Fixed
115
+
116
+ - **`<glk-card fill>` grew past its grid cell with content that cannot wrap.** `fill` makes the host a grid so the inner `.glass-card` stretches to the cell — which also makes the card a grid item, and a grid item's `min-width: auto` is its min-content width. A nowrap `<glk-list-item>` subtitle therefore widened the card past its cell instead of getting its ellipsis: in a `repeat(auto-fit, minmax(300px, 1fr))` grid at 1100 px the host measured 522 px and the card 888 px, 366 px over the cell and across the neighbour; without `fill` the ellipsis worked. The card and the host now carry `min-width: 0`, so both yield to the cell and the subtitle truncates — the host part matters in `1fr` tracks and flex rows, where the host itself refused to shrink. The card also gets `min-height: 0`: in a cell of fixed height a scrollable child inside the card now shrinks and scrolls instead of the card running 250 px past the cell. Measured in Chromium and WebKit: card 522 px in the `minmax` grid, in a `1fr 1fr` grid and in a flex row; equal heights across a row unchanged; a plain `<glk-card>` unchanged. Compatibility: content that can neither wrap nor shrink now overflows the card's edge instead of pushing the card out of its cell, which is the trade-off `min-width: 0` always makes; a `glk-card[fill]::part(card) { min-width: 0 }` workaround can go. A plain `<glk-card>` keeps `min-width: auto` like any block — set `min-width: 0` on it yourself when it holds nowrap content in a `1fr` track. (EhrenPfoten, Elements finding 4.)
117
+
118
+ ---
119
+
120
+ ## [1.15.1] – 2026-09-21
121
+
122
+ ### Fixed
123
+
124
+ - **Rebuilt against GlassKit 1.15.1.** The elements bundle GlassKit's stylesheet, so two CSS fixes need a new build to reach them: `<glk-sheet>` is readable in dark mode (it had a light milk surface under white text), and a `<glk-sheet>` or `<glk-modal>` overlay now paints above a `<glk-tab-bar>` when both sit inside `.glass-bg` — `.glass-bg` no longer turns each of its children into a stacking context that trapped the overlay below the bar. No element changed; the peer dependency moves to `>=1.15.1`.
125
+
126
+ ---
127
+
128
+ ## [1.15.0] – 2026-09-21
129
+
130
+ Version numbers stay in step with GlassKit CSS at 1.15.0.
131
+
132
+ ### Added
133
+
134
+ - **Four elements from EhrenPfoten: `<glk-segmented>`, `<glk-steps>`, `<glk-sheet>`, `<glk-empty>`.** Built there as `GlkElement` subclasses by the rules in SKILL.md and reviewed here class by class. They arrive as copies with these deviations, which the project mirrors: no German defaults — `label` on `<glk-segmented>` and `<glk-steps>` sets the `aria-label` and there is none without it; `aria-current` only on the current step, not `"false"` on the others; the done check is an SVG, not a text glyph; tones are `success` / `warning` / `error`; `full` and `label` changes no longer rebuild the buttons. `<glk-segmented>` is form-associated (`name`, `setFormValue`, reset restores the initial value), like every other element in the forms group.
135
+
136
+ `<glk-sheet>` is the mobile sibling of `<glk-modal>` with the same API shape (`open`, `title`, `show()`, `close()`, `glk-close` only on a user close). It hides its overlay after `transitionend` (fallback 400 ms, immediate under reduced motion), so the blurred layer leaves the layout instead of idling at opacity 0 — `<glk-modal>` still keeps its overlay in the layout with `pointer-events: none`; giving it the same mechanic is a follow-up, not part of this release.
137
+
138
+ Documented on the docs and showcase pages in both languages with live demos, in README and SKILL.md. Requires GlassKit 1.15.0 for the four CSS blocks; the peer dependency moves to `>=1.15.0`. All 29 existing elements, attributes and events are unchanged.
139
+
140
+ ### Changed
141
+
142
+ - **The per-component files no longer inline the GlassKit stylesheet.** `dist/components/base.js` carried `componentsSheet` and `tokensCss` from `@jungherz-de/glasskit/glasskit-styles.js` compiled in — 61 KB, and a second copy of the sheet next to the one an import-map project already loads for its own elements (EhrenPfoten, finding 3). The per-component build now leaves `@jungherz-de/glasskit/glasskit-styles.js` as an external import: a bundler resolves it from `node_modules`, a build-free project adds one import-map entry, and either way the sheet exists once. `base.js` shrinks to about 8 KB. The full bundles keep inlining it — a `<script>` tag has nothing to resolve against.
143
+
144
+ Documented alongside: never mix the bundle with `base.js`. The bundle carries its own copy of `GlkElement`, so a subclass built on `base.js` next to it is a different class and `instanceof` fails across the two — with the bundle, take `GlassKitElements.GlkElement` or the ESM bundle's export.
145
+
146
+ ---
147
+
148
+ ## [1.14.0] – 2026-09-20
149
+
150
+ Version numbers realign with GlassKit CSS at 1.14.0.
151
+
152
+ ### Added
153
+
154
+ - **`GlkElement` and `GlkFormElement` are exported.** A project that wanted to build its own elements on the same base — lifecycle, adopted GlassKit stylesheet, theme sync, `emit()` — could not: the bundle exported the 29 component classes and nothing else. EhrenPfoten had to wrap its own elements in a different library, and every one of them that later flows back here would have to be rewritten instead of moved.
155
+
156
+ The classes are now reachable three ways: `import { GlkElement, GlkFormElement } from '@jungherz-de/glasskit-elements'` from the bundle; `from '@jungherz-de/glasskit-elements/base.js'` for per-component setups; and `GlassKitElements.GlkElement` from the CDN `<script>` bundle.
157
+
158
+ - **`dist/components/base.js` is a stable entry, not a hashed chunk.** `base.js` used to land in `dist/components/shared/base-<hash>.js`, a name that changed with every build and could not be imported on purpose. It is now an entry of the per-component build; Rollup never duplicates an entry module, so `glk-button.js` and a project's subclass import the same file and `instanceof GlkElement` holds across both. The `./base.js` export in `package.json` points at it.
159
+
160
+ Documented with a live `<demo-counter>` on the docs and showcase pages (both languages) and in SKILL.md, including the rules a subclass has to follow.
161
+
162
+ ### Changed
163
+
164
+ - **Requires GlassKit 1.14.0.** It ships `.glass-skeleton`, `.glass-table` and `.glass-prose`. All three are document-level blocks — from a shadow root, `::slotted()` cannot reach a table's cells or a Markdown paragraph — so no element wraps them; put the class on the light-DOM element. The peer dependency moves to `>=1.14.0`.
165
+
166
+ ---
167
+
168
+ ## [1.13.0] – 2026-09-20
169
+
170
+ ### Added
171
+
172
+ - **`<glk-badge interactive selected>` — the badge as a filter chip.** A badge was already being used as a chip in the wild — a status row where one entry is picked — but the element offered nothing for it. Projects marked the chosen chip with `variant="primary"` and bolted an `onclick` onto the host, which worked with a mouse and nowhere else: no focus ring, no keyboard, nothing announced.
173
+
174
+ `interactive` renders the badge as a real `<button type="button">` instead of a `<span>`, so the keyboard, the focus ring and the click semantics come from the platform rather than from a re-implementation. `selected` marks the chip that is on and is mirrored to `aria-pressed`, so a screen reader announces the row as a group of toggles. Both are reflected as properties.
175
+
176
+ ```html
177
+ <div id="filter">
178
+ <glk-badge interactive selected>Active</glk-badge>
179
+ <glk-badge interactive>Applied</glk-badge>
180
+ </div>
181
+ <script>
182
+ filter.addEventListener('glk-click', e => {
183
+ for (const chip of filter.querySelectorAll('glk-badge')) chip.selected = chip === e.target;
184
+ });
185
+ </script>
186
+ ```
187
+
188
+ `glk-click` fires only while `interactive` is set — the same rule `<glk-list-item>` follows. Toggling `interactive` at runtime swaps the inner element; the slot moves across, so the slotted label never has to be re-assigned.
189
+
190
+ ### Changed
191
+
192
+ - **Requires GlassKit 1.12.0.** The chip states are painted by `.glass-badge--interactive` and `.glass-badge--selected`, which arrived in GlassKit CSS 1.12.0 — a selected chip deepens the colour the badge already has, so `variant="success"` stays green when picked. The peer dependency moves to `>=1.12.0`; on an older stylesheet the button renders, but without hover, focus ring or selection tint.
193
+
194
+ ---
195
+
196
+ ## [1.12.0] – 2026-08-18
197
+
198
+ ### Fixed
199
+
200
+ - **`<glk-select>` copied its options exactly once.** `render()` cloned the
201
+ `<option>` children into the shadow tree on the next frame and nothing watched
202
+ them afterwards — no observer, no `slotchange`, and `observedAttributes` cannot
203
+ cover children. Replacing the list after that first frame left the rendered
204
+ select on the first state for good. Measured: with light-DOM options `['c']`
205
+ the shadow select still reported `['a', 'b']`.
206
+
207
+ It fails quietly. Nothing errors, the element looks right, and
208
+ `querySelectorAll('option')` on the host returns the correct values — the
209
+ difference only exists inside the shadow root, which is why it typically
210
+ surfaces as a failing end-to-end test rather than a bug report.
211
+
212
+ A `MutationObserver` now keeps the copy in step. Adding, removing or replacing
213
+ options is picked up, including a changed option label.
214
+
215
+ - **The selection no longer jumps to the first entry on every update.** Rebuilding
216
+ starts with `innerHTML = ''`, which drops the selection. It is now restored: a
217
+ selected value that is still in the new list stays selected, otherwise the
218
+ `value` attribute decides, otherwise the browser picks the first option.
219
+
220
+ - **The empty string is a valid selection.** `render()` guarded the initial value
221
+ with `if (value)`, so `value=""` was discarded and the field fell back to the
222
+ first option. `""` is a real choice in plenty of forms ("detect automatically",
223
+ "enter your own below"). Measured with the `""` option placed second: before,
224
+ the field showed the first option; now it shows the `""` one.
225
+
226
+ As a consequence, a `value` naming no existing option now leaves the current
227
+ selection alone instead of clearing it — when the matching option arrives with
228
+ a later update, it is selected then. This makes a controlled select self-heal
229
+ when value and options arrive in separate renders.
230
+
231
+ - **`<glk-tab-item>` and `<glk-modal>` had the same defect** and were fixed with
232
+ it. Both cloned from the light DOM once per `requestAnimationFrame`: a swapped
233
+ `<svg>` never reached the tab item, and replaced `[slot="actions"]` buttons never
234
+ reached the modal footer. The modal also forwarded clicks to the button object it
235
+ had captured at clone time, so after a framework re-render the footer buttons
236
+ drove nodes that were no longer in the document. The original is now looked up at
237
+ click time.
238
+
239
+ - **A moved element stopped reacting.** `disconnectedCallback` calls
240
+ `teardownEvents()`, but `setupEvents()` only ever ran on the first connect, and
241
+ the element was dropped from the theme-sync registry for good. Moving a
242
+ `<glk-*>` element in the DOM — routine for any framework — left it looking
243
+ correct while its events were dead. Both now re-arm on every connect. Measured:
244
+ after `otherParent.appendChild(el)`, `glk-change` fired 0 times before and 1
245
+ time after, with no double-firing.
246
+
247
+ ### Added
248
+
249
+ - `GlkElement.observesLightDom` / `projectLightDom()` — the hook the three
250
+ components above share, so a component that copies light-DOM children into its
251
+ shadow tree gets an observer without repeating the wiring.
252
+ - `element.refresh()` — public escape hatch that re-runs the copy immediately,
253
+ for the cases an observer cannot see. Nobody needs to reach into
254
+ `element.shadowRoot` any more.
255
+
256
+ ### Compatibility
257
+
258
+ No tag, attribute or event changed. Three behaviour changes worth knowing:
259
+ `value=""` is now honoured, a `value` matching no option no longer clears the
260
+ selection, and a moved element keeps working instead of going quiet.
261
+
262
+ ---
263
+
264
+ ## [1.11.0] – 2026-08-17
265
+
266
+ ### Fixed
267
+
268
+ - **`<glk-radio>` did not group: two radios with the same `name` could both be
269
+ checked.** Every `<glk-radio>` keeps its `<input type="radio">` in its own shadow
270
+ root, and native radio grouping works per tree — it does not reach across shadow
271
+ boundaries. The `name` attribute was passed through and so *looked* like a
272
+ grouping that did not exist. Measured before the fix with two
273
+ `<glk-radio name="skr">`: right after clicking the second one, **both** inputs
274
+ reported `checked === true`, and a `FormData` of the surrounding form carried
275
+ **three** `skr` entries for three radios.
276
+
277
+ The group is now kept by the component, following the HTML definition as closely
278
+ as it can: same `name`, same containing tree, same form owner. Selecting one
279
+ clears the others — by click, by arrow key, by the `checked` property and by the
280
+ `checked` attribute — so `FormData` carries exactly one entry. Two `<glk-radio>`
281
+ in two different `<form>`s stay two groups, a radio without `name` is not grouped,
282
+ and when several carry `checked` in the markup the last one wins, as with native
283
+ radios.
284
+
285
+ - **A radio group had no keyboard navigation.** Arrow keys did nothing and every
286
+ radio was its own tab stop. The group is now a single tab stop with a roving
287
+ `tabindex`; <kbd>↑</kbd> <kbd>↓</kbd> <kbd>←</kbd> <kbd>→</kbd> move through it,
288
+ wrap around, skip disabled entries and select as they go, firing `glk-change` and
289
+ `change` exactly as a click does. <kbd>Tab</kbd> and modified arrow presses are
290
+ left alone.
291
+
292
+ ### Changed
293
+
294
+ - Requires **GlassKit CSS >= 1.11.0**, which brands the focus ring, the warm rim and
295
+ the primary glow from `--gl-color-primary`, and aligns checkbox, radio and toggle
296
+ on the *first* line of a multi-line label instead of the middle of the text block.
297
+ Both reach into the shadow roots without any change here.
298
+ - The CDN snippets on the site and in the docs pinned `glasskit@1.6` — below the peer
299
+ requirement since 1.10.0. Now `@1.11` everywhere.
300
+
301
+ ### Why no `<glk-radio-group>`
302
+
303
+ It was the report's second proposal, and it is the only way to get `role="radiogroup"`
304
+ announced. It is not carried here: new components are out of scope for this round, and
305
+ a container holding the selection would be a second, competing source of truth next to
306
+ the `checked` attribute. Grouping and keyboard navigation are the parts that could be
307
+ fixed without one, and they are. For the screen-reader announcement, wrap the radios in
308
+ your own `<div role="radiogroup" aria-label="…">` — documented in SKILL.md.
309
+
310
+ ### Compatibility
311
+
312
+ The grouping is a **behaviour change** for code that relied on two same-named radios
313
+ staying independent: they now clear each other. That was the defect, but it is worth
314
+ checking before upgrading. Tab order changes too — a group is one tab stop now, not
315
+ one per radio.
316
+
317
+ ---
318
+
319
+ ## [1.10.0] – 2026-08-17
320
+
321
+ ### Fixed
322
+
323
+ - **Icons passed into an element were not styled by GlassKit.** The icon rules are
324
+ descendant selectors (`.glass-btn svg`, `.glass-list__leading svg`, …), but a slotted
325
+ icon stays in the light DOM and is no descendant of the shadow tree, so they never
326
+ matched. Nothing errored — the component just rendered with an unusable icon.
327
+
328
+ | | before | after |
329
+ |---|---|---|
330
+ | `<glk-button>` | 1210×1210 | 20×20 |
331
+ | `<glk-tab-accessory>` | 54×54 | 22×22 |
332
+ | `<glk-list-item slot="leading">` | 28×28 | 24×24 |
333
+ | `<glk-list-item leading-lg>` | 28×28 | 32×32 |
334
+ | `<glk-list-item slot="trailing">` | 0×0 | 18×18 |
335
+ | `<glk-status slot="icon">` | 0×0 | 20×20 |
336
+ | `<glk-pill>` | 32×32 | 20×20 |
337
+
338
+ Fixed in GlassKit CSS 1.10.0, which gives every icon rule sitting above a slot a
339
+ `::slotted()` twin. This release only raises the peer dependency and documents the
340
+ behavior; no element changed.
341
+
342
+ `<glk-tab-item>` was never affected — it clones the SVG into its shadow root, where it
343
+ is a real descendant.
344
+
345
+ ### Why this is not fixed inside the elements
346
+
347
+ The finding proposed adding `::slotted()` rules to the element stylesheets. That was not
348
+ the right place, and it would not have been complete:
349
+
350
+ 1. **`::slotted()` matches only the assigned node, never inside it.** An icon wrapped in a
351
+ container — `<span slot="leading"><svg …></span>` — cannot be styled from the shadow
352
+ root at all. That is a limit of the platform. Wrapped icons still measure 0×0 after
353
+ this release; pass the `<svg>` directly, as the docs show, or size it yourself.
354
+ 2. **The rules belong to the stylesheet that owns them.** `.glass-btn--primary`,
355
+ `--secondary` and `--tertiary` each carry their own icon rule, as do the four
356
+ accessory variants. Restating them here would duplicate GlassKit's cascade in a second
357
+ project and let the two drift apart. Written as twin selectors next to the originals,
358
+ they cannot.
359
+
360
+ The proposed rule also omitted `stroke: currentColor`; combined with `fill: none` that
361
+ renders an icon invisible unless it carries its own presentation attributes.
362
+
363
+ ### Changed
364
+
365
+ - Peer dependency raised to `@jungherz-de/glasskit >= 1.10.0`.
366
+ - **Documented how to pass icons** in README and SKILL.md, including the wrapped-icon
367
+ limitation and the fact that a project's own rules keep precedence over `::slotted()`.
368
+
369
+ ---
370
+
371
+ ## [1.9.0] – 2026-08-17
372
+
373
+ Version numbers of GlassKit and GlassKit Elements are realigned with this release.
374
+
375
+ ### Fixed
376
+
377
+ - **`--gl-*` overrides from the document had no effect inside any `<glk-*>` element.**
378
+ Every element adopted the full GlassKit stylesheet, which contains
379
+ `:root, [data-theme="dark"] { … }`. Inside the shadow root that selector matches the
380
+ element's own `.glk-wrapper`, so all tokens were re-declared locally — and a matching
381
+ rule always beats an inherited value. A project's brand file reached plain `.glass-*`
382
+ markup but never the components, so projects came out half-branded.
383
+
384
+ Measured before the fix, same page, same button:
385
+
386
+ | | document | inside `.glk-wrapper` |
387
+ |---|---|---|
388
+ | `--gl-color-primary` | `#2e9e8f` (brand) | `#e8852d` |
389
+ | `--gl-color-text` | `#12242f` (brand) | `#1a2a36` |
390
+ | rendered | teal | orange |
391
+
392
+ Elements now adopt `componentsSheet` — the component rules without the token
393
+ declarations — so the document's values are inherited normally. Both the CSS class and
394
+ the web component render the brand color.
395
+
396
+ `!important` never helped here, and neither did `theme-override.css`: both operate at
397
+ document level, while the problem was a competing declaration inside the shadow root.
398
+
399
+ ### Added
400
+
401
+ - **Token defaults are placed on the document**, once, wrapped in
402
+ `@layer glasskit-defaults`. Since the tokens no longer live in the shadow roots, this
403
+ keeps the advertised standalone case working — a page that loads only the elements
404
+ bundle and no `glasskit.css` still renders styled components. The cascade layer means
405
+ an ordinary brand stylesheet wins regardless of load order, and so does a linked
406
+ `glasskit.css`, at identical values.
407
+
408
+ The sheet is *appended* to `document.adoptedStyleSheets`, never assigned, and a global
409
+ guard prevents a second injection when more than one copy of the bundle is loaded
410
+ (verified: full bundle plus a per-component entry still yields exactly one sheet).
411
+
412
+ - **Branding is now documented** in README and SKILL.md. It was not mentioned in the
413
+ README at all, and SKILL.md claimed the opposite of the actual behavior.
414
+
415
+ ### Changed
416
+
417
+ - Peer dependency raised to `@jungherz-de/glasskit >= 1.9.0`, the release that exports
418
+ the split stylesheet this depends on.
419
+
420
+ ### Upgrading
421
+
422
+ Projects **without** `--gl-*` overrides see no change — verified against Voice-Office-Hub
423
+ across all 117 tokens in both themes: zero differences.
424
+
425
+ Projects **with** overrides will see their components change to the branded values. That
426
+ is the fix working, but it is visible. Anything your brand file sets that differs from
427
+ GlassKit's default will now also apply inside components. Tokens that only feed
428
+ `.glass-bg` (`--gl-color-bg-*`, `--gl-bg-aurora-*`) were already applied at document
429
+ level and do not change.
430
+
431
+ ---
432
+
433
+ ## [1.8.0] – 2026-08-16
434
+
435
+ ### Added
436
+
437
+ - **`<glk-card fill>` stretches the card to its grid or flex cell.** A card in a
438
+ `repeat(auto-fit, minmax(…, 1fr))` grid left the visible `.glass-card` at its natural
439
+ height even though the host stretched correctly, so tiles ended up ragged and footer
440
+ buttons sat at different heights. Measured with four tiles: hosts all 248 px, cards
441
+ 184/200/248/184, footers 83/99/147/83 px from the top of their tile. With `fill`, all
442
+ four cards are 248 px and all footers sit at 147 px.
443
+
444
+ ```html
445
+ <glk-card fill>…</glk-card>
446
+ ```
447
+
448
+ The host becomes a grid when `fill` is set, and the card becomes a flex column so a
449
+ footer can be pushed down with `margin-top: auto`. Making the *host* a grid is the
450
+ point: it is stretched by the outer layout but keeps `height: auto`, so the host alone
451
+ is not enough — a child needs either a grid stretch or a definite height to resolve
452
+ against.
453
+
454
+ - **`part` on the structural elements of `glk-card`, `glk-list` and `glk-modal`**, so
455
+ their internals can be styled from outside the shadow root:
456
+
457
+ | Element | Parts |
458
+ |---|---|
459
+ | `<glk-card>` | `card` |
460
+ | `<glk-list>` | `header`, `list` |
461
+ | `<glk-modal>` | `overlay`, `modal`, `header`, `body`, `footer` |
462
+
463
+ ```css
464
+ glk-card::part(card) { border-radius: 8px; }
465
+ ```
466
+
467
+ `::part(card) { height: 100% }` also solves the stretch problem on its own — it is the
468
+ general escape hatch, `fill` is the ergonomic shortcut for the common case. `fill` is
469
+ deliberately **not** offered on `glk-modal`: an overlay is not a grid item, so it has
470
+ no such problem.
471
+
472
+ - **`GlkElement.hostStyles`** — an optional static returning a `CSSStyleSheet`, adopted
473
+ after the shared sheets. It keeps per-component selectors like `:host([fill])` out of
474
+ the shared stylesheet, so an attribute only means something where it is documented.
475
+
476
+ ### Changed
477
+
478
+ - Peer dependency raised to `@jungherz-de/glasskit >= 1.7.1`, which declares
479
+ `color-scheme`. Because that rule is keyed on `[data-theme]`, it applies to the
480
+ `.glk-wrapper` inside every shadow root — so `<glk-input type="date">` and friends now
481
+ get browser widgets in the right scheme.
482
+
483
+ ---
484
+
485
+ ## [1.7.0] – 2026-08-16
486
+
487
+ ### Fixed
488
+
489
+ - **`/components/*` imports resolved to nothing.** The export map advertised
490
+ `"./components/*": "./dist/components/*.js"`, but Rollup only ever produced the three
491
+ full bundles — `dist/components/` did not exist. The subpath was also malformed: `*`
492
+ captures the whole remainder including the extension, so the documented specifier
493
+ `…/components/glk-button.js` expanded to `dist/components/glk-button.js.js`. Every
494
+ per-component import in README.md and SKILL.md therefore failed with a resolution
495
+ error.
496
+
497
+ Both halves are fixed rather than removed, because the smaller import is worth having:
498
+
499
+ - Rollup now emits one ES module per element to `dist/components/glk-{name}.js`
500
+ (29 entries, discovered from `src/components/{category}/`), with `base.js` and the
501
+ GlassKit stylesheet split into a single shared chunk under
502
+ `dist/components/shared/` instead of being copied into each file.
503
+ - The export map entry is now `"./components/*.js": "./dist/components/*.js"`, which
504
+ matches the documented specifier. `"./package.json"` was added alongside it.
505
+
506
+ Importing a single element pulls ~50 KB (shared chunk + component) instead of the
507
+ 112 KB full ESM bundle.
508
+
509
+ ### Changed
510
+
511
+ - **Peer dependency raised to `@jungherz-de/glasskit >= 1.7.0`.** The elements bundle
512
+ the GlassKit stylesheet into their shadow roots, so they carry the 1.7.0 WCAG AA
513
+ contrast fixes for badges, the primary button, and filled state surfaces.
514
+
515
+ > **Release order matters:** `dist/` embeds whatever GlassKit version is installed at
516
+ > build time. Publish `@jungherz-de/glasskit@1.7.0` first, then `npm install` here and
517
+ > rebuild before tagging.
518
+
519
+ - **npm publishing switched to Trusted Publishing (OIDC).** `release.yml` requests
520
+ `id-token: write` and publishes without `NODE_AUTH_TOKEN`; provenance is generated
521
+ automatically. Requires a trusted publisher registered on npm for
522
+ `JUNGHERZ/glasskit-elements` with workflow `release.yml`, so the filename must stay.
523
+ - **Release workflow** now fails when the committed `dist/` differs from a fresh build,
524
+ and the checkout/setup-node/release actions were bumped to the majors already used by
525
+ the GlassKit repo. `prepublishOnly` runs `npm run build`.
526
+ - **`prebuild` clears `dist/components/`** before each build. The shared chunk carries a
527
+ content hash in its filename, so a rebuild against a new GlassKit version writes a new
528
+ file instead of replacing the old one. Without the clean step the stale chunk would be
529
+ committed and published forever.
530
+
531
+ ---
532
+
533
+ ## [1.6.2] – 2026-07-19
534
+
535
+ Site / docs / README only — no component or API changes.
536
+
537
+ ### Fixed
538
+
539
+ - **Stale component counts aligned to 29** across all pages:
540
+ - Docs hero (EN + DE) still said "all 24 web components" — the only place left from the 24-component era.
541
+ - Meta / Open Graph / Twitter descriptions on the landing pages (EN + DE) and docs (EN + DE) still said 27.
542
+ - SKILL.md project-structure table still said "registers all 27 elements".
543
+ - **German landing page wording**:
544
+ - Hero headline gradient said "for GlassKit CSS" — now "für GlassKit CSS", matching the page's own `<title>` and meta tags.
545
+ - Hero badge said "29 Components" — now "29 Komponenten", matching the German docs badge and feature card.
546
+
547
+ ---
548
+
549
+ ## [1.6.1] – 2026-07-19
550
+
551
+ Site / docs / README only — no component or API changes.
552
+
553
+ ### Added
554
+
555
+ - **GlassKit family cross-linking** — landing pages, docs, and README now interlink the three-layer family (GlassKit CSS → GlassKit Elements → GlassKit Web), mirroring the family section on the [GlassKit Web](https://glasskit-web.jungherz.com) site:
556
+ - **Landing pages (EN + DE)** — new "The GlassKit family" / "Die GlassKit-Familie" section ("Three layers, one design language") with three cards; the own card is marked "you are here" / "du bist hier". Footer gained links to [GlassKit](https://glasskit.jungherz.com) and [GlassKit Web](https://glasskit-web.jungherz.com).
557
+ - **Docs (EN + DE)** — new closing section "Building a complete website?" / "Eine komplette Website bauen?" pointing to GlassKit Web as the intended path for full marketing websites; sidebar footer links to both sister projects.
558
+ - **README** — GlassKit Web added to the header link row and a family / layering paragraph added to the intro.
559
+
560
+ ### Changed
561
+
562
+ - **README header link** for GlassKit CSS now points to the landing page (glasskit.jungherz.com) instead of the GitHub repo, consistent with the new GlassKit Web link.
563
+
564
+ ---
565
+
566
+ ## [1.6.0] – 2026-04-28
567
+
568
+ ### Added
569
+
570
+ - **Two new components — `glk-tab-dock`, `glk-tab-accessory`** — tracking GlassKit CSS v1.6.0 floating Tab-Bar variant (iOS 26 Liquid Glass):
571
+ - **`<glk-tab-dock>`** — wrapper that holds a floating tab bar plus an optional accessory capsule, with `accessory-left` modifier (maps to `.glass-tab-bar-dock` + `.glass-tab-bar-dock--accessory-left`).
572
+ - **`<glk-tab-accessory>`** — standalone 56×56 px glass capsule (search, compose…) sitting next to the bar. Supports `variant="accent" / "success" / "error"` for filled colored capsules with white icons (maps to `.glass-tab-bar__accessory` + variants), plus `label` (aria-label) and `disabled`. Emits `glk-click`.
573
+ - **`<glk-tab-bar>` — `floating` attribute** — pill-shaped Liquid Glass variant (maps to `.glass-tab-bar--floating`). Active item gets a soft radial Spotlight halo instead of the underline dot. Use inside `<glk-tab-dock>`.
574
+ - **Component count** bumped from **27 → 29** across README, SKILL.md, landing pages, showcase, and docs.
575
+
576
+ ### Changed
577
+
578
+ - **Peer dependency** `@jungherz-de/glasskit` raised from `>=1.5.0` to `>=1.6.0`. The new floating Tab-Bar variant + Accessory ship their CSS in 1.6.0 only.
579
+ - **CDN version pin** updated from `@1.5` to `@1.6` across all HTML pages.
580
+ - **Showcase** (EN + DE) — bottom navigation switched from the standard tab bar to the new floating variant with an accent accessory capsule, matching the sister GlassKit CSS showcase.
581
+
582
+ ---
583
+
584
+ ## [1.5.0] – 2026-04-12
585
+
586
+ ### Version alignment
587
+
588
+ Starting with this release, GlassKit Elements version numbers are aligned with GlassKit CSS. The jump from 0.9.0 to 1.5.0 reflects this alignment — both projects now share the same version number. Future releases will maintain this parity.
589
+
590
+ ### Added
591
+
592
+ - **`<glk-list>` — `header` attribute** — renders an uppercase section header label above the list (maps to `.glass-list__section-header`)
593
+ - **`<glk-list-item>` — 4 new attributes** tracking GlassKit CSS v1.5.0:
594
+ - **`leading-lg`** — large 40×40 icon slot with rounded corners for app icons (maps to `.glass-list__leading--lg`)
595
+ - **`wrap`** — multi-line subtitle (up to 3 lines with ellipsis, maps to `.glass-list__subtitle--wrap`)
596
+ - **`detail`** — muted trailing value text for metadata like file sizes or version numbers (maps to `.glass-list__value`)
597
+ - **`variant`** — semantic color: `"danger"` (red destructive) or `"accent"` (primary color), consistent with `<glk-badge>`, `<glk-button>`, `<glk-toast>` (maps to `.glass-list__item--danger` / `--accent`)
598
+
599
+ ### Changed
600
+
601
+ - **Peer dependency** `@jungherz-de/glasskit` raised from `>=1.4.0` to `>=1.5.0`. The new List sub-features ship their CSS in 1.5.0.
602
+ - **CDN version pin** updated from `@1.4` to `@1.5` across all HTML pages.
603
+
604
+ ### Fixed
605
+
606
+ - **Range slider** — thumb centering fix on Chrome / Safari inherited from GlassKit CSS v1.5.0 (pure CSS, no JS change).
607
+
608
+ ---
609
+
610
+ ## [0.9.0] – 2026-04-11
611
+
612
+ ### Added
613
+
614
+ - **Three new components — `glk-popover`, `glk-list`, `glk-list-item`** — tracking GlassKit CSS v1.4.0:
615
+ - **`<glk-popover>`** — anchored dropdown / menu container with fade + scale animation, `placement` attribute (`top` / `bottom` / `start` / `end`), `.show()` / `.close()` / `.toggle()` methods, automatic outside-click and <kbd>Escape</kbd>-key dismiss. Uses a `slot="trigger"` pattern; toggling is handled internally. Method is deliberately named `.toggle()` instead of `.togglePopover()` to avoid collision with the native `HTMLElement.togglePopover()` API.
616
+ - **`<glk-list>`** — iOS-style grouped settings container with `flush` and `bare` modifiers.
617
+ - **`<glk-list-item>`** — list row with `title`, `subtitle`, `interactive`, `center` attributes and `leading` / `trailing` slots for icons and values. Emits `glk-click` when `interactive`.
618
+ - **`SKILL.md` AI reference** — tag-based companion to the class-based SKILL.md in `@jungherz-de/glasskit`. Structured frontmatter + sections for setup, element catalog (27 elements), composition patterns, rules & common mistakes, quick reference.
619
+ - **Component count** bumped from **24 → 27** across README, landing pages, showcase, and docs.
620
+
621
+ ### Changed
622
+
623
+ - **Peer dependency** `@jungherz-de/glasskit` raised from `>=1.3.0` to `>=1.4.0`. The new List and Popover components ship their CSS in 1.4.0 only.
624
+ - **CDN version pin** updated from `@1.3` to `@1.4` in `showcase.html`, `docs.html`, and their German counterparts.
625
+
626
+ ### Design Decisions
627
+
628
+ - **Pure Shadow DOM + sentinel-sibling trick for `<glk-list-item>`** — the GlassKit-CSS auto-divider rule relies on `:not(:last-child)::after`, which cannot cross Shadow DOM boundaries. Rather than cloning children into a parent shadow (which would break lit-html, HybridsJS, React, Vue, and Svelte template bindings), each list-item renders its own `<li class="glass-list__item">` inside its own shadow root with a hidden sibling so `:last-child` never matches internally. `<glk-list>` then marks the actual last child in the light DOM with a `data-last` attribute, and the item's shadow adopts a one-line override sheet `:host([data-last]) .glass-list__item::after { content: none; }` to hide the divider on the real last row. Zero CSS duplication, zero DOM cloning, framework-safe.
629
+ - **Why not data-carrier pattern** — `<glk-select>` reads `<option>` children and clones them into its shadow. That works for static child data, but with reactive frameworks like lit-html or HybridsJS, the original templates re-render independently of our clones, losing bindings and event listeners. For list-items we kept slot projection pure.
630
+
631
+ ---
632
+
633
+ ## [0.8.3] – 2026-03-27
634
+
635
+ ### Changed
636
+
637
+ - **package.json metadata**: Added `homepage`, `repository`, and `bugs` fields so npm registry displays the correct website and GitHub links
638
+
639
+ ---
640
+
641
+ ## [0.8.2] – 2026-03-22
642
+
643
+ ### Fixed
644
+
645
+ - **CDN/npm references**: All documentation, landing pages, and README now correctly reference `@jungherz-de/glasskit-elements` scope
646
+
647
+ ---
648
+
649
+ ## [0.8.1] – 2026-03-22
650
+
651
+ ### Fixed
652
+
653
+ - **glk-select**: Options not rendering — deferred option copying to next frame (`requestAnimationFrame`) to ensure light DOM children are parsed
654
+ - **glk-modal**: Footer buttons not visible — deferred footer population to next frame for same timing reason
655
+ - **glk-tab-item**: Badge positioned incorrectly — moved badge element inside `.glass-tab-bar__icon` container (which has `position: relative`)
656
+ - **glk-tab-item**: Icons not styled correctly — SVGs are now cloned from light DOM into shadow DOM so GlassKit CSS rules apply; inline attributes (`stroke`, `width`, `fill`) stripped during clone
657
+
658
+ ### Added
659
+
660
+ - **glk-tab-bar `static` attribute**: Sets `position: relative` instead of `fixed` for embedding in documentation previews
661
+ - **Showcase navbar**: Added `glk-nav` with pill buttons (back, theme toggle) and `glk-tab-bar` at bottom
662
+ - **Docs live previews**: Added interactive previews for `glk-nav`, `glk-pill`, `glk-tab-bar`, `glk-modal`, and `glk-toast`
663
+ - **npm scope**: Package published as `@jungherz-de/glasskit-elements`
664
+ - **GitHub Pages**: Switched from import maps to built IIFE bundle (`dist/glasskit-elements.min.js`)
665
+ - **Phone frame**: Matched GlassKit original styling with multi-layer bezel box-shadow
666
+ - **SEO meta tags**: Open Graph, Twitter Cards, hreflang, canonical on all 6 pages
667
+ - **German translations**: `de/index.html`, `de/docs.html`, `de/showcase.html` with language switcher
668
+ - **Language switcher**: `🇩🇪 DE` / `🇬🇧 EN` pills in header (index) and fixed button (docs)
669
+ - **README.md, CHANGELOG.md, LICENSE**: Project documentation
670
+
671
+ ### Changed
672
+
673
+ - **GitHub links**: Point to `JUNGHERZ/GlassKit-Elements` instead of `JUNGHERZ/GlassKit`
674
+ - **dist/ tracked in git**: Required for GitHub Pages deployment
675
+
676
+ ---
677
+
678
+ ## [0.8.0] – 2026-03-21
679
+
680
+ ### Added 🎉
681
+
682
+ - **Initial public release** of GlassKit Elements
683
+ - **24 Web Components** wrapping the full GlassKit CSS component library
684
+ - **Base classes** (`GlkElement`, `GlkFormElement`) with Shadow DOM + `adoptedStyleSheets`
685
+ - **Shadow DOM architecture** using GlassKit's exported `glassSheet` constructable stylesheet
686
+ - **Theme sync** via global `MutationObserver` on `data-theme` attribute
687
+ - **Form participation** for all form components via `ElementInternals` (`formAssociated`)
688
+ - **Components:**
689
+ - Navigation: `glk-nav`, `glk-pill`, `glk-tab-bar`, `glk-tab-item`
690
+ - Content: `glk-card`, `glk-badge`, `glk-avatar`, `glk-title`, `glk-divider`, `glk-status`
691
+ - Buttons: `glk-button` (primary, secondary, tertiary; sm, md, lg, auto)
692
+ - Forms: `glk-input`, `glk-textarea`, `glk-select`, `glk-search`, `glk-toggle`, `glk-checkbox`, `glk-radio`, `glk-range`
693
+ - Feedback: `glk-progress`, `glk-modal`, `glk-toast`
694
+ - Containers: `glk-accordion`, `glk-accordion-item`
695
+ - **Three build formats:** IIFE (CDN), ESM (bundlers), ESM per-component (tree-shaking)
696
+ - **Landing page** (`index.html`) with phone mockup and before/after comparison
697
+ - **Documentation** (`docs.html`) with live previews, attribute tables, and scroll spy
698
+ - **Showcase** (`showcase.html`) with all components in a mobile frame
699
+ - **German translations** for all pages (`de/`)
700
+ - **SEO meta tags** (Open Graph, Twitter Cards, hreflang, canonical)
701
+ - **Language switcher** matching GlassKit's design (🇩🇪 DE / 🇬🇧 EN)
702
+
703
+ ### Design Decisions
704
+
705
+ - **Shadow DOM + `adoptedStyleSheets`** over Light DOM — proper encapsulation while sharing the GlassKit `CSSStyleSheet` object across all instances
706
+ - **`display: contents`** on the theme wrapper div — layout-transparent node for `data-theme` CSS selectors without affecting component layout
707
+ - **Two base classes** — `GlkElement` for general components, `GlkFormElement` (with `formAssociated = true`) for form elements only
708
+ - **Peer dependency** on `@jungherz-de/glasskit` — CSS is not bundled, users load it separately
709
+
710
+ ---
711
+
712
+ [1.19.2]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.19.2
713
+ [1.19.1]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.19.1
714
+ [1.19.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.19.0
715
+ [1.18.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.18.0
716
+ [1.17.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.17.0
717
+ [1.16.1]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.16.1
718
+ [1.16.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.16.0
719
+ [1.15.2]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.15.2
720
+ [1.15.1]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.15.1
721
+ [1.15.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.15.0
722
+ [1.14.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.14.0
723
+ [1.13.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.13.0
724
+ [1.12.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.12.0
725
+ [1.11.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.11.0
726
+ [1.10.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.10.0
727
+ [1.9.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.9.0
728
+ [1.8.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.8.0
729
+ [1.7.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.7.0
730
+ [1.6.2]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.6.2
731
+ [1.6.1]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.6.1
732
+ [1.6.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.6.0
733
+ [1.5.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.5.0
734
+ [0.9.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v0.9.0
735
+ [0.8.3]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v0.8.3
736
+ [0.8.2]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v0.8.2
737
+ [0.8.1]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v0.8.1
738
+ [0.8.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v0.8.0