@jungherz-de/glasskit-elements 1.25.0 → 1.27.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 +29 -0
- package/README.md +36 -5
- package/SKILL.md +38 -4
- package/dist/components/glk-segmented.js +22 -3
- package/dist/components/glk-tab-bar.js +61 -1
- package/dist/components/glk-tab-item.js +22 -0
- package/dist/components/shared/glasskit-droplet-C3k1mxn4.js +217 -0
- package/dist/glasskit-elements.esm.js +322 -7
- package/dist/glasskit-elements.js +322 -7
- package/dist/glasskit-elements.min.js +1 -1
- package/package.json +3 -3
- package/src/components/forms/glk-segmented.js +22 -3
- package/src/components/navigation/glk-tab-bar.js +61 -1
- package/src/components/navigation/glk-tab-item.js +22 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.27.0] – 2026-10-18
|
|
11
|
+
|
|
12
|
+
Versions stay aligned with GlassKit at 1.27.0, which this release is built against (peer dependency `>=1.27.0`).
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`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))
|
|
17
|
+
- **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))
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **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.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [1.26.0] – 2026-10-18
|
|
26
|
+
|
|
27
|
+
Versions stay aligned with GlassKit at 1.26.0, which this release is built against (peer dependency `>=1.26.0`).
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **Primary-coloured text has a token of its own: `--gl-color-primary-text`.** GlassKit 1.26.0 separates the primary as text from the primary as fill. In the elements, the icon and label of the active `<glk-tab-item>`, `<glk-list-item variant="accent">`, the value of `<glk-range>`, the primary action of `<glk-modal>`, and the trigger on hover and the chevron of an open `<glk-accordion-item>` take it; buttons, toggles, steps and the chosen days of `<glk-date-strip>` and `<glk-calendar>` keep the primary. A brand that darkens its primary for white button text lightens the text in its dark theme without changing a button, and `--gl-tab-bar-active-color` colours the active tab alone. Both reach every shadow root by inheritance, also on a page that loads only these elements: the token blocks the bundle puts on the document declare `--gl-color-primary-text` in both themes. Measured in Chromium, WebKit and Firefox: set in the dark theme, both arrive in every element listed; in a nested `data-theme="light"` scope `--gl-color-primary-text` keeps the light primary; the fill of `<glk-button variant="primary">` stays as it was. ([GlassKit #12](https://github.com/JUNGHERZ/GlassKit/issues/12))
|
|
32
|
+
|
|
33
|
+
With the tokens unset, docs, showcase and landing pages render pixel-identical to 1.25.0 in Chromium, WebKit and Firefox.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
10
37
|
## [1.25.0] – 2026-10-16
|
|
11
38
|
|
|
12
39
|
Versions stay aligned with GlassKit at 1.25.0, which this release is built against (peer dependency `>=1.25.0`).
|
|
@@ -870,6 +897,8 @@ Starting with this release, GlassKit Elements version numbers are aligned with G
|
|
|
870
897
|
---
|
|
871
898
|
|
|
872
899
|
[Unreleased]: https://github.com/JUNGHERZ/GlassKit-Elements/compare/v1.25.0...HEAD
|
|
900
|
+
[1.27.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.27.0
|
|
901
|
+
[1.26.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.26.0
|
|
873
902
|
[1.25.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.25.0
|
|
874
903
|
[1.24.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.24.0
|
|
875
904
|
[1.23.0]: https://github.com/JUNGHERZ/GlassKit-Elements/releases/tag/v1.23.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.
|
|
8
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.27.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.
|
|
70
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.27/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.
|
|
108
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.27/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,7 +126,7 @@ 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-bar>` | Bottom tab bar navigation | `static`, `floating`, `droplet` |
|
|
129
130
|
| `<glk-tab-item>` | Tab bar item | `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` |
|
|
@@ -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; form-associated | `options` (JSON), `value`, `full`, `overflow` (scroll, wrap), `droplet`, `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,27 @@ 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
|
+
|
|
219
241
|
### Solid and tint surfaces
|
|
220
242
|
|
|
221
243
|
Not every screen wants glass. Set `data-surface="solid"` on `<html>`, next to `data-theme` (since 1.24.0):
|
|
@@ -278,6 +300,15 @@ inherits them — no JavaScript, no per-element setup:
|
|
|
278
300
|
> upgrading from ≤1.8.0 and already ship a brand stylesheet, expect your components to
|
|
279
301
|
> change to the colors you intended all along.
|
|
280
302
|
|
|
303
|
+
**Primary as text (GlassKit 1.26.0).** The active `<glk-tab-item>`, `<glk-list-item variant="accent">`, the value of `<glk-range>`, the primary action of `<glk-modal>` and `<glk-accordion-item>` draw text and line icons in `--gl-color-primary-text`, which is the primary unless you set it. A brand that darkens its primary for white button text lightens the text in its dark theme, and the buttons keep their colour — the light rule after the dark one, because `:root` matches a page in the light theme too:
|
|
304
|
+
|
|
305
|
+
```css
|
|
306
|
+
:root, [data-theme='dark'] { --gl-color-primary-text: color-mix(in srgb, var(--gl-color-primary) 18%, #ffffff); }
|
|
307
|
+
[data-theme='light'] { --gl-color-primary-text: var(--gl-color-primary); }
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
`--gl-tab-bar-active-color` colours the icon and label of the active tab alone; unset, they take `--gl-color-primary-text`.
|
|
311
|
+
|
|
281
312
|
Token defaults are placed on the document once, inside `@layer glasskit-defaults`, so
|
|
282
313
|
pages that never load `glasskit.css` still work and your brand file always wins.
|
|
283
314
|
|
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.
|
|
3
|
+
description: GlassKit Elements is a vanilla-JS Web Components library (v1.27.0) wrapping GlassKit CSS v1.27.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,8 @@ description: GlassKit Elements is a vanilla-JS Web Components library (v1.25.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
|
+
|
|
11
13
|
---
|
|
12
14
|
|
|
13
15
|
## 1. Setup & Boilerplate
|
|
@@ -18,7 +20,7 @@ description: GlassKit Elements is a vanilla-JS Web Components library (v1.25.0)
|
|
|
18
20
|
npm install @jungherz-de/glasskit-elements @jungherz-de/glasskit
|
|
19
21
|
```
|
|
20
22
|
|
|
21
|
-
Peer dependency `@jungherz-de/glasskit >=1.
|
|
23
|
+
Peer dependency `@jungherz-de/glasskit >=1.26.0` is required — 1.26.0 brings `--gl-color-primary-text` and `--gl-tab-bar-active-color` for primary-coloured text, 1.25.0 the tint surface preset and the toggle, radio and field tokens, 1.24.0 the solid surface preset behind `data-surface`, 1.23.0 lets list text wrap app-wide through tokens, 1.22.2 hands a click on a disabled control in an input affix to the field, 1.22.1 lets date and time fields shrink in narrow columns, 1.22.0 brings the input affixes behind the `prefix` / `suffix` slots, 1.21.2 gives disabled controls their look, 1.21.1 keeps the controls' state on paper, 1.21.0 brings the density tokens behind `data-density`, 1.20.0 the rules the elements build on since then (the dialog overlay, hidden list slots, empty control labels, control inputs on top); 1.9.0 is the release that made the stylesheet splittable, which is what lets document-level branding reach the elements at all.
|
|
22
24
|
|
|
23
25
|
### Import (ES modules)
|
|
24
26
|
|
|
@@ -202,6 +204,15 @@ inline on `<html>`. Every `<glk-*>` element inherits them:
|
|
|
202
204
|
No JavaScript, no `::part`, no per-element setup. Both `.glass-btn--primary` in the
|
|
203
205
|
document and `<glk-button variant="primary">` end up the same color.
|
|
204
206
|
|
|
207
|
+
**Primary as text (since 1.26.0, GlassKit 1.26.0).** Text and line icons in the primary take `--gl-color-primary-text`, which defaults to the primary: the icon and label of the active `<glk-tab-item>`, `<glk-list-item variant="accent">`, the value of `<glk-range>`, the primary action of `<glk-modal>` (`.glass-modal__action--primary`), and the trigger on hover and the chevron of an open `<glk-accordion-item>`. A brand that darkens its primary for white button text lightens the text in its dark theme without touching a button. Write the light rule after the dark one, because `:root` matches a page in the light theme too:
|
|
208
|
+
|
|
209
|
+
```css
|
|
210
|
+
:root, [data-theme='dark'] { --gl-color-primary-text: color-mix(in srgb, var(--gl-color-primary) 18%, #ffffff); }
|
|
211
|
+
[data-theme='light'] { --gl-color-primary-text: var(--gl-color-primary); }
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`--gl-tab-bar-active-color` colours the icon and label of the active tab alone (unset → `--gl-color-primary-text`); glow and dot stay in the primary, the spotlight in `--gl-tab-bar-spotlight-color`. Both tokens are inherited into the shadow roots, with or without `glasskit.css` on the page.
|
|
215
|
+
|
|
205
216
|
**This did not work before 1.9.0.** Up to and including 1.8.0 every element adopted the
|
|
206
217
|
full GlassKit sheet, whose `[data-theme]` blocks matched the element's own theme wrapper
|
|
207
218
|
and re-declared all tokens inside the shadow root. A matching rule beats an inherited
|
|
@@ -354,13 +365,14 @@ Fixed bottom navigation. Requires `.glass-bg--has-tab-bar` on the outer backgrou
|
|
|
354
365
|
|---|---|---|
|
|
355
366
|
| `static` | Boolean | Switches from `position: fixed` to `position: relative` (useful for docs / previews) |
|
|
356
367
|
| `floating` | Boolean | Pill-shaped Liquid Glass variant — adds `.glass-tab-bar--floating`. Use inside `<glk-tab-dock>` |
|
|
368
|
+
| `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 |
|
|
357
369
|
|
|
358
370
|
**`<glk-tab-item>`**
|
|
359
371
|
|
|
360
372
|
| Attribute | Type | Description |
|
|
361
373
|
|---|---|---|
|
|
362
374
|
| `label` | String | Tab label |
|
|
363
|
-
| `active` | Boolean | Active state — gets a soft radial Spotlight halo when inside a `floating` bar |
|
|
375
|
+
| `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 |
|
|
364
376
|
| `badge` | String / Number | Numeric badge on the icon |
|
|
365
377
|
|
|
366
378
|
Default slot: icon SVG. Events: `glk-tab-select` on click.
|
|
@@ -407,6 +419,21 @@ iOS 26 Liquid Glass-style floating tab bar. Wrap a `<glk-tab-bar floating>` in a
|
|
|
407
419
|
|
|
408
420
|
Default slot: icon SVG (22×22). Events: `glk-click` (suppressed when disabled).
|
|
409
421
|
|
|
422
|
+
#### Droplet (since 1.27.0) — recommended
|
|
423
|
+
|
|
424
|
+
```html
|
|
425
|
+
<glk-tab-dock>
|
|
426
|
+
<glk-tab-bar floating droplet>
|
|
427
|
+
<glk-tab-item label="Home" active>…</glk-tab-item>
|
|
428
|
+
<glk-tab-item label="Docs">…</glk-tab-item>
|
|
429
|
+
</glk-tab-bar>
|
|
430
|
+
</glk-tab-dock>
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
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.
|
|
434
|
+
|
|
435
|
+
**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.
|
|
436
|
+
|
|
410
437
|
---
|
|
411
438
|
|
|
412
439
|
### 3.4 `<glk-avatar>`
|
|
@@ -1110,8 +1137,9 @@ A small, exclusive choice as one control (since 1.15.0) — traffic light, morni
|
|
|
1110
1137
|
| `label` | String | `aria-label` of the group (no default — set it) |
|
|
1111
1138
|
| `name` | String | Form field name |
|
|
1112
1139
|
| `disabled` | Boolean | The whole row (since 1.22.3); a `<fieldset disabled>` around it disables it too |
|
|
1140
|
+
| `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 |
|
|
1113
1141
|
|
|
1114
|
-
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`.
|
|
1142
|
+
Properties: `value`, `options` (array or JSON text), `full`, `overflow`, `label`, `disabled`, `droplet`. Events: `glk-change` `{ value }` — only on a change made by the user, not on `.value = …`. Part: `group`.
|
|
1115
1143
|
|
|
1116
1144
|
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:
|
|
1117
1145
|
|
|
@@ -1122,6 +1150,12 @@ With `overflow="scroll"` the chosen option is centred in the row after the first
|
|
|
1122
1150
|
|
|
1123
1151
|
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.
|
|
1124
1152
|
|
|
1153
|
+
**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.
|
|
1154
|
+
|
|
1155
|
+
```html
|
|
1156
|
+
<glk-segmented droplet full overflow="scroll" label="Area" value="a" options='[…]'></glk-segmented>
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1125
1159
|
---
|
|
1126
1160
|
|
|
1127
1161
|
### 3.26 `<glk-steps>`
|
|
@@ -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-C3k1mxn4.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,11 @@ 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)
|
|
14
17
|
// Properties: value, options (array or JSON text), full, overflow, label,
|
|
15
|
-
// disabled
|
|
18
|
+
// disabled, droplet
|
|
16
19
|
// Event: glk-change { value } — only on a change made by the user
|
|
17
20
|
// Part: group
|
|
18
21
|
//
|
|
@@ -41,7 +44,7 @@ function parseList(json) {
|
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
class GlkSegmented extends GlkFormElement {
|
|
44
|
-
static get observedAttributes() { return ['options', 'value', 'full', 'overflow', 'label']; }
|
|
47
|
+
static get observedAttributes() { return ['options', 'value', 'full', 'overflow', 'label', 'droplet']; }
|
|
45
48
|
|
|
46
49
|
// A row of buttons with one tab stop: delegated focus would land on the
|
|
47
50
|
// first button, not the chosen one.
|
|
@@ -92,6 +95,7 @@ class GlkSegmented extends GlkFormElement {
|
|
|
92
95
|
_applyLayout() {
|
|
93
96
|
const overflow = this.overflow;
|
|
94
97
|
this._group.classList.toggle('glass-segmented--full', this.getBoolAttr('full'));
|
|
98
|
+
this._group.classList.toggle('glass-segmented--droplet', this.getBoolAttr('droplet'));
|
|
95
99
|
for (const mode of OVERFLOWS) this._group.classList.toggle(`glass-segmented--${mode}`, overflow === mode);
|
|
96
100
|
this._reveal('instant');
|
|
97
101
|
}
|
|
@@ -121,12 +125,23 @@ class GlkSegmented extends GlkFormElement {
|
|
|
121
125
|
this._group.addEventListener('click', this._onClick);
|
|
122
126
|
this._resizeObserver = new ResizeObserver(this._onResize);
|
|
123
127
|
this._resizeObserver.observe(this._group);
|
|
128
|
+
this._applyDroplet();
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
teardownEvents() {
|
|
127
132
|
this._group?.removeEventListener('click', this._onClick);
|
|
128
133
|
this._resizeObserver?.disconnect();
|
|
129
134
|
this._resizeObserver = null;
|
|
135
|
+
this._droplet?.destroy();
|
|
136
|
+
this._droplet = null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// The drop follows aria-pressed inside this shadow root by itself; a drag
|
|
140
|
+
// that ends on an option clicks it, the same path as a tap.
|
|
141
|
+
_applyDroplet() {
|
|
142
|
+
const on = this.getBoolAttr('droplet') && this.isConnected;
|
|
143
|
+
if (on && !this._droplet) this._droplet = attachDroplet(this._group);
|
|
144
|
+
else if (!on && this._droplet) { this._droplet.destroy(); this._droplet = null; }
|
|
130
145
|
}
|
|
131
146
|
|
|
132
147
|
onAttributeChanged(name) {
|
|
@@ -136,6 +151,7 @@ class GlkSegmented extends GlkFormElement {
|
|
|
136
151
|
case 'options': this._build(); break;
|
|
137
152
|
case 'full':
|
|
138
153
|
case 'overflow': this._applyLayout(); break;
|
|
154
|
+
case 'droplet': this._applyLayout(); this._applyDroplet(); break;
|
|
139
155
|
case 'label': this._applyLabel(); break;
|
|
140
156
|
}
|
|
141
157
|
}
|
|
@@ -155,6 +171,9 @@ class GlkSegmented extends GlkFormElement {
|
|
|
155
171
|
get full() { return this.getBoolAttr('full'); }
|
|
156
172
|
set full(v) { this.setBoolAttr('full', v); }
|
|
157
173
|
|
|
174
|
+
get droplet() { return this.getBoolAttr('droplet'); }
|
|
175
|
+
set droplet(v) { this.setBoolAttr('droplet', v); }
|
|
176
|
+
|
|
158
177
|
get overflow() {
|
|
159
178
|
const v = this.getAttribute('overflow');
|
|
160
179
|
return OVERFLOWS.includes(v) ? v : '';
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { GlkElement } from './base.js';
|
|
2
|
+
import { a as attachDroplet } from './shared/glasskit-droplet-C3k1mxn4.js';
|
|
2
3
|
import '@jungherz-de/glasskit/glasskit-styles.js';
|
|
3
4
|
|
|
5
|
+
// droplet (since 1.27.0): the active item sits on a drop of glass that glides
|
|
6
|
+
// to the next one and can be dragged — GlassKit's .glass-tab-bar--droplet,
|
|
7
|
+
// moved by its glasskit-droplet.js. The items live in shadow roots of their
|
|
8
|
+
// own, so the bar hands its state down to them (see glk-tab-item _syncBar)
|
|
9
|
+
// and tells the drop when the active item changed.
|
|
10
|
+
|
|
4
11
|
class GlkTabBar extends GlkElement {
|
|
5
12
|
static get observedAttributes() {
|
|
6
|
-
return ['static', 'floating'];
|
|
13
|
+
return ['static', 'floating', 'droplet'];
|
|
7
14
|
}
|
|
8
15
|
|
|
9
16
|
render() {
|
|
@@ -15,6 +22,7 @@ class GlkTabBar extends GlkElement {
|
|
|
15
22
|
if (this.getBoolAttr('floating')) {
|
|
16
23
|
nav.classList.add('glass-tab-bar--floating');
|
|
17
24
|
}
|
|
25
|
+
nav.classList.toggle('glass-tab-bar--droplet', this.getBoolAttr('droplet'));
|
|
18
26
|
|
|
19
27
|
if (this.getBoolAttr('static')) {
|
|
20
28
|
this._applyStatic();
|
|
@@ -27,6 +35,10 @@ class GlkTabBar extends GlkElement {
|
|
|
27
35
|
this._applyStatic();
|
|
28
36
|
} else if (name === 'floating') {
|
|
29
37
|
this._nav.classList.toggle('glass-tab-bar--floating', this.getBoolAttr('floating'));
|
|
38
|
+
this._syncItems();
|
|
39
|
+
} else if (name === 'droplet') {
|
|
40
|
+
this._nav.classList.toggle('glass-tab-bar--droplet', this.getBoolAttr('droplet'));
|
|
41
|
+
this._applyDroplet();
|
|
30
42
|
}
|
|
31
43
|
}
|
|
32
44
|
|
|
@@ -35,6 +47,42 @@ class GlkTabBar extends GlkElement {
|
|
|
35
47
|
this._nav.style.borderRadius = '16px';
|
|
36
48
|
}
|
|
37
49
|
|
|
50
|
+
_items() {
|
|
51
|
+
return [...this.children].filter(el => el.localName === 'glk-tab-item');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Hands the bar's floating and droplet state to every item's wrapper. */
|
|
55
|
+
_syncItems() {
|
|
56
|
+
const state = {
|
|
57
|
+
floating: this.getBoolAttr('floating'),
|
|
58
|
+
droplet: this.getBoolAttr('droplet'),
|
|
59
|
+
placed: Boolean(this._nav?.hasAttribute('data-droplet')),
|
|
60
|
+
drag: Boolean(this._nav?.hasAttribute('data-droplet-drag')),
|
|
61
|
+
};
|
|
62
|
+
for (const item of this._items()) item._syncBar?.(state);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Called by an item that rendered or changed its active state. */
|
|
66
|
+
_itemChanged() {
|
|
67
|
+
this._syncItems();
|
|
68
|
+
this._droplet?.update();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_applyDroplet() {
|
|
72
|
+
const on = this.getBoolAttr('droplet') && this.isConnected;
|
|
73
|
+
if (on && !this._droplet) {
|
|
74
|
+
// The drop measures and marks the items' own buttons; picking one clicks
|
|
75
|
+
// it, which is what a tap does.
|
|
76
|
+
this._droplet = attachDroplet(this._nav, {
|
|
77
|
+
items: () => this._items().map(item => item._btn).filter(Boolean),
|
|
78
|
+
});
|
|
79
|
+
} else if (!on && this._droplet) {
|
|
80
|
+
this._droplet.destroy();
|
|
81
|
+
this._droplet = null;
|
|
82
|
+
}
|
|
83
|
+
this._syncItems();
|
|
84
|
+
}
|
|
85
|
+
|
|
38
86
|
setupEvents() {
|
|
39
87
|
// Listen for tab selection events from child glk-tab-item elements
|
|
40
88
|
this._onTabSelect = (e) => {
|
|
@@ -48,10 +96,22 @@ class GlkTabBar extends GlkElement {
|
|
|
48
96
|
this.emit('glk-tab-change', { tab: e.target });
|
|
49
97
|
};
|
|
50
98
|
this.addEventListener('glk-tab-select', this._onTabSelect);
|
|
99
|
+
|
|
100
|
+
// The drop's state lives on the nav; the items carry it on their wrappers.
|
|
101
|
+
this._navObserver = new MutationObserver(() => this._syncItems());
|
|
102
|
+
this._navObserver.observe(this._nav, { attributes: true, attributeFilter: ['data-droplet', 'data-droplet-drag'] });
|
|
103
|
+
// Items added or removed.
|
|
104
|
+
this._itemObserver = new MutationObserver(() => this._itemChanged());
|
|
105
|
+
this._itemObserver.observe(this, { childList: true });
|
|
106
|
+
this._applyDroplet();
|
|
51
107
|
}
|
|
52
108
|
|
|
53
109
|
teardownEvents() {
|
|
54
110
|
this.removeEventListener('glk-tab-select', this._onTabSelect);
|
|
111
|
+
this._navObserver?.disconnect();
|
|
112
|
+
this._itemObserver?.disconnect();
|
|
113
|
+
this._droplet?.destroy();
|
|
114
|
+
this._droplet = null;
|
|
55
115
|
}
|
|
56
116
|
}
|
|
57
117
|
|
|
@@ -67,6 +67,27 @@ class GlkTabItem extends GlkElement {
|
|
|
67
67
|
this.emit('glk-tab-select');
|
|
68
68
|
};
|
|
69
69
|
this._btn.addEventListener('click', this._onClick);
|
|
70
|
+
this._tellBar();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The bar's look reaches the item through its wrapper. GlassKit's rules for
|
|
75
|
+
* floating and droplet items are descendant selectors of the bar's classes,
|
|
76
|
+
* and this button sits in a shadow root of its own, so <glk-tab-bar> hands
|
|
77
|
+
* its state down and the wrapper carries it. Before 1.27.0 the items of a
|
|
78
|
+
* floating bar kept the fixed bar's look: no spotlight, no pill, the dot.
|
|
79
|
+
*/
|
|
80
|
+
_syncBar({ floating, droplet, placed, drag }) {
|
|
81
|
+
if (!this._wrapper) return;
|
|
82
|
+
this._wrapper.classList.toggle('glass-tab-bar--floating', floating);
|
|
83
|
+
this._wrapper.classList.toggle('glass-tab-bar--droplet', droplet);
|
|
84
|
+
this._wrapper.toggleAttribute('data-droplet', placed);
|
|
85
|
+
this._wrapper.toggleAttribute('data-droplet-drag', drag);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Tells the bar that this item rendered or changed its active state. */
|
|
89
|
+
_tellBar() {
|
|
90
|
+
this.closest('glk-tab-bar')?._itemChanged?.();
|
|
70
91
|
}
|
|
71
92
|
|
|
72
93
|
teardownEvents() {
|
|
@@ -78,6 +99,7 @@ class GlkTabItem extends GlkElement {
|
|
|
78
99
|
switch (name) {
|
|
79
100
|
case 'active':
|
|
80
101
|
this._btn.classList.toggle('is-active', this.getBoolAttr('active'));
|
|
102
|
+
this._tellBar();
|
|
81
103
|
break;
|
|
82
104
|
case 'label':
|
|
83
105
|
this._labelEl.textContent = this.getAttribute('label') || '';
|