@jungherz-de/glasskit 1.19.1 → 1.21.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 +71 -1
- package/README.md +82 -13
- package/SKILL.md +107 -5
- package/glasskit-styles.js +4 -4
- package/glasskit.css +185 -70
- package/glasskit.min.css +2 -2
- package/glasskit.min.css.map +1 -1
- package/package.json +2 -2
- package/theme-override.css +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,74 @@ GlassKit uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.21.0] – 2026-10-05
|
|
11
|
+
|
|
12
|
+
Contributed as pull request [#5](https://github.com/JUNGHERZ/GlassKit/pull/5) by the product that is adopting GlassKit at full depth; GlassKit Elements 1.21.0 follows the attribute.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Density tokens for the control sizes, and a compact preset: `data-density="compact"`.** The heights of fields, buttons, toggles, checkboxes, radios, list rows and modal actions were px literals in the component rules, so a denser layout — an admin screen, a desktop form, a narrow column — had to override a dozen selectors and keep the toggle's thumb, its travel and the first-line alignment of the labels in step by hand. They are tokens now, declared next to the spacing tokens with the values GlassKit has always drawn and read with that value as fallback, as `--gl-modal-max-width` is; `data-density="compact"` on `<html>`, next to `data-theme`, swaps in a denser set, at load or at runtime:
|
|
17
|
+
|
|
18
|
+
| Token | Default | Compact |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `--gl-control-height` (input, select, search) | `52px` | `40px` |
|
|
21
|
+
| `--gl-control-padding-x` (input, select, textarea) | unset → `var(--gl-space-md)` | `var(--gl-space-sm)` |
|
|
22
|
+
| `--gl-btn-height` / `-sm` / `-lg` | `56px` / `44px` / `64px` | `40px` / `32px` / `48px` |
|
|
23
|
+
| `--gl-textarea-min-height` | `120px` | `88px` |
|
|
24
|
+
| `--gl-list-item-min-height` | `56px` | `48px` |
|
|
25
|
+
| `--gl-list-item-padding-y` | unset → `var(--gl-space-md)` | `10px` |
|
|
26
|
+
| `--gl-toggle-width` × `--gl-toggle-height` | `52px` × `30px` | `44px` × `26px` |
|
|
27
|
+
| `--gl-toggle-thumb-size` | `22px` | `18px` |
|
|
28
|
+
| `--gl-check-size` (checkbox, radio) | `24px` | `20px` |
|
|
29
|
+
| `--gl-modal-action-height` | `52px` | `44px` |
|
|
30
|
+
|
|
31
|
+
Only these tokens change; colours, type and spacing stay, so nothing outside the controls moves. The toggle's thumb sits `(height − thumb) / 2 − 1px` inside the track — 3 px at 52 × 30, where it has always sat — and travels `width − height`, from the right and to the left under `dir="rtl"`; the invisible inputs that lie on top of the controls since 1.20.0 take the same sizes, and the first-line offsets of toggle, checkbox and radio are computed from them. Any value a project sets therefore stays aligned. Two paddings join the heights because the heights alone would not have shown: a list row's 16 px top and bottom padding already makes a plain row 50 px tall, so a 48 px minimum needs `--gl-list-item-padding-y`; and a 40 px field reads better with 12 px inside (`--gl-control-padding-x`, which the textarea follows too, so stacked fields keep one text edge). Both are left unset by default, like `--gl-toast-top`: the rules fall back to `--gl-space-md` as before, so a spacing override still reaches them wherever it is declared. The select keeps its padding pair under `:dir(rtl)`: the token takes the text side, left to right on the left and right to left on the right, and the chevron's room stays with the chevron. The chevron, the search icon and the check and radio glyphs keep their sizes.
|
|
32
|
+
|
|
33
|
+
The preset is a bare attribute selector, like `[data-theme="light"]`, placed after the theme blocks, and the build puts it into `tokensCss` / `tokensSheet` with them. GlassKit Elements adopts only `componentsSheet` in its shadow roots and places the tokens on the document, so the compact values reach every element by inheritance — and so does a project's own `[data-density="compact"] { --gl-btn-height: 36px; }`, which a preset inside `componentsSheet` would have overridden in every shadow root. A `glassSheet` consumer whose shadow root holds an element with `data-theme` has to mirror `data-density` onto it as well, as GlassKit Elements does with its theme wrapper.
|
|
34
|
+
|
|
35
|
+
Measured in Chromium and WebKit (Playwright 1.63) against 1.20.0: without the attribute every one of these controls has the same size, padding, thumb position, input box, label offset and first-line centre as before, left to right and right to left, and full-page screenshots — a test page in both themes, this repository's index, showcase and docs in English and German — are pixel-identical, apart from regions that also differ between two renders of 1.20.0. With `data-density="compact"` on `<html>`, at load and switched at runtime: input, select and search 40 px with 12 px inner padding, buttons 40 / 32 / 48 px, the textarea 88 px, list rows 48 px with or without a 28 px icon (about 56 px with title and subtitle), the toggle 44 × 26 px with an 18 px thumb and the same gap at either end in both directions, checkbox and radio 20 px with their inputs on top, modal actions 44 px, every label still centred on its first line; under `dir="rtl"` the select's 12 px move to the right with the chevron on the left. Removing the attribute restores every value.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- `build-styles-js.mjs` splits three token blocks off instead of two — `:root, [data-theme="dark"]`, `[data-theme="light"]` and `[data-density="compact"]` — and fails if `tokensCss` lacks the preset or `componentsCss` declares a density token.
|
|
40
|
+
|
|
41
|
+
### Compatibility
|
|
42
|
+
|
|
43
|
+
- Without `data-density` nothing changes, and a stylesheet that lacks the new tokens — an older `tokensCss` next to this `componentsSheet` — gets the old sizes from the fallbacks.
|
|
44
|
+
- Like every token of the dark block, the size defaults are declared again by an element below `<html>` that carries `data-theme="dark"`; keep `data-density` on `<html>`, next to `data-theme`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## [1.20.0] – 2026-10-05
|
|
49
|
+
|
|
50
|
+
The first batch of findings filed as GitHub issues, from a product that is adopting GlassKit at full depth; GlassKit Elements 1.20.0 ships the matching element changes.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- **The select's chevron shows in the light theme.** It was an SVG with a fixed white stroke (`rgba(255,255,255,0.6)`) in both themes, so on light glass the arrow all but disappeared and the select no longer read as one. It is now the token `--gl-select-chevron`, set per theme: the dark theme keeps the same white stroke, the light theme draws it in its muted text colour, `rgba(26,42,54,0.55)`. The rule reads `var(--gl-select-chevron, …)` with the old image as fallback; a page replaces the arrow by setting the token to its own `url(…)`. Measured: docs and showcase render pixel-identical in the dark theme; in the light theme the chevron's 28 pixels are all that changes. ([#1](https://github.com/JUNGHERZ/GlassKit/issues/1))
|
|
55
|
+
- **A hidden list slot takes no room.** `.glass-list__leading { display: flex }` beat the user-agent rule for `[hidden]`, so a `<glk-list-item>` without an icon, which hides its empty leading slot, kept the 28 px box and its gap: title at 60 px instead of 20, row 60 px instead of 56. `.glass-list__leading[hidden]` and `.glass-list__trailing[hidden]` are now `display: none` — the same fix 1.16.0 made for `.glass-btn[hidden]` — and the divider rules look for a *visible* leading slot, so such a row's divider starts at 20 px like that of a row built without the slot. Measured in Chromium and WebKit: title 20 px, row 56 px, divider from 20 px. ([#4](https://github.com/JUNGHERZ/GlassKit/issues/4))
|
|
56
|
+
- **Toggle, checkbox and radio: the invisible input lies on top of its control.** With `pointer-events: none`, and painted below the track, box or circle, the input was covered — a test tool that clicks the control by its role (`getByRole('switch').click()`, `check()` in Playwright) found something else at the spot and timed out, and a pointer reached the input only by way of the label. It now has `z-index: 1` and takes the click itself. It covers exactly the track (52 × 30) or the box and circle (24 × 24), left to right, right to left and next to large text alike (measured offset: 0 px in Chromium and WebKit), and lines up with their first-line offset through the same `lh` margin; without `lh` support it keeps `margin: 0`, as the visuals do. The label text — a link in a consent label included — stays the label's: the link follows and the box stays unticked. Nothing changes visually; docs and showcase render pixel-identical. Found while moving `<glk-toggle>`'s switch role onto its input. (GlassKit Elements [#6](https://github.com/JUNGHERZ/glasskit-elements/issues/6))
|
|
57
|
+
- **An empty control label takes no room.** `.glass-toggle__label`, `.glass-checkbox__label` and `.glass-radio__label` are `display: none` while `:empty`, so a switch without text keeps no 12 px gap for one: 52 px wide instead of 64. (GlassKit Elements [#8](https://github.com/JUNGHERZ/glasskit-elements/issues/8))
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- **Right to left.** With `dir="rtl"` on `<html>` or a container, the components mirror. Paddings, insets and borders are logical properties now: label and hint padding, the search icon and the room kept for it, the toast's ×, the tab bar badge, the list dividers, the popover's `--start` and `--end` anchors, the line between modal actions, and the prose list indent and blockquote rule; accordion triggers, list rows, table headers and prose align to the start, `.glass-table__num` to the end. Pairs that must move together sit under `:dir(rtl)` — the select's chevron and its 40 px padding, the toggle's thumb and its travel, the popover's transform origin, the progress fill's gradient (turned with `scale: -1 1`, so its darker end still leads) — so a browser without `:dir()` (Chrome before 120) keeps them left to right instead of splitting them. Left to right nothing moves: docs and showcase render pixel-identical in both themes, apart from the light chevron above. Checked under `dir="rtl"` in Chromium and WebKit: chevron at 16 px from the left with the padding on its side, label and hint padding on the right, search icon on the right, thumb starting right and travelling left, rows without icon with title and divider at 20 px from the right, fill growing from the right. ([#2](https://github.com/JUNGHERZ/GlassKit/issues/2))
|
|
62
|
+
- **`--gl-modal-max-width`.** `.glass-modal` was capped by a literal 340 px, so a dialog with a form or a table could not grow on tablet or desktop without overriding the component rule. It reads `var(--gl-modal-max-width, 340px)` now, with the token in the `:root` block: `.settings-dialog { --gl-modal-max-width: 560px; }`. ([#3](https://github.com/JUNGHERZ/GlassKit/issues/3))
|
|
63
|
+
- **The modal overlay may be a native `<dialog>`.** Opened with `showModal()`, it lies in the top layer, the page behind it is inert for pointer, keyboard and screen readers, focus moves in and goes back to where it came from, and Escape closes it. `dialog.glass-modal-overlay` undoes the dialog's own box — size, margin, border, colour — keeps a closed dialog hidden (the overlay's `display: flex` would beat the user-agent rule) and makes its `::backdrop` transparent, because the overlay paints the dimmed, blurred layer itself; the `.is-active` fade works as before. While such a dialog is open, everything outside it is inert, a toast included: it is neither clickable nor announced. GlassKit Elements 1.20.0 builds `<glk-modal>` on it. (GlassKit Elements [#5](https://github.com/JUNGHERZ/glasskit-elements/issues/5))
|
|
64
|
+
|
|
65
|
+
### Documentation
|
|
66
|
+
|
|
67
|
+
- **Browser support in the README.** It still named Firefox 103 and "full" support elsewhere, but the token derivations use `color-mix()` since 1.11.0: the floor is Chrome and Edge 111, Safari 16.4, Firefox 113, Samsung Internet 22. Three refinements come later and fall back quietly — first-line alignment of toggle, checkbox and radio (`lh`, Firefox 120), the divider of rows without icon (`:has()`, Firefox 121), the right-to-left pairs (`:dir()`, Chrome 120). (GlassKit Elements [#9](https://github.com/JUNGHERZ/glasskit-elements/issues/9) asked for the check.)
|
|
68
|
+
- The docs pages counted 31 components and the package description 24; README, SKILL.md and the landing pages say 34, and now all of them do. Docs (English and German) and SKILL.md describe right to left, the dialog overlay, both tokens and the control inputs; `theme-override.css` has an example for the two tokens.
|
|
69
|
+
|
|
70
|
+
### Compatibility
|
|
71
|
+
|
|
72
|
+
- Pages under `dir="rtl"` that mirrored GlassKit with their own rules can drop them.
|
|
73
|
+
- A pointer click on a toggle, checkbox or radio now targets the input: listeners above it see one `click` (from the input) where they saw two (one from the track, box or circle, one from the input that the label then activated).
|
|
74
|
+
- A page that gave the select its own chevron through `background-image` keeps it; setting `--gl-select-chevron` is the simpler way now.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
10
78
|
## [1.19.1] – 2026-09-26
|
|
11
79
|
|
|
12
80
|
### Fixed
|
|
@@ -944,6 +1012,8 @@ during development. Version 1.3 is the first public open-source release.
|
|
|
944
1012
|
|
|
945
1013
|
---
|
|
946
1014
|
|
|
1015
|
+
[1.21.0]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.21.0
|
|
1016
|
+
[1.20.0]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.20.0
|
|
947
1017
|
[1.19.1]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.19.1
|
|
948
1018
|
[1.19.0]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.19.0
|
|
949
1019
|
[1.18.0]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.18.0
|
|
@@ -971,4 +1041,4 @@ during development. Version 1.3 is the first public open-source release.
|
|
|
971
1041
|
[1.3.2]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.3.2
|
|
972
1042
|
[1.3.1]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.3.1
|
|
973
1043
|
[1.3.0]: https://github.com/JUNGHERZ/GlassKit/releases/tag/v1.3.0
|
|
974
|
-
[Unreleased]: https://github.com/JUNGHERZ/GlassKit/compare/v1.
|
|
1044
|
+
[Unreleased]: https://github.com/JUNGHERZ/GlassKit/compare/v1.21.0...HEAD
|
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://img.shields.io/badge/version-1.
|
|
2
|
+
<img src="https://img.shields.io/badge/version-1.21.0-orange?style=flat-square" alt="Version">
|
|
3
3
|
<img src="https://img.shields.io/badge/CSS-only-blue?style=flat-square" alt="CSS only">
|
|
4
4
|
<img src="https://img.shields.io/badge/components-34-green?style=flat-square" alt="Components">
|
|
5
5
|
<img src="https://img.shields.io/badge/license-MIT-lightgrey?style=flat-square" alt="License">
|
|
6
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.
|
|
6
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.21.0-f5a623?style=flat-square" alt="Changelog"></a>
|
|
7
7
|
<a href="https://www.npmjs.com/package/@jungherz-de/glasskit"><img src="https://img.shields.io/npm/v/@jungherz-de/glasskit?style=flat-square&color=cb3837&label=npm" alt="npm"></a>
|
|
8
8
|
<a href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit/"><img src="https://img.shields.io/badge/CDN-jsDelivr-blue?style=flat-square" alt="jsDelivr"></a>
|
|
9
9
|
</p>
|
|
@@ -72,16 +72,16 @@ No download, no build tool – just include and go:
|
|
|
72
72
|
|
|
73
73
|
```html
|
|
74
74
|
<!-- jsDelivr – Minified -->
|
|
75
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.
|
|
75
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.21/glasskit.min.css">
|
|
76
76
|
|
|
77
77
|
<!-- jsDelivr – Unminified (for reading/debugging) -->
|
|
78
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.
|
|
78
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.21/glasskit.css">
|
|
79
79
|
|
|
80
80
|
<!-- unpkg – Alternative -->
|
|
81
|
-
<link rel="stylesheet" href="https://unpkg.com/@jungherz-de/glasskit@1.
|
|
81
|
+
<link rel="stylesheet" href="https://unpkg.com/@jungherz-de/glasskit@1.21/glasskit.min.css">
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
> **Tip:** Replace `@1.
|
|
84
|
+
> **Tip:** Replace `@1.21` with `@latest` for the newest version – or pin to a specific version for maximum stability.
|
|
85
85
|
|
|
86
86
|
### npm / yarn / pnpm
|
|
87
87
|
|
|
@@ -280,6 +280,44 @@ The `theme-override.css` template comes with **4 example themes**:
|
|
|
280
280
|
- 🌹 Rose
|
|
281
281
|
- 🎨 Custom (empty, ready to fill)
|
|
282
282
|
|
|
283
|
+
### Density
|
|
284
|
+
|
|
285
|
+
Admin screens, desktop layouts and narrow forms want denser controls. Set `data-density="compact"` on `<html>`, next to `data-theme`:
|
|
286
|
+
|
|
287
|
+
```html
|
|
288
|
+
<html data-theme="dark" data-density="compact">
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```js
|
|
292
|
+
// Switch at runtime
|
|
293
|
+
document.documentElement.setAttribute('data-density', 'compact');
|
|
294
|
+
document.documentElement.removeAttribute('data-density'); // back to the default
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Since **1.21.0** the control sizes are tokens, and the attribute swaps in a denser set. Without it every control keeps the size it has always had. Colours, type and spacing stay as they are, so nothing outside the controls moves:
|
|
298
|
+
|
|
299
|
+
| Token | Default | Compact |
|
|
300
|
+
|---|---|---|
|
|
301
|
+
| `--gl-control-height` (input, select, search) | `52px` | `40px` |
|
|
302
|
+
| `--gl-control-padding-x` (input, select, textarea) | unset → `var(--gl-space-md)` | `var(--gl-space-sm)` |
|
|
303
|
+
| `--gl-btn-height` / `-sm` / `-lg` | `56px` / `44px` / `64px` | `40px` / `32px` / `48px` |
|
|
304
|
+
| `--gl-textarea-min-height` | `120px` | `88px` |
|
|
305
|
+
| `--gl-list-item-min-height` | `56px` | `48px` |
|
|
306
|
+
| `--gl-list-item-padding-y` | unset → `var(--gl-space-md)` | `10px` |
|
|
307
|
+
| `--gl-toggle-width` × `--gl-toggle-height` | `52px` × `30px` | `44px` × `26px` |
|
|
308
|
+
| `--gl-toggle-thumb-size` | `22px` | `18px` |
|
|
309
|
+
| `--gl-check-size` (checkbox, radio) | `24px` | `20px` |
|
|
310
|
+
| `--gl-modal-action-height` | `52px` | `44px` |
|
|
311
|
+
|
|
312
|
+
Every token can also be set on its own, for one density or both — the toggle's thumb and the first-line alignment of toggle, checkbox and radio follow whatever size you give:
|
|
313
|
+
|
|
314
|
+
```css
|
|
315
|
+
:root { --gl-btn-height: 48px; } /* default density */
|
|
316
|
+
[data-density='compact'] { --gl-btn-height: 36px; } /* compact only */
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Like `data-theme`, keep `data-density` on `<html>`: an element further down that carries `data-theme="dark"` re-declares the dark block, the default sizes included.
|
|
320
|
+
|
|
283
321
|
---
|
|
284
322
|
|
|
285
323
|
## 🎛️ Design Tokens
|
|
@@ -308,9 +346,20 @@ All visual values are controlled via CSS Custom Properties:
|
|
|
308
346
|
/* Spacing */
|
|
309
347
|
--gl-space-xs … --gl-space-4xl
|
|
310
348
|
|
|
349
|
+
/* Density – control sizes, denser with data-density="compact" */
|
|
350
|
+
--gl-control-height /* 52px – input, select */
|
|
351
|
+
--gl-btn-height /* 56px; -sm 44px, -lg 64px */
|
|
352
|
+
--gl-check-size /* 24px – checkbox, radio */
|
|
353
|
+
--gl-toggle-width … --gl-modal-action-height
|
|
354
|
+
|
|
311
355
|
/* Shadows & Insets */
|
|
312
356
|
--gl-shadow-card
|
|
313
357
|
--gl-inset-strong
|
|
358
|
+
|
|
359
|
+
/* Component hooks */
|
|
360
|
+
--gl-modal-max-width /* 340px */
|
|
361
|
+
--gl-select-chevron /* url(…) per theme */
|
|
362
|
+
--gl-toast-top /* distance of the toast from the top */
|
|
314
363
|
```
|
|
315
364
|
|
|
316
365
|
The full token reference can be found in the [Documentation](docs.html).
|
|
@@ -432,6 +481,8 @@ Since CSS Custom Properties penetrate the shadow boundary, **theme switching wor
|
|
|
432
481
|
document.documentElement.setAttribute('data-theme', 'light');
|
|
433
482
|
```
|
|
434
483
|
|
|
484
|
+
`data-density="compact"` reaches the shadow roots the same way: the preset only sets tokens, and tokens cross the shadow boundary by inheritance.
|
|
485
|
+
|
|
435
486
|
> **Tip:** For maximum performance with many component instances, import `glassSheet` once and share it across all components. The browser keeps the stylesheet in memory only once.
|
|
436
487
|
|
|
437
488
|
---
|
|
@@ -520,14 +571,20 @@ Attach or reference `SKILL.md` when asking an AI to generate GlassKit HTML. It p
|
|
|
520
571
|
|
|
521
572
|
## 🌐 Browser Compatibility
|
|
522
573
|
|
|
523
|
-
|
|
574
|
+
The floor is set by `color-mix()`, which derives the brand, state and focus tokens on `:root` (since 1.11.0):
|
|
524
575
|
|
|
525
|
-
| Browser |
|
|
576
|
+
| Browser | Version |
|
|
526
577
|
|---|---|
|
|
527
|
-
|
|
|
528
|
-
|
|
|
529
|
-
| Firefox |
|
|
530
|
-
| Samsung Internet |
|
|
578
|
+
| Chrome / Edge | 111+ |
|
|
579
|
+
| Safari (iOS/macOS) | 16.4+ |
|
|
580
|
+
| Firefox | 113+ |
|
|
581
|
+
| Samsung Internet | 22+ |
|
|
582
|
+
|
|
583
|
+
A few refinements arrive later and fall back quietly where they are missing:
|
|
584
|
+
|
|
585
|
+
- The first-line alignment of toggle, checkbox and radio uses the `lh` unit (Firefox 120); without it the control sits at the top of its label.
|
|
586
|
+
- List rows without a leading icon move their divider in with `:has()` (Firefox 121); without it the divider keeps the icon inset.
|
|
587
|
+
- Right to left, the pairs that must move together — select chevron and padding, toggle thumb and travel, progress gradient — sit under `:dir(rtl)` (Chrome 120); without it they stay left to right.
|
|
531
588
|
|
|
532
589
|
> **Note:** In browsers without `backdrop-filter` support, elements will be rendered with the defined background colors – the UI remains usable, just without the blur effect.
|
|
533
590
|
|
|
@@ -536,6 +593,10 @@ GlassKit uses `backdrop-filter` for glass effects. Support:
|
|
|
536
593
|
## 📋 States & Modifiers – Cheat Sheet
|
|
537
594
|
|
|
538
595
|
```
|
|
596
|
+
Page Attributes (on <html>):
|
|
597
|
+
data-theme="dark" / "light"
|
|
598
|
+
data-density="compact" (denser controls)
|
|
599
|
+
|
|
539
600
|
Interactive States:
|
|
540
601
|
.is-active → Tab Bar item, Modal Overlay
|
|
541
602
|
.is-open → Accordion item, Popover
|
|
@@ -567,8 +628,13 @@ Toast Modifiers:
|
|
|
567
628
|
.glass-toast__action / __close (offer with a button)
|
|
568
629
|
--gl-toast-top (distance from the top)
|
|
569
630
|
|
|
570
|
-
Modal
|
|
631
|
+
Modal:
|
|
571
632
|
.glass-modal__action--primary / --danger
|
|
633
|
+
dialog.glass-modal-overlay (native <dialog>, opened with showModal())
|
|
634
|
+
--gl-modal-max-width (panel width, 340px unless set)
|
|
635
|
+
|
|
636
|
+
Select:
|
|
637
|
+
--gl-select-chevron (the chevron, per theme)
|
|
572
638
|
|
|
573
639
|
List Modifiers:
|
|
574
640
|
.glass-list--flush / --bare
|
|
@@ -616,6 +682,9 @@ Tab Bar – Floating:
|
|
|
616
682
|
.glass-tab-bar--floating
|
|
617
683
|
.glass-tab-bar__accessory
|
|
618
684
|
.glass-tab-bar__accessory--accent / --success / --error
|
|
685
|
+
|
|
686
|
+
Right to left:
|
|
687
|
+
dir="rtl" on <html> or a container – the components mirror
|
|
619
688
|
```
|
|
620
689
|
|
|
621
690
|
---
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: glasskit-css
|
|
3
|
-
description: GlassKit is a pure CSS glassmorphism component library (v1.
|
|
3
|
+
description: GlassKit is a pure CSS glassmorphism component library (v1.21.0) with 34 components, Dark & Light mode, design tokens, and BEM-like naming. Use this reference whenever generating HTML that uses GlassKit classes to ensure correct structure, nesting, modifiers, and token usage.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# GlassKit CSS – AI Component Reference
|
|
@@ -80,6 +80,25 @@ function toggleTheme() {
|
|
|
80
80
|
}
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
### Right to Left (since 1.20.0)
|
|
84
|
+
|
|
85
|
+
Set `dir="rtl"` on `<html>` or on any container; nothing else. Paddings, insets and borders
|
|
86
|
+
are logical properties, so labels, hints, the search icon, list dividers, popover anchors,
|
|
87
|
+
tab badges, modal actions, the toast's × and the text alignment of accordion, list, table
|
|
88
|
+
and prose mirror. Pairs that must move together — the select's chevron and its padding, the
|
|
89
|
+
toggle's thumb and its travel, the progress fill's gradient — are under `:dir(rtl)`
|
|
90
|
+
(Chrome 120+); an older browser keeps them left to right rather than splitting them.
|
|
91
|
+
|
|
92
|
+
### Density
|
|
93
|
+
|
|
94
|
+
Denser controls for admin screens, desktop layouts and narrow forms: `data-density="compact"` on `<html>`, next to `data-theme` (since 1.21.0).
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<html data-theme="dark" data-density="compact">
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Fields and buttons are 40px high instead of 52 and 56px; toggles, checkboxes, radios, list rows and modal actions shrink with them. Colours, type and spacing stay. Without the attribute nothing changes; `removeAttribute('data-density')` switches back at runtime. The values are the density tokens in section 2 — never shrink controls by overriding their `height`. It combines with `dir="rtl"`: the toggle's thumb and the select's padding mirror at either density.
|
|
101
|
+
|
|
83
102
|
---
|
|
84
103
|
|
|
85
104
|
## 2. Design Tokens
|
|
@@ -206,6 +225,28 @@ fully-translucent pre-1.7.0 chip.
|
|
|
206
225
|
| `--gl-space-3xl` | `40px` |
|
|
207
226
|
| `--gl-space-4xl` | `56px` |
|
|
208
227
|
|
|
228
|
+
### Density (since 1.21.0)
|
|
229
|
+
|
|
230
|
+
The control sizes. `data-density="compact"` on `<html>` switches to the second value column.
|
|
231
|
+
|
|
232
|
+
| Token | Default | Compact | Used by |
|
|
233
|
+
|---|---|---|---|
|
|
234
|
+
| `--gl-control-height` | `52px` | `40px` | `.glass-input`, `.glass-select` (and the search field) |
|
|
235
|
+
| `--gl-control-padding-x` | unset → `var(--gl-space-md)` | `var(--gl-space-sm)` | Inner left/right padding of input, select, textarea |
|
|
236
|
+
| `--gl-btn-height` | `56px` | `40px` | `.glass-btn` |
|
|
237
|
+
| `--gl-btn-height-sm` | `44px` | `32px` | `.glass-btn--sm` |
|
|
238
|
+
| `--gl-btn-height-lg` | `64px` | `48px` | `.glass-btn--lg` |
|
|
239
|
+
| `--gl-textarea-min-height` | `120px` | `88px` | `.glass-textarea` |
|
|
240
|
+
| `--gl-list-item-min-height` | `56px` | `48px` | `.glass-list__item` |
|
|
241
|
+
| `--gl-list-item-padding-y` | unset → `var(--gl-space-md)` | `10px` | `.glass-list__item`, top and bottom |
|
|
242
|
+
| `--gl-toggle-width` | `52px` | `44px` | `.glass-toggle__track` |
|
|
243
|
+
| `--gl-toggle-height` | `30px` | `26px` | `.glass-toggle__track` |
|
|
244
|
+
| `--gl-toggle-thumb-size` | `22px` | `18px` | `.glass-toggle__thumb` |
|
|
245
|
+
| `--gl-check-size` | `24px` | `20px` | `.glass-checkbox__box`, `.glass-radio__circle` |
|
|
246
|
+
| `--gl-modal-action-height` | `52px` | `44px` | `.glass-modal__action` |
|
|
247
|
+
|
|
248
|
+
The rules read each size with its default as fallback, like `--gl-modal-max-width`. The toggle's thumb inset and travel (in both directions) and the first-line alignment of toggle, checkbox and radio are derived from these, so any value stays aligned. The two paddings are unset by default and fall back to `--gl-space-md`, so a spacing override still reaches them. Set any token on `:root` for both densities, or on `[data-density="compact"]` for compact only.
|
|
249
|
+
|
|
209
250
|
### Shadows
|
|
210
251
|
|
|
211
252
|
| Token | Usage |
|
|
@@ -469,6 +510,8 @@ Full-width buttons (56px height) with three variants and size modifiers.
|
|
|
469
510
|
|
|
470
511
|
**Important:** Buttons default to `width: 100%`. Use `--auto` for inline/auto-width buttons.
|
|
471
512
|
|
|
513
|
+
**Heights** are density tokens: `--gl-btn-height`, `-sm`, `-lg` — 56 / 44 / 64px, or 40 / 32 / 48px with `data-density="compact"` on `<html>` (since 1.21.0).
|
|
514
|
+
|
|
472
515
|
**Icons:** Button SVGs need **no inline `fill`/`stroke` attributes** – GlassKit styles them automatically: outline style (`fill: none; stroke: currentColor; stroke-width: 2`, round caps/joins) as the default, `--secondary`/`--tertiary` use their icon tokens, `--primary` renders icons filled. For deliberately filled icons (e.g. brand logos like the GitHub mark) add `glass-icon--fill` to the `<svg>`.
|
|
473
516
|
|
|
474
517
|
**Links as buttons:** `.glass-btn` also works on `<a>` elements – anchors render as `inline-flex` with `text-decoration: none`, so `--auto` shrink-wraps exactly like on a real `<button>`.
|
|
@@ -598,7 +641,8 @@ Danger variant:
|
|
|
598
641
|
|---|---|
|
|
599
642
|
| `.glass-modal-overlay` | Fullscreen container with blur |
|
|
600
643
|
| `.glass-modal-overlay.is-active` | Visible + animated |
|
|
601
|
-
|
|
|
644
|
+
| `dialog.glass-modal-overlay` | The overlay as a native `<dialog>`, opened with `showModal()` (since 1.20.0) |
|
|
645
|
+
| `.glass-modal` | Dialog box, at most `--gl-modal-max-width` wide (340px unless set; since 1.20.0) |
|
|
602
646
|
| `.glass-modal__header` | Header area |
|
|
603
647
|
| `.glass-modal__title` | Title (20px, bold) |
|
|
604
648
|
| `.glass-modal__body` | Content area |
|
|
@@ -618,6 +662,43 @@ document.querySelector('.glass-modal-overlay').classList.add('is-active');
|
|
|
618
662
|
document.querySelector('.glass-modal-overlay').classList.remove('is-active');
|
|
619
663
|
```
|
|
620
664
|
|
|
665
|
+
**Prefer a native `<dialog>` (since 1.20.0).** Opened with `showModal()` it lies in the top
|
|
666
|
+
layer, the page behind it is inert (pointer, keyboard, screen readers), focus moves in and
|
|
667
|
+
returns on close, and Escape closes it. GlassKit resets the dialog's own box and backdrop:
|
|
668
|
+
|
|
669
|
+
```html
|
|
670
|
+
<dialog class="glass-modal-overlay" id="confirm" aria-labelledby="confirm-title">
|
|
671
|
+
<div class="glass-modal">
|
|
672
|
+
<div class="glass-modal__header">
|
|
673
|
+
<h2 class="glass-modal__title" id="confirm-title">Delete contract?</h2>
|
|
674
|
+
</div>
|
|
675
|
+
<div class="glass-modal__body"><p>This action cannot be undone.</p></div>
|
|
676
|
+
<div class="glass-modal__footer">
|
|
677
|
+
<button class="glass-modal__action" onclick="closeDialog()">Cancel</button>
|
|
678
|
+
<button class="glass-modal__action glass-modal__action--danger">Delete</button>
|
|
679
|
+
</div>
|
|
680
|
+
</div>
|
|
681
|
+
</dialog>
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
```js
|
|
685
|
+
const dialog = document.getElementById('confirm');
|
|
686
|
+
function openDialog() {
|
|
687
|
+
dialog.showModal();
|
|
688
|
+
void dialog.offsetHeight; // compute the closed state first,
|
|
689
|
+
dialog.classList.add('is-active'); // so the fade runs
|
|
690
|
+
}
|
|
691
|
+
function closeDialog() {
|
|
692
|
+
dialog.classList.remove('is-active');
|
|
693
|
+
setTimeout(() => dialog.close(), 300); // after the fade
|
|
694
|
+
}
|
|
695
|
+
dialog.addEventListener('cancel', (e) => { e.preventDefault(); closeDialog(); }); // Escape fades too
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
While a modal dialog is open everything outside it is inert — a toast shown then is neither
|
|
699
|
+
clickable nor announced; give feedback inside the dialog. Wider dialogs (forms, tables):
|
|
700
|
+
`.my-dialog { --gl-modal-max-width: 560px; }`.
|
|
701
|
+
|
|
621
702
|
---
|
|
622
703
|
|
|
623
704
|
### 3.13 Toast
|
|
@@ -734,6 +815,10 @@ Dropdown with glass styling and custom chevron.
|
|
|
734
815
|
|---|---|
|
|
735
816
|
| `.glass-select` | Styled dropdown |
|
|
736
817
|
|
|
818
|
+
The chevron is the token `--gl-select-chevron` — an SVG `url(…)` in each theme's muted text
|
|
819
|
+
colour (since 1.20.0; before, it stayed white in the light theme). Override it with your own
|
|
820
|
+
`url(…)`. Right to left, chevron and padding move to the left.
|
|
821
|
+
|
|
737
822
|
---
|
|
738
823
|
|
|
739
824
|
### 3.17 Search
|
|
@@ -753,7 +838,7 @@ Search field with embedded search icon.
|
|
|
753
838
|
| Class | Description |
|
|
754
839
|
|---|---|
|
|
755
840
|
| `.glass-search` | Wrapper (position: relative) |
|
|
756
|
-
| `.glass-search__icon` | Positioned search icon (left) |
|
|
841
|
+
| `.glass-search__icon` | Positioned search icon (inline start — left, or right under `dir="rtl"`) |
|
|
757
842
|
|
|
758
843
|
**Important:** The input inside `.glass-search` uses the regular `.glass-input` class.
|
|
759
844
|
|
|
@@ -783,6 +868,12 @@ iOS-style switch.
|
|
|
783
868
|
|
|
784
869
|
**State:** `:checked` on the input activates the toggle visually.
|
|
785
870
|
|
|
871
|
+
The input is invisible but lies **on top of** the track and takes the click itself (since
|
|
872
|
+
1.20.0) — a test tool clicking the switch by role (`getByRole('switch')` with
|
|
873
|
+
`role="switch"` on the input) reaches it. It covers only the track; label text, links in it
|
|
874
|
+
included, stays the label's. An empty `__label` takes no room (no 12px gap). Both apply to
|
|
875
|
+
checkbox and radio as well.
|
|
876
|
+
|
|
786
877
|
---
|
|
787
878
|
|
|
788
879
|
### 3.19 Checkbox
|
|
@@ -1050,7 +1141,8 @@ iOS-style grouped settings list. Items can carry a leading icon, a title with op
|
|
|
1050
1141
|
|
|
1051
1142
|
**Notes:**
|
|
1052
1143
|
- Dividers are auto-rendered via `::after`. The last item never has a divider.
|
|
1053
|
-
- Items **with** a `__leading` slot get an icon-aligned divider inset; items **without** a
|
|
1144
|
+
- Items **with** a `__leading` slot get an icon-aligned divider inset; items **without** one — or with a `__leading` that carries the `hidden` attribute (since 1.20.0) — get the standard padding inset (handled via `:has()`). Large leading (`--lg`) adjusts the divider inset automatically.
|
|
1145
|
+
- A `__leading` or `__trailing` with `hidden` takes no room (since 1.20.0; `display: flex` used to beat the attribute).
|
|
1054
1146
|
- SVG icon convention: `24px` for leading (32px for `--lg`), `18px` for trailing, `stroke: currentColor`, `stroke-width: 2`.
|
|
1055
1147
|
- Use `<ul>` + `<li>` for semantic lists. For interactive rows wrap in `<a>` or `<button>` instead of `<li>` if a single-row list is needed.
|
|
1056
1148
|
- `.glass-list__section-header` sits **outside** the `.glass-list` container, directly above it.
|
|
@@ -1826,6 +1918,7 @@ Key points in this composition:
|
|
|
1826
1918
|
7. **`data-theme`** – Always set on `<html>`, never on `<body>` or deeper elements.
|
|
1827
1919
|
8. **List dividers are automatic** – Never add a `<hr>` or divider element between `.glass-list__item`s. The divider is rendered via `::after` and respects `:has(.glass-list__leading)` for the inset.
|
|
1828
1920
|
9. **Popover toggle naming** – Never name your popover toggle JS function `togglePopover`. It collides with the native `HTMLElement.togglePopover()` method. Use a prefix like `gkTogglePopover`.
|
|
1921
|
+
10. **`data-density`** – Like `data-theme`, on `<html>`: `compact` or absent. For a denser UI set the attribute or a density token, never `height` on the components.
|
|
1829
1922
|
|
|
1830
1923
|
### ❌ Common Mistakes
|
|
1831
1924
|
|
|
@@ -1842,6 +1935,7 @@ Key points in this composition:
|
|
|
1842
1935
|
| Putting `glass-list` inside `glass-popover` without `--bare` | Add `.glass-list--bare` to strip the double glass surface |
|
|
1843
1936
|
| JS function named `togglePopover()` | Rename to `gkTogglePopover()` or similar to avoid native API clash |
|
|
1844
1937
|
| Putting `.is-open` on the trigger button instead of `.glass-popover` | The state class belongs on the popover element |
|
|
1938
|
+
| Overriding `height` of `.glass-btn`, `.glass-input` etc. for a denser UI | `data-density="compact"` on `<html>`, or set a density token — toggle thumb and label alignment follow the tokens, not a hand-set `height` |
|
|
1845
1939
|
|
|
1846
1940
|
---
|
|
1847
1941
|
|
|
@@ -1919,7 +2013,7 @@ customElements.define('my-card', MyCard);
|
|
|
1919
2013
|
| `css` | `string` | The same, as a string |
|
|
1920
2014
|
| `componentsSheet` | `CSSStyleSheet` | Component rules only, no token declarations (since 1.9.0) |
|
|
1921
2015
|
| `componentsCss` | `string` | The same, as a string |
|
|
1922
|
-
| `tokensSheet` | `CSSStyleSheet` | Only the two `[data-theme]` blocks
|
|
2016
|
+
| `tokensSheet` | `CSSStyleSheet` | Only the blocks that declare `--gl-*`: the two `[data-theme]` blocks (since 1.9.0) and the `[data-density="compact"]` preset (since 1.21.0) |
|
|
1923
2017
|
| `tokensCss` | `string` | The same, as a string |
|
|
1924
2018
|
|
|
1925
2019
|
CSS Custom Properties (`--gl-*`) cross the shadow boundary by inheritance, so the example
|
|
@@ -1930,6 +2024,7 @@ above picks up whatever the document defines and theme switching works globally.
|
|
|
1930
2024
|
> element carrying `data-theme`, that selector matches it and re-declares every token
|
|
1931
2025
|
> locally — and a matching rule always beats an inherited value. A project's
|
|
1932
2026
|
> `:root { --gl-color-primary: … }` then silently stops arriving inside your component.
|
|
2027
|
+
> The dark block declares the default control sizes too, so `<html data-density="compact">` stops arriving as well — unless that element carries `data-density` mirrored from `<html>`, which lets the compact preset (also in the full sheet) match it.
|
|
1933
2028
|
>
|
|
1934
2029
|
> If you need a themed element inside the shadow root, adopt `componentsSheet` instead
|
|
1935
2030
|
> and make sure the tokens are present on the document:
|
|
@@ -2002,6 +2097,13 @@ Overriding `--gl-color-success` / `--gl-color-error` is enough on its own: fill,
|
|
|
2002
2097
|
text and glow of every state component are derived from those tokens. Only if you want
|
|
2003
2098
|
a different ink than the derived one do you need to touch `--gl-color-{state}-on-surface`.
|
|
2004
2099
|
|
|
2100
|
+
The density tokens (section 2) are overridden the same way, for both densities or for compact only:
|
|
2101
|
+
|
|
2102
|
+
```css
|
|
2103
|
+
:root { --gl-btn-height: 48px; }
|
|
2104
|
+
[data-density='compact'] { --gl-btn-height: 36px; }
|
|
2105
|
+
```
|
|
2106
|
+
|
|
2005
2107
|
Included theme templates in `theme-override.css`:
|
|
2006
2108
|
- 🔵 Ocean Blue
|
|
2007
2109
|
- 🟢 Emerald Green
|