@jungherz-de/glasskit-elements 1.26.0 → 1.28.0

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
@@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.28.0] – 2026-10-20
11
+
12
+ Versions stay aligned with GlassKit at 1.28.0, which this release is built against (peer dependency `>=1.28.0`).
13
+
14
+ ### Added
15
+
16
+ - **Icons that are not inline SVG in `<glk-tab-item>`: `slot="icon"`.** The item copied the first `<svg>` of its light DOM into its shadow root and showed nothing else, so an app whose tab icons come from Material Icons, a ligature font, or from an element of its own could not use them. Anything slotted as `icon` now sits in GlassKit's `.glass-tab-bar__icon`, before the badge, and takes the state colour from it (GlassKit 1.28.0): inactive, hover, active, the lens of the drop and the drag; on a bar without droplet the active icon carries the glow. An `<svg>` without `slot` is copied as before; with a slotted icon nothing is copied. ([#17](https://github.com/JUNGHERZ/GlassKit-Elements/issues/17))
17
+ - **Icons per option in `<glk-segmented>`: `slot="icon-<value>"`, and `icon-only`.** The options were text only. Each option now takes an icon from the slot named after its value — an `<svg>`, a font icon, an `<img>` — in GlassKit's `.glass-segmented__icon` before the label; an option without one has no icon box, and an icon added or removed later shows or hides it. The icon box is `aria-hidden`, so a font icon's text never joins the name. `icon-only` (property `iconOnly`) shows the icons alone, for a light / dark / auto switch: the row takes `.glass-segmented--icons`, and each label becomes the button's `aria-label` and `title`. ([#17](https://github.com/JUNGHERZ/GlassKit-Elements/issues/17))
18
+ - **`droplet` and `floating` are properties of `<glk-tab-bar>`.** The README called `droplet` "also a property", but `GlkTabBar` had no accessor, so `bar.droplet = true` set an own property and changed nothing; `floating` had the same gap. ([#17](https://github.com/JUNGHERZ/GlassKit-Elements/issues/17))
19
+ - **GlassKit 1.28.0's tokens reach the elements by inheritance:** `--gl-tab-bar-color`, `--gl-tab-bar-hover-color`, `--gl-tab-bar-label-size` and `--gl-tab-bar-z-index` for `<glk-tab-item>`, `<glk-tab-bar>` and `<glk-tab-dock>`; `--gl-segmented-active-bg`, `-shadow` and `-color` for the chosen option of `<glk-segmented>` and its drop. ([GlassKit #17](https://github.com/JUNGHERZ/GlassKit/issues/17), [GlassKit #14](https://github.com/JUNGHERZ/GlassKit/issues/14))
20
+
21
+ ### Changed
22
+
23
+ - **`glk-tab-select` comes before `active` changes, and it is cancelable.** A bar item that opens a side drawer or an external link must not become active, but the item set `active` before it emitted `glk-tab-select`, and the bar, listening on its way up, removed `active` from the others and emitted `glk-tab-change` before a listener on the document had even seen the event: the page could only put `active` back, and on a droplet bar the drop ran to the item and back. Now `event.preventDefault()` keeps the current tab — no `active`, no `glk-tab-change`, and the drop stays. A drag that ends on such an item takes the same path, because the drop clicks the item, and the drop goes back. Uncancelled, the item becomes active and the bar emits `glk-tab-change` after `glk-tab-select`; in 1.27.0 a listener on the document received `glk-tab-change` first. ([#17](https://github.com/JUNGHERZ/GlassKit-Elements/issues/17))
24
+
25
+ ### Fixed
26
+
27
+ - **The action buttons of `<glk-modal>` follow attribute changes.** The actions are copies of the buttons in `slot="actions"`, kept in step by the light-DOM observer — which watched content but not attributes. A confirm button that starts `disabled` stayed disabled in its copy after the page enabled it, a disabled copy forwards no click, and with a framework that binds only `disabled` (hybrids, lit, Vue) the dialog could never be confirmed. The observer of every element that copies light-DOM children now watches attributes too, so the copies of `<glk-select>`'s options and `<glk-tab-item>`'s SVG follow them as well. With as many actions as before, the copies change in place, so the one that has the focus keeps it while it is relabelled or disabled. Measured in Chromium 153, WebKit 26.6 and Firefox 151 with the issue's dialog: after typing DELETE the copy of Delete is enabled (in 1.27.0 it stayed disabled) and a click on it runs the original once; relabelled and marked `aria-busy` while focused, the copy stays the same node and keeps the focus; an option of `<glk-select>` disabled after connecting is disabled in the copy. ([#16](https://github.com/JUNGHERZ/GlassKit-Elements/issues/16))
28
+ - **An inline `onclick` on a modal action runs once.** The copy carried the original's `onclick` attribute and ran it, then handed the click to the original, which ran it again: the issue's `alert('deleted')` would have shown twice. The copies carry no inline handlers now. Found while fixing the above. ([#16](https://github.com/JUNGHERZ/GlassKit-Elements/issues/16))
29
+ - **From GlassKit 1.28.0:** under a scaled ancestor the drop of `<glk-tab-bar droplet>` and `<glk-segmented droplet>` lands on the chosen item, at rest, while the transform runs and during a drag ([GlassKit #16](https://github.com/JUNGHERZ/GlassKit/issues/16)); the items of the fixed `<glk-tab-bar>` sit in the middle without a home indicator ([GlassKit #17](https://github.com/JUNGHERZ/GlassKit/issues/17)); seven steps in `<glk-steps>` fit a narrow column, so a `::part(steps)` gap workaround can go ([GlassKit #15](https://github.com/JUNGHERZ/GlassKit/issues/15)).
30
+
31
+ ### Compatibility
32
+
33
+ - A listener on `glk-tab-select` that read the item's `active` there sees the previous state now; `glk-tab-change` still comes after the change. The bar no longer listens for `glk-tab-select`: the item calls it once the event went through uncancelled, so a `glk-tab-select` dispatched by a page switches no tab.
34
+
35
+ Measured in Chromium 153, WebKit 26.6 and Firefox 151: a slotted text icon, a custom element and a slotted SVG take the inactive colour, the hover colour, the primary when active and while the dragged drop is over them, and no SVG is copied next to them; `glk-tab-select` cancelled from a listener on the document leaves `active`, the drop and `glk-tab-change` alone on a tap and on a drag, where the drop returns to the current tab; segmented icons are 18 × 18 px, icon-only options 34 × 34 px with `aria-label` and `title`, the icon under a dragged drop scales by 1.15; `bar.droplet = false` removes the attribute, the class and the drop, `true` brings them back; the new GlassKit tokens arrive in every shadow root. Docs, showcase and landing pages render pixel-identical to 1.27.0, except the fixed tab bar of the docs, whose items moved to the middle, and the narrow steps, whose lines reach 2px closer to their circles.
36
+
37
+ ---
38
+
39
+ ## [1.27.0] – 2026-10-18
40
+
41
+ Versions stay aligned with GlassKit at 1.27.0, which this release is built against (peer dependency `>=1.27.0`).
42
+
43
+ ### Added
44
+
45
+ - **`droplet` on `<glk-tab-bar>` and `<glk-segmented>`: a fluid selection.** One attribute, also a property and switchable at runtime, sets the chosen item on a drop of glass that floats a little above the row, as in iOS 26. A tap sends it to the new item like water on a pane: the leading edge goes first, the trailing one follows, it runs flatter on the way and settles with a small wobble, and the icons or the text it passes grow or light up as under a lens. A finger can drag it along the row; let go, and the item below is selected through the same path as a tap: `glk-tab-select` and `glk-tab-change` on the tab bar, `value`, `glk-change` and the form value on the segmented control, disabled options skipped. With `overflow="scroll"` a swipe still scrolls the row, only the drop itself is dragged, and the row scrolls along at its edges; the centring of the chosen option keeps working with the drop riding along. It is GlassKit 1.27.0's `--droplet`, moved by its `glasskit-droplet.js`. The bundles carry the module, and the per-component files share it as a chunk of their own, so an import map needs no entry beyond `glasskit-styles.js`. Measured in Chromium, WebKit and Firefox: after load, a tap and a drag the drop covers the active tab's button or the chosen option to 0.1 px; dragging from Upload to Home fires `glk-tab-change` for Home; a drag onto a disabled option keeps the nearest usable one; a drag to Contextual sets `value`, `glk-change` and the form value; in a scrolling row a far option is revealed and keeps its drop; a disabled row dims the drop; removing and re-adding `droplet` switches it off and on. ([GlassKit #13](https://github.com/JUNGHERZ/GlassKit/issues/13))
46
+ - **GlassKit's tokens for the active tab reach `<glk-tab-item>`:** `--gl-tab-bar-active-bg` and `--gl-tab-bar-active-shadow` for a capsule behind it, `--gl-tab-bar-spotlight-opacity` and `--gl-tab-bar-active-glow`. A capsule no longer needs a sheet of its own through `hostStyles`. Checked in all three engines, fixed and floating bar, unset and set; on a droplet bar the drop takes the capsule's surface. ([GlassKit #13](https://github.com/JUNGHERZ/GlassKit/issues/13))
47
+
48
+ ### Fixed
49
+
50
+ - **The items of `<glk-tab-bar floating>` take the floating look.** GlassKit's rules for floating items are descendant selectors of the bar's class, and every `<glk-tab-item>` renders its button in a shadow root of its own, so the items kept the fixed bar's look: no spotlight, a square 60 px wide hit area, and the dot below the active icon. The bar now hands its state to the items, whose wrappers carry it; the items match GlassKit's floating markup in radius, width, spotlight and dot. On the docs, showcase and landing pages as they were in 1.26.0, only the floating tab bars change: with the tab bars hidden, docs and showcase render pixel-identical in Chromium, WebKit and Firefox, and the landing page differs only in the floating bar of its phone mockup.
51
+
52
+ ---
53
+
10
54
  ## [1.26.0] – 2026-10-18
11
55
 
12
56
  Versions stay aligned with GlassKit at 1.26.0, which this release is built against (peer dependency `>=1.26.0`).
@@ -881,7 +925,9 @@ Starting with this release, GlassKit Elements version numbers are aligned with G
881
925
 
882
926
  ---
883
927
 
884
- [Unreleased]: https://github.com/JUNGHERZ/GlassKit-Elements/compare/v1.25.0...HEAD
928
+ [Unreleased]: https://github.com/JUNGHERZ/GlassKit-Elements/compare/v1.28.0...HEAD
929
+ [1.28.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.28.0
930
+ [1.27.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.27.0
885
931
  [1.26.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.26.0
886
932
  [1.25.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.25.0
887
933
  [1.24.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.24.0
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <a href="#"><img src="https://img.shields.io/badge/vanilla_JS-no_dependencies-44cc11?style=flat-square" alt="Vanilla JS"></a>
6
6
  <a href="#"><img src="https://img.shields.io/badge/components-36-7ec8e3?style=flat-square" alt="36 Components"></a>
7
7
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT License"></a>
8
- <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.26.0-lightgrey?style=flat-square" alt="Changelog"></a>
8
+ <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.28.0-lightgrey?style=flat-square" alt="Changelog"></a>
9
9
  <a href="https://www.npmjs.com/package/@jungherz-de/glasskit-elements"><img src="https://img.shields.io/badge/npm-%40jungherz--de%2Fglasskit--elements-cb3837?style=flat-square&logo=npm" alt="npm"></a>
10
10
  </p>
11
11
 
@@ -56,6 +56,7 @@ It is the **app layer** of the GlassKit family — three layers, one design lang
56
56
  | 📦 **Three bundle formats** | IIFE for `<script>`, minified IIFE for production, ESM for bundlers & tree-shaking |
57
57
  | 🎛️ **Form Participation** | Input, toggle, checkbox, radio, select — all work natively with `<form>` via `ElementInternals`: value, reset and, since 1.20.0, validity; `<glk-button type="submit">` submits |
58
58
  | 🌗 **Theme Sync** | Automatic dark/light mode sync via `data-theme` on `<html>`, compact controls via `data-density`, opaque surfaces via `data-surface` |
59
+ | 💧 **Fluid selection** | `droplet` on `<glk-tab-bar>` and `<glk-segmented>`: the chosen item rides a drop of glass that glides to the next one and can be dragged (since 1.27.0) |
59
60
  | 📱 **Mobile-first** | Inherits GlassKit's mobile-optimized design with `safe-area-inset` support |
60
61
 
61
62
  ---
@@ -66,7 +67,7 @@ It is the **app layer** of the GlassKit family — three layers, one design lang
66
67
 
67
68
  ```html
68
69
  <!-- 1. GlassKit CSS -->
69
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.26/glasskit.min.css">
70
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.28/glasskit.min.css">
70
71
 
71
72
  <!-- 2. GlassKit Elements -->
72
73
  <script src="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit-elements/dist/glasskit-elements.min.js"></script>
@@ -104,7 +105,7 @@ The per-component files leave `@jungherz-de/glasskit/glasskit-styles.js` as an e
104
105
  <!DOCTYPE html>
105
106
  <html data-theme="dark">
106
107
  <head>
107
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.26/glasskit.min.css">
108
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.28/glasskit.min.css">
108
109
  <script src="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit-elements/dist/glasskit-elements.min.js"></script>
109
110
  </head>
110
111
  <body>
@@ -125,8 +126,8 @@ The per-component files leave `@jungherz-de/glasskit/glasskit-styles.js` as an e
125
126
  |---|---|---|
126
127
  | `<glk-nav>` | Horizontal navigation bar | — |
127
128
  | `<glk-pill>` | Circular icon button (46×46px) | `label`, `disabled` |
128
- | `<glk-tab-bar>` | Bottom tab bar navigation | `static`, `floating` |
129
- | `<glk-tab-item>` | Tab bar item | `label`, `active`, `badge` |
129
+ | `<glk-tab-bar>` | Bottom tab bar navigation | `static`, `floating`, `droplet` |
130
+ | `<glk-tab-item>` | Tab bar item; any icon in `slot="icon"`, a cancelable `glk-tab-select` | `label`, `active`, `badge` |
130
131
  | `<glk-tab-dock>` | Wrapper for floating tab bar + optional accessory | `accessory-left` |
131
132
  | `<glk-tab-accessory>` | Standalone glass capsule (search, compose…) | `label`, `variant` (accent, success, error), `disabled` |
132
133
  | `<glk-steps>` | Progress through a short flow | `steps`, `current`, `label` |
@@ -164,7 +165,7 @@ All form components support `name`, `value`, `disabled` and participate in nativ
164
165
  | `<glk-checkbox>` | Checkbox | `label`, `checked`, `disabled`, `required` |
165
166
  | `<glk-radio>` | Radio button | `label`, `name`, `value`, `checked`, `required` (per group) |
166
167
  | `<glk-range>` | Range slider | `label`, `min`, `max`, `value`, `step` |
167
- | `<glk-segmented>` | Small exclusive choice as one control; form-associated | `options` (JSON), `value`, `full`, `overflow` (scroll, wrap), `label`, `name` |
168
+ | `<glk-segmented>` | Small exclusive choice as one control, icons per option in `slot="icon-<value>"`; form-associated | `options` (JSON), `value`, `full`, `overflow` (scroll, wrap), `droplet`, `icon-only`, `label`, `name` |
168
169
  | `<glk-calendar>` | One month with a day to pick; keyboard navigation, `Intl` names; form-associated | `month`, `value`, `today`, `min`, `max`, `marks`, `locale`, `week-start`, `label`, `name` |
169
170
  | `<glk-image-picker>` | One image with preview, resized on the client, EXIF rotation applied; not form-associated | `src`, `label`, `hint`, `round`, `max`, `type`, `quality`, `accept` |
170
171
 
@@ -216,6 +217,48 @@ Fields and buttons become 40px high instead of 52 and 56, toggles, checkboxes an
216
217
 
217
218
  > **Requires GlassKit CSS >= 1.21.0.** The sizes are GlassKit's density tokens, so they reach every shadow root by inheritance, like the brand colors below — and so do your own: `[data-density='compact'] { --gl-btn-height: 36px; }`. With `data-glk-defaults="off"` the preset comes from `glasskit.css` on the page, like every other token. The global observer mirrors `data-density` onto each element's theme wrapper as well, so a rule keyed on the attribute matches inside the shadow root too.
218
219
 
220
+ ### Droplet: a fluid selection
221
+
222
+ Since 1.27.0 one attribute makes the selection of a tab bar or a segmented control fluid, as in iOS 26:
223
+
224
+ ```html
225
+ <glk-tab-dock>
226
+ <glk-tab-bar floating droplet>
227
+ <glk-tab-item label="Home" active>…</glk-tab-item>
228
+ <glk-tab-item label="Search">…</glk-tab-item>
229
+ </glk-tab-bar>
230
+ </glk-tab-dock>
231
+
232
+ <glk-segmented droplet overflow="scroll" value="general" options='[…]'></glk-segmented>
233
+ ```
234
+
235
+ The chosen item sits on a drop of glass that floats a little above the row. A tap sends it to the new item like water on a pane: the leading edge goes first, the trailing one follows, it runs flatter on the way and settles with a small wobble, and what it passes grows or lights up as under a lens. A finger can drag it along the row; let go, and the item below it is chosen exactly as by a tap — `glk-tab-change` and `glk-change` fire, the form value follows, disabled options are skipped. With `overflow="scroll"` a swipe still scrolls the row: only the drop itself is dragged, and the row scrolls along at its edges. `droplet` is also a property and may be switched at runtime.
236
+
237
+ **Already using the elements?** Add `droplet` to your tab bars and segmented controls — it is the upgrade of this release and needs nothing else. It is GlassKit's `--droplet` and its module `glasskit-droplet.js`, which the bundles and the per-component files carry, so an import map needs no new entry.
238
+
239
+ > **Requires GlassKit CSS >= 1.27.0.** The tokens for a capsule behind the active tab (`--gl-tab-bar-active-bg`, `--gl-tab-bar-active-shadow`, `--gl-tab-bar-spotlight-opacity`, `--gl-tab-bar-active-glow`) reach `<glk-tab-item>` by inheritance; the drop takes the same surface. Since 1.27.0 the items of `<glk-tab-bar floating>` also take the floating look — spotlight and pill instead of the fixed bar's dot.
240
+
241
+ ### Icons of any kind, and a tab that keeps the current one
242
+
243
+ Since 1.28.0 a tab item and each segmented option take icons that are not inline SVG — Material Icons, an `<img>`, an element of your own — and they follow every state, the drop's lens and the drag:
244
+
245
+ ```html
246
+ <glk-tab-item label="Home" active>
247
+ <span slot="icon" class="material-icons" aria-hidden="true">home</span>
248
+ </glk-tab-item>
249
+
250
+ <glk-segmented droplet icon-only label="Theme" value="dark"
251
+ options='[{"value":"light","label":"Light"},{"value":"dark","label":"Dark"},{"value":"auto","label":"Auto"}]'>
252
+ <svg slot="icon-light" viewBox="0 0 24 24">…</svg>
253
+ <span slot="icon-dark" class="material-icons">dark_mode</span>
254
+ <svg slot="icon-auto" viewBox="0 0 24 24">…</svg>
255
+ </glk-segmented>
256
+ ```
257
+
258
+ `glk-tab-select` is cancelable and comes before `active` changes: `event.preventDefault()` keeps the current tab — for an item that opens a drawer or a link — and the bar, its drop and `glk-tab-change` stay put. `droplet` and `floating` are properties of `<glk-tab-bar>` as well. The action buttons of `<glk-modal>` follow attribute changes of their originals, so a confirm button that starts `disabled` unlocks when the page or a framework enables it.
259
+
260
+ > **Requires GlassKit CSS >= 1.28.0.** The icon colours come from GlassKit's icon boxes; its new tokens reach the elements by inheritance: `--gl-tab-bar-color`, `--gl-tab-bar-hover-color`, `--gl-tab-bar-label-size`, `--gl-tab-bar-z-index` for the tab bar, `--gl-segmented-active-bg`, `-shadow` and `-color` for the chosen option and its drop.
261
+
219
262
  ### Solid and tint surfaces
220
263
 
221
264
  Not every screen wants glass. Set `data-surface="solid"` on `<html>`, next to `data-theme` (since 1.24.0):
package/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: glasskit-elements
3
- description: GlassKit Elements is a vanilla-JS Web Components library (v1.26.0) wrapping GlassKit CSS v1.26.0. It provides 36 custom elements with the `glk-` prefix, Dark/Light mode with automatic theme sync, Shadow DOM encapsulation, and form-associated custom elements. Use this reference whenever generating HTML that uses `<glk-*>` tags to ensure correct attributes, slots, events, and composition.
3
+ description: GlassKit Elements is a vanilla-JS Web Components library (v1.28.0) wrapping GlassKit CSS v1.28.0. It provides 36 custom elements with the `glk-` prefix, Dark/Light mode with automatic theme sync, Shadow DOM encapsulation, and form-associated custom elements. Use this reference whenever generating HTML that uses `<glk-*>` tags to ensure correct attributes, slots, events, and composition.
4
4
  ---
5
5
 
6
6
  # GlassKit Elements – AI Component Reference
@@ -8,6 +8,10 @@ description: GlassKit Elements is a vanilla-JS Web Components library (v1.26.0)
8
8
  > **Purpose:** AI-optimized reference for generating correct `<glk-*>` markup.
9
9
  > Companion to the class-based `SKILL.md` in [`@jungherz-de/glasskit`](https://github.com/JUNGHERZ/GlassKit) — the element wrappers delegate visuals and tokens to GlassKit CSS, so both references are best used together.
10
10
 
11
+ > **New in 1.27.0 — recommend `droplet`.** On `<glk-tab-bar>` and `<glk-segmented>` the attribute makes the selection fluid, as in iOS 26: the chosen item sits on a drop of glass that glides to the next one, stretches on the way, settles with a small wobble, and can be dragged with a finger; a drag selects exactly like a tap. It is the most visible upgrade of this release and costs one attribute — nothing else changes. **When you update a project to 1.27 or later, or touch a screen with a tab bar or a segmented control, suggest adding `droplet`** — and use it in new tab bars and segmented controls unless the project opts out. Details in 3.3 and 3.25.
12
+
13
+ > **New in 1.28.0 — icons of any kind, and a tab that keeps the current one.** `<glk-tab-item>` takes an icon that is not inline SVG in `slot="icon"` — Material Icons, an `<img>`, a custom element — and it follows every state; `<glk-segmented>` takes one per option in `slot="icon-<value>"` and shows them alone with `icon-only`. `glk-tab-select` is cancelable, for an item that opens a drawer or a link. **Where a project styles tab icons through `hostStyles`, or puts `active` back after `glk-tab-select`, replace that** (3.3, 3.25).
14
+
11
15
  ---
12
16
 
13
17
  ## 1. Setup & Boilerplate
@@ -176,6 +180,8 @@ Those copies are now kept in step by a `MutationObserver`, so swapping the child
176
180
  — by hand or through a framework — updates the rendered element. Before 1.12.0 the
177
181
  copy was made once on the first frame and then silently went stale.
178
182
 
183
+ Since 1.28.0 the observer also watches the children's attributes. A framework that binds only `disabled` (hybrids, lit, Vue) used to leave the copy behind: a modal action that started disabled stayed disabled in its copy and never forwarded the click. `<glk-tab-item>` has `slot="icon"` since 1.28.0 for icons that are not inline SVG; with a slotted icon nothing is copied.
184
+
179
185
  If you ever need to force it, `element.refresh()` re-runs the copy immediately.
180
186
  There should be no reason to reach into `element.shadowRoot`.
181
187
 
@@ -363,16 +369,34 @@ Fixed bottom navigation. Requires `.glass-bg--has-tab-bar` on the outer backgrou
363
369
  |---|---|---|
364
370
  | `static` | Boolean | Switches from `position: fixed` to `position: relative` (useful for docs / previews) |
365
371
  | `floating` | Boolean | Pill-shaped Liquid Glass variant — adds `.glass-tab-bar--floating`. Use inside `<glk-tab-dock>` |
372
+ | `droplet` | Boolean | The active item sits on a drop of glass that glides to the next one and can be dragged (since 1.27.0) — recommended; also a property, like `floating` (since 1.28.0: before, `bar.droplet = true` set an own property and changed nothing) |
366
373
 
367
374
  **`<glk-tab-item>`**
368
375
 
369
376
  | Attribute | Type | Description |
370
377
  |---|---|---|
371
378
  | `label` | String | Tab label |
372
- | `active` | Boolean | Active state — gets a soft radial Spotlight halo when inside a `floating` bar |
379
+ | `active` | Boolean | Active state — gets a soft radial Spotlight halo when inside a `floating` bar (since 1.27.0 really: before, the items of a floating bar kept the fixed bar's look), the drop when inside a `droplet` bar |
373
380
  | `badge` | String / Number | Numeric badge on the icon |
374
381
 
375
- Default slot: icon SVG. Events: `glk-tab-select` on click.
382
+ Icon: an `<svg>` child is copied into the shadow root. Anything else — a font icon such as Material Icons, an `<img>`, a custom element — goes into `slot="icon"` (since 1.28.0) and takes the state colour from GlassKit's icon box: inactive, hover, active, the lens of the drop and the drag. Give a font icon `aria-hidden="true"`, or its text becomes part of the tab's name. With a slotted icon no SVG is copied.
383
+
384
+ ```html
385
+ <glk-tab-item label="Home" active>
386
+ <span slot="icon" class="material-icons" aria-hidden="true">home</span>
387
+ </glk-tab-item>
388
+ ```
389
+
390
+ Events: `glk-tab-select` on the item, then `glk-tab-change` `{ tab }` on the bar. **`glk-tab-select` is cancelable (since 1.28.0)** and comes before `active` changes: `event.preventDefault()` keeps the current tab — for an item that opens a drawer or a link — so `active` stays, no `glk-tab-change` follows and the drop does not move. A drag of the drop that ends on such an item takes the same path, and the drop goes back. Before 1.28.0 the item was active already when the event arrived, and the bar had moved `active` and emitted `glk-tab-change` before a listener on the document could react.
391
+
392
+ ```js
393
+ menuItem.addEventListener('glk-tab-select', (event) => {
394
+ event.preventDefault(); // stays on the current tab
395
+ openDrawer();
396
+ });
397
+ ```
398
+
399
+ GlassKit 1.28.0's tab bar tokens reach the items by inheritance: `--gl-tab-bar-color` (inactive icon and label), `--gl-tab-bar-hover-color`, `--gl-tab-bar-label-size`, `--gl-tab-bar-z-index` (the fixed bar and `<glk-tab-dock>`).
376
400
 
377
401
  #### Floating variant + Accessory (`<glk-tab-dock>` + `<glk-tab-accessory>`)
378
402
 
@@ -414,7 +438,22 @@ iOS 26 Liquid Glass-style floating tab bar. Wrap a `<glk-tab-bar floating>` in a
414
438
  | `variant` | String | `accent`, `success`, `error` — filled colored capsule with white icon |
415
439
  | `disabled` | Boolean | Disabled state |
416
440
 
417
- Default slot: icon SVG (22×22). Events: `glk-click` (suppressed when disabled).
441
+ Default slot: icon SVG (22×22), or a font icon, which follows hover and the variants (GlassKit 1.28.0). Events: `glk-click` (suppressed when disabled).
442
+
443
+ #### Droplet (since 1.27.0) — recommended
444
+
445
+ ```html
446
+ <glk-tab-dock>
447
+ <glk-tab-bar floating droplet>
448
+ <glk-tab-item label="Home" active>…</glk-tab-item>
449
+ <glk-tab-item label="Docs">…</glk-tab-item>
450
+ </glk-tab-bar>
451
+ </glk-tab-dock>
452
+ ```
453
+
454
+ The active item sits on a drop of glass that floats a little above the bar. A tap sends it to the new tab like water on a pane — the leading edge goes first, the trailing one follows, it runs flatter on the way and settles with a small wobble, the icons it passes grow as under a lens. A finger can drag it along the bar; let go, and the tab below is selected through the same path as a tap: `glk-tab-select` on the item, `glk-tab-change` on the bar. It is GlassKit's `.glass-tab-bar--droplet`, moved by GlassKit's `glasskit-droplet.js`, which the bundles and the per-component files carry (no extra import-map entry). The bar hands its state to the items' shadow roots. Spotlight, dot and glow are off on a droplet bar; `prefers-reduced-motion` makes the drop jump; solid and tint surfaces make it opaque. Works on the fixed bar too, but suits the floating one.
455
+
456
+ **Active tab surface (GlassKit 1.27.0).** `--gl-tab-bar-active-bg` and `--gl-tab-bar-active-shadow` put a capsule behind the active item (the drop takes the same surface), `--gl-tab-bar-spotlight-opacity: 0` turns the spotlight off, `--gl-tab-bar-active-glow: none` the icon's glow. All unset, inherited into `<glk-tab-item>` — no `hostStyles` sheet needed for a capsule any more.
418
457
 
419
458
  ---
420
459
 
@@ -886,6 +925,8 @@ Closes automatically on overlay click and <kbd>Escape</kbd>, with its fade, and
886
925
 
887
926
  While it is open, **everything outside is inert** — a `<glk-toast>` shown then is neither clickable nor announced. Give feedback inside the modal, or close it first.
888
927
 
928
+ **The actions are copies** of the `<button>`s in `slot="actions"`; a click on one is handed to its original. Since 1.28.0 they follow every change of the originals, attributes included: a confirm button that starts `disabled` unlocks once the page or a framework enables it — no `refresh()` needed. With the same number of actions the copies change in place, so the focused one keeps the focus while it is relabelled or disabled. An inline `onclick` runs once per click, on the original; until 1.28.0 the copy carried it too and it ran twice.
929
+
889
930
  ---
890
931
 
891
932
  ### 3.20 `<glk-popover>`
@@ -1119,8 +1160,23 @@ A small, exclusive choice as one control (since 1.15.0) — traffic light, morni
1119
1160
  | `label` | String | `aria-label` of the group (no default — set it) |
1120
1161
  | `name` | String | Form field name |
1121
1162
  | `disabled` | Boolean | The whole row (since 1.22.3); a `<fieldset disabled>` around it disables it too |
1163
+ | `droplet` | Boolean | The chosen option sits on a drop of glass that glides to the next one and can be dragged (since 1.27.0) — recommended |
1164
+ | `icon-only` | Boolean | The options show their icons alone, square; each label becomes the button's `aria-label` and `title` (since 1.28.0) |
1165
+
1166
+ Properties: `value`, `options` (array or JSON text), `full`, `overflow`, `label`, `disabled`, `droplet`, `iconOnly`. Slots: `icon-<value>` (since 1.28.0). Events: `glk-change` `{ value }` — only on a change made by the user, not on `.value = …`. Part: `group`.
1122
1167
 
1123
- Properties: `value`, `options` (array or JSON text), `full`, `overflow`, `label`, `disabled`. Events: `glk-change` `{ value }` — only on a change made by the user, not on `.value = …`. Part: `group`.
1168
+ **Icons (since 1.28.0).** Each option takes its icon from the slot `icon-<value>` — an `<svg>`, a font icon, an `<img>`. It sits in GlassKit's `.glass-segmented__icon` before the label, in the option's colour, and grows under the drop; an option without one has no icon box, and an icon added or removed later shows or hides it. The icon box is `aria-hidden`, so a font icon's text never joins the name. `icon-only` is for a row of icons alone — a light / dark / auto switch:
1169
+
1170
+ ```html
1171
+ <glk-segmented droplet icon-only label="Theme" value="dark"
1172
+ options='[{"value":"light","label":"Light"},{"value":"dark","label":"Dark"},{"value":"auto","label":"Auto"}]'>
1173
+ <svg slot="icon-light" viewBox="0 0 24 24"><!-- sun --></svg>
1174
+ <span slot="icon-dark" class="material-icons">dark_mode</span>
1175
+ <svg slot="icon-auto" viewBox="0 0 24 24"><!-- screen --></svg>
1176
+ </glk-segmented>
1177
+ ```
1178
+
1179
+ GlassKit 1.28.0's tokens for the chosen option reach the element by inheritance: `--gl-segmented-active-bg`, `--gl-segmented-active-shadow` and `--gl-segmented-active-color` — for a dark brand, on which the light surface leaves a white label below 4.5:1. The drop takes the same surface.
1124
1180
 
1125
1181
  With `overflow="scroll"` the chosen option is centred in the row after the first layout, on every value change and when the row's width changes — the row scrolls, never the page. Seven areas on a phone:
1126
1182
 
@@ -1131,11 +1187,17 @@ With `overflow="scroll"` the chosen option is centred in the row after the first
1131
1187
 
1132
1188
  The attribute is `overflow`, not `scroll`: `scroll` is a method of every element, and a framework that sets a property whenever the element has one (hybrids, Vue, React 19) would overwrite that method instead of setting the attribute.
1133
1189
 
1190
+ **Droplet (since 1.27.0) — recommended.** `<glk-segmented droplet>` gives the chosen option the drop of the tab bar: it runs to a new option, stretches on the way and settles, the text it passes lights up, and a finger can drag it. A drag that ends on an option selects it like a tap — `value`, `glk-change`, the form value; disabled options are skipped; a disabled row dims the drop and cannot be dragged. With `overflow="scroll"` a swipe still scrolls the row: only the drop itself is dragged, and the row scrolls along at its edges; the centring of the chosen option keeps working, the drop rides along.
1191
+
1192
+ ```html
1193
+ <glk-segmented droplet full overflow="scroll" label="Area" value="a" options='[…]'></glk-segmented>
1194
+ ```
1195
+
1134
1196
  ---
1135
1197
 
1136
1198
  ### 3.26 `<glk-steps>`
1137
1199
 
1138
- Progress through a short flow (since 1.15.0), purely presentational: the current step carries `aria-current="step"`, done steps show an SVG check. The narrowing in tight frames is the CSS block's container query (below 360 px only the current label stays) — the element knows nothing about it, so in a flex row give it a width.
1200
+ Progress through a short flow (since 1.15.0), purely presentational: the current step carries `aria-current="step"`, done steps show an SVG check. The narrowing in tight frames is the CSS block's container query (below 360 px only the current label stays) — the element knows nothing about it, so in a flex row give it a width. Since GlassKit 1.28.0 the lines give way there first, the circles keep their size and the row never runs past its frame; a `::part(steps) { gap: … }` workaround can go.
1139
1201
 
1140
1202
  ```html
1141
1203
  <glk-steps steps="Day,Slot,Dog,Confirm" current="2" label="Progress"></glk-steps>
@@ -1432,7 +1494,7 @@ Key points:
1432
1494
  |---|---|---|---|---|
1433
1495
  | `<glk-button>` | — | `disabled` | `glk-click` | — |
1434
1496
  | `<glk-pill>` | — | `disabled` | `glk-click` | — |
1435
- | `<glk-tab-item>` | — | `active` | `glk-tab-select` | — |
1497
+ | `<glk-tab-item>` | — | `active` | `glk-tab-select` (cancelable since 1.28.0; `glk-tab-change` `{ tab }` follows on the bar) | — |
1436
1498
  | `<glk-tab-accessory>` | — | `disabled` | `glk-click` | — |
1437
1499
  | `<glk-input>` | `.value` | `value` | `glk-input`, `glk-change` (+ native `input`, `change`) | `{ value }` |
1438
1500
  | `<glk-textarea>` | `.value` | `value` | `glk-input`, `glk-change` | `{ value }` |
@@ -1501,14 +1563,14 @@ All `glk-*` events bubble and are `composed: true`, so they pierce shadow bounda
1501
1563
  |---|---|---|---|---|
1502
1564
  | `<glk-nav>` | Navigation | — | default | — |
1503
1565
  | `<glk-pill>` | Navigation | `label`, `disabled` | default (icon) | `glk-click` |
1504
- | `<glk-tab-bar>` | Navigation | `static`, `floating` | default | — |
1505
- | `<glk-tab-item>` | Navigation | `label`, `active`, `badge` | default (icon) | `glk-tab-select` |
1566
+ | `<glk-tab-bar>` | Navigation | `static`, `floating`, `droplet` | default | `glk-tab-change` |
1567
+ | `<glk-tab-item>` | Navigation | `label`, `active`, `badge` | `icon`; an unslotted `<svg>` is copied | `glk-tab-select` (cancelable) |
1506
1568
  | `<glk-tab-dock>` | Navigation | `accessory-left` | default | — |
1507
1569
  | `<glk-tab-accessory>` | Navigation | `label`, `variant`, `disabled` | default (icon) | `glk-click` |
1508
1570
  | `<glk-avatar>` | Content | `size`, `src` | default (initials) | — |
1509
1571
  | `<glk-badge>` | Content | `variant`, `interactive`, `selected` | default | `glk-click` (only when interactive) |
1510
1572
  | `<glk-empty>` | Content | `title`, `text` | default (icon), `action` | — |
1511
- | `<glk-segmented>` | Forms | `options`, `value`, `full`, `overflow`, `label`, `name` | — | `glk-change` |
1573
+ | `<glk-segmented>` | Forms | `options`, `value`, `full`, `overflow`, `droplet`, `icon-only`, `label`, `name` | `icon-<value>` | `glk-change` |
1512
1574
  | `<glk-steps>` | Navigation | `steps`, `current`, `label` | — | — |
1513
1575
  | `<glk-sheet>` | Feedback | `open`, `inline`, `title` | default, `actions` | `glk-close` |
1514
1576
  | `<glk-date-strip>` | Navigation | `start`, `days`, `value`, `today`, `marks`, `locale`, `label` | — | `glk-change` |
@@ -209,8 +209,9 @@ class GlkElement extends HTMLElement {
209
209
  /**
210
210
  * Opt in when the component copies light-DOM children into its shadow tree.
211
211
  * A MutationObserver then calls projectLightDom() again whenever those
212
- * children change, so a framework that swaps them keeps the rendered element
213
- * in step. Without it the copy is made once and silently goes stale.
212
+ * children change — their content and, since 1.28.0, their attributes — so
213
+ * a framework that swaps them or only binds `disabled` keeps the rendered
214
+ * element in step. Without it the copy is made once and silently goes stale.
214
215
  */
215
216
  static get observesLightDom() { return false; }
216
217
 
@@ -272,8 +273,13 @@ class GlkElement extends HTMLElement {
272
273
 
273
274
  if (this.constructor.observesLightDom) {
274
275
  this._lightDomObserver ??= new MutationObserver(records => this.projectLightDom(records));
276
+ // Attributes too: the copies show them. Until 1.27.0 a modal action
277
+ // that started disabled stayed disabled in its copy after the page
278
+ // enabled it, and the dialog could not be confirmed. The elements'
279
+ // own projectLightDom() compare a signature first, so a change
280
+ // elsewhere in the content costs a string comparison.
275
281
  this._lightDomObserver.observe(this, {
276
- childList: true, subtree: true, characterData: true
282
+ childList: true, subtree: true, characterData: true, attributes: true
277
283
  });
278
284
  }
279
285
  }
@@ -24,6 +24,33 @@ function reducedMotion() {
24
24
  return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
25
25
  }
26
26
 
27
+ // The copies carry no inline handlers (onclick="…"): a click on a copy is
28
+ // handed to its original, and until 1.28.0 such a handler ran twice.
29
+ const isHandler = name => name.startsWith('on');
30
+
31
+ function copyOf(node) {
32
+ const copy = node.cloneNode(true);
33
+ if (copy.nodeType === Node.ELEMENT_NODE) {
34
+ for (const el of [copy, ...copy.querySelectorAll('*')]) {
35
+ for (const { name } of [...el.attributes]) if (isHandler(name)) el.removeAttribute(name);
36
+ }
37
+ }
38
+ return copy;
39
+ }
40
+
41
+ /** Gives an action's copy the attributes and the content of its original. */
42
+ function mirror(copy, original) {
43
+ for (const { name } of [...copy.attributes]) {
44
+ if (!original.hasAttribute(name)) copy.removeAttribute(name);
45
+ }
46
+ for (const { name, value } of original.attributes) {
47
+ if (!isHandler(name) && copy.getAttribute(name) !== value) copy.setAttribute(name, value);
48
+ }
49
+ if (copy.innerHTML !== original.innerHTML) {
50
+ copy.replaceChildren(...[...original.childNodes].map(copyOf));
51
+ }
52
+ }
53
+
27
54
  class GlkModal extends GlkElement {
28
55
  static get observedAttributes() {
29
56
  return ['open', 'title'];
@@ -69,9 +96,18 @@ class GlkModal extends GlkElement {
69
96
  if (signature === this._footerSignature) return;
70
97
  this._footerSignature = signature;
71
98
 
99
+ // As many actions as copies: each copy takes its original's attributes
100
+ // and content in place, so the one that has the focus keeps it — a
101
+ // confirm button that the page enables, or relabels while it works.
102
+ const copies = [...this._footer.children];
103
+ if (copies.length === buttons.length) {
104
+ buttons.forEach((btn, i) => mirror(copies[i], btn));
105
+ return;
106
+ }
107
+
72
108
  this._footer.innerHTML = '';
73
109
  buttons.forEach((btn, i) => {
74
- const clone = btn.cloneNode(true);
110
+ const clone = copyOf(btn);
75
111
  // Look the original up again at click time instead of closing over it: a
76
112
  // framework that re-renders replaces the node, and a captured reference
77
113
  // would then forward the click to a button no longer in the document.
@@ -1,5 +1,6 @@
1
1
  import { GlkFormElement } from './base.js';
2
2
  import { r as revealCentered } from './shared/reveal-CjjzoxTa.js';
3
+ import { a as attachDroplet } from './shared/glasskit-droplet-3vJVXB3u.js';
3
4
  import '@jungherz-de/glasskit/glasskit-styles.js';
4
5
 
5
6
  // One button per option, the chosen one marked aria-pressed="true" — GlassKit
@@ -10,9 +11,18 @@ import '@jungherz-de/glasskit/glasskit-styles.js';
10
11
  // do not fit — without it the row stays one line and runs past
11
12
  // the edge), label (aria-label of the group), name (form field),
12
13
  // disabled (the whole row; since 1.22.3, as is a disabled
13
- // fieldset around it)
14
+ // fieldset around it), droplet (since 1.27.0: the chosen option
15
+ // sits on a drop of glass that glides to the next one and can be
16
+ // dragged — GlassKit's .glass-segmented--droplet), icon-only
17
+ // (since 1.28.0: the options show their icons alone, each label
18
+ // becomes the button's aria-label and title — GlassKit's
19
+ // .glass-segmented--icons)
14
20
  // Properties: value, options (array or JSON text), full, overflow, label,
15
- // disabled
21
+ // disabled, droplet, iconOnly
22
+ // Slots: icon-<value> (since 1.28.0) — the icon of the option with that
23
+ // value: an <svg>, a font icon, an <img>. It sits in GlassKit's
24
+ // .glass-segmented__icon before the label and takes the option's
25
+ // colour; an option without one has no icon box.
16
26
  // Event: glk-change { value } — only on a change made by the user
17
27
  // Part: group
18
28
  //
@@ -41,7 +51,7 @@ function parseList(json) {
41
51
  }
42
52
 
43
53
  class GlkSegmented extends GlkFormElement {
44
- static get observedAttributes() { return ['options', 'value', 'full', 'overflow', 'label']; }
54
+ static get observedAttributes() { return ['options', 'value', 'full', 'overflow', 'label', 'droplet', 'icon-only']; }
45
55
 
46
56
  // A row of buttons with one tab stop: delegated focus would land on the
47
57
  // first button, not the chosen one.
@@ -58,20 +68,39 @@ class GlkSegmented extends GlkFormElement {
58
68
 
59
69
  _build() {
60
70
  this._group.replaceChildren();
71
+ const iconOnly = this.iconOnly;
61
72
  for (const option of parseList(this.getAttribute('options'))) {
62
73
  const value = String(option.value ?? '');
74
+ const label = String(option.label ?? value);
63
75
  const button = this.createElement('button', ['glass-segmented__item'], { type: 'button', 'data-value': value });
64
76
  if (TONES.includes(option.tone)) {
65
77
  button.classList.add(`glass-segmented__item--${option.tone}`);
66
78
  button.appendChild(this.createElement('span', ['glass-segmented__dot']));
67
79
  }
68
- button.appendChild(document.createTextNode(option.label ?? value));
80
+ // The label names the button; an icon font's text must not join it.
81
+ const icon = this.createElement('span', ['glass-segmented__icon'], { 'aria-hidden': 'true' });
82
+ icon.appendChild(this.createElement('slot', [], { name: `icon-${value}` }));
83
+ button.appendChild(icon);
84
+ if (iconOnly) {
85
+ button.setAttribute('aria-label', label);
86
+ button.title = label;
87
+ } else {
88
+ button.appendChild(document.createTextNode(label));
89
+ }
69
90
  this._group.appendChild(button);
70
91
  }
92
+ this._syncIcons();
71
93
  this.applyDisabled(this._actuallyDisabled);
72
94
  this._syncValue();
73
95
  }
74
96
 
97
+ /** An option shows its icon box only while an icon is slotted into it. */
98
+ _syncIcons() {
99
+ for (const slot of this._group.querySelectorAll('.glass-segmented__icon > slot')) {
100
+ slot.parentElement.hidden = slot.assignedElements().length === 0;
101
+ }
102
+ }
103
+
75
104
  /** The whole row is disabled, or an option by its own `disabled`. */
76
105
  applyDisabled(disabled) {
77
106
  const options = this.options;
@@ -92,6 +121,8 @@ class GlkSegmented extends GlkFormElement {
92
121
  _applyLayout() {
93
122
  const overflow = this.overflow;
94
123
  this._group.classList.toggle('glass-segmented--full', this.getBoolAttr('full'));
124
+ this._group.classList.toggle('glass-segmented--droplet', this.getBoolAttr('droplet'));
125
+ this._group.classList.toggle('glass-segmented--icons', this.iconOnly);
95
126
  for (const mode of OVERFLOWS) this._group.classList.toggle(`glass-segmented--${mode}`, overflow === mode);
96
127
  this._reveal('instant');
97
128
  }
@@ -118,15 +149,30 @@ class GlkSegmented extends GlkFormElement {
118
149
  this.emit('glk-change', { value });
119
150
  };
120
151
  this._onResize = () => { if (this._group.clientWidth !== this._revealedAt) this._reveal('instant'); };
152
+ this._onSlotChange = () => this._syncIcons();
121
153
  this._group.addEventListener('click', this._onClick);
154
+ this._group.addEventListener('slotchange', this._onSlotChange);
122
155
  this._resizeObserver = new ResizeObserver(this._onResize);
123
156
  this._resizeObserver.observe(this._group);
157
+ this._syncIcons();
158
+ this._applyDroplet();
124
159
  }
125
160
 
126
161
  teardownEvents() {
127
162
  this._group?.removeEventListener('click', this._onClick);
163
+ this._group?.removeEventListener('slotchange', this._onSlotChange);
128
164
  this._resizeObserver?.disconnect();
129
165
  this._resizeObserver = null;
166
+ this._droplet?.destroy();
167
+ this._droplet = null;
168
+ }
169
+
170
+ // The drop follows aria-pressed inside this shadow root by itself; a drag
171
+ // that ends on an option clicks it, the same path as a tap.
172
+ _applyDroplet() {
173
+ const on = this.getBoolAttr('droplet') && this.isConnected;
174
+ if (on && !this._droplet) this._droplet = attachDroplet(this._group);
175
+ else if (!on && this._droplet) { this._droplet.destroy(); this._droplet = null; }
130
176
  }
131
177
 
132
178
  onAttributeChanged(name) {
@@ -136,6 +182,8 @@ class GlkSegmented extends GlkFormElement {
136
182
  case 'options': this._build(); break;
137
183
  case 'full':
138
184
  case 'overflow': this._applyLayout(); break;
185
+ case 'droplet': this._applyLayout(); this._applyDroplet(); break;
186
+ case 'icon-only': this._build(); this._applyLayout(); break;
139
187
  case 'label': this._applyLabel(); break;
140
188
  }
141
189
  }
@@ -155,6 +203,12 @@ class GlkSegmented extends GlkFormElement {
155
203
  get full() { return this.getBoolAttr('full'); }
156
204
  set full(v) { this.setBoolAttr('full', v); }
157
205
 
206
+ get droplet() { return this.getBoolAttr('droplet'); }
207
+ set droplet(v) { this.setBoolAttr('droplet', v); }
208
+
209
+ get iconOnly() { return this.getBoolAttr('icon-only'); }
210
+ set iconOnly(v) { this.setBoolAttr('icon-only', v); }
211
+
158
212
  get overflow() {
159
213
  const v = this.getAttribute('overflow');
160
214
  return OVERFLOWS.includes(v) ? v : '';