@gjsify/adwaita-web 0.21.0 → 0.22.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-web",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Adwaita/Libadwaita web components for browser targets",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -41,13 +41,13 @@
41
41
  "@codemirror/language": "^6.12.4",
42
42
  "@codemirror/state": "^6.7.0",
43
43
  "@codemirror/view": "^6.43.4",
44
- "@gjsify/adwaita-fonts": "^0.21.0",
45
- "@gjsify/adwaita-icons": "^0.21.0",
44
+ "@gjsify/adwaita-fonts": "^0.22.0",
45
+ "@gjsify/adwaita-icons": "^0.22.0",
46
46
  "@lezer/highlight": "^1.2.3"
47
47
  },
48
48
  "devDependencies": {
49
- "@gjsify/cli": "^0.21.0",
50
- "@gjsify/unit": "^0.21.0",
49
+ "@gjsify/cli": "^0.22.0",
50
+ "@gjsify/unit": "^0.22.0",
51
51
  "sass": "^1.101.0",
52
52
  "typescript": "^6.0.3"
53
53
  },
@@ -0,0 +1,69 @@
1
+ // _reset.scss — style-isolation boundary for embedding in arbitrary host pages.
2
+ //
3
+ // adwaita-web renders as LIGHT-DOM custom elements (by design: the widgets
4
+ // compose with the page and stay overridable via the `--adw-*` / `--*` design
5
+ // tokens). The trade-off of light DOM is that a host page's *inherited*
6
+ // typography — `font-family`, `color`, `line-height`, `letter-spacing`, … — and
7
+ // generic element resets can leak into the widgets.
8
+ //
9
+ // This partial establishes an Adwaita typographic + box-model context at EVERY
10
+ // component boundary, so inheritance from the host stops at the widget. It sets
11
+ // only a FLOOR: it is `@use`d before the component partials, so each component's
12
+ // own rules override it, and consumers keep full control through the tokens and
13
+ // ordinary higher-specificity rules (isolation without giving up overriding).
14
+ //
15
+ // The box battles (borders, backgrounds) are already won by the components'
16
+ // class-scoped rules against realistic element-level host CSS; the real leak is
17
+ // inherited typography + a host `* {}` box-sizing reset, which is what this
18
+ // neutralises.
19
+
20
+ // Every custom element adwaita-web defines. Keep in sync with
21
+ // `src/elements/*` (the `customElements.define('adw-…')` calls).
22
+ $adw-components:
23
+ adw-about-dialog, adw-action-row, adw-alert-dialog, adw-alert-response,
24
+ adw-avatar, adw-banner, adw-bottom-sheet, adw-bottom-sheet-content,
25
+ adw-bottom-sheet-sheet, adw-button, adw-button-content, adw-button-row,
26
+ adw-card, adw-carousel, adw-carousel-indicator-dots,
27
+ adw-carousel-indicator-lines, adw-clamp, adw-combo-row, adw-data-grid,
28
+ adw-dialog, adw-drop-down, adw-entry, adw-entry-row, adw-expander-row,
29
+ adw-header-bar, adw-inline-view-switcher, adw-menu-button, adw-navigation-page,
30
+ adw-navigation-split-view, adw-navigation-view, adw-overlay-split-view,
31
+ adw-password-entry-row, adw-preferences-dialog, adw-preferences-group,
32
+ adw-preferences-page, adw-sidebar, adw-sidebar-item, adw-sidebar-section,
33
+ adw-spinner, adw-spin-row, adw-split-button, adw-status-page, adw-switch-row,
34
+ adw-tab-page, adw-tab-view, adw-toast-overlay, adw-toggle, adw-toggle-group,
35
+ adw-toolbar-view, adw-view-stack, adw-view-stack-page, adw-view-switcher,
36
+ adw-view-switcher-bar, adw-view-switcher-page, adw-window, adw-window-title,
37
+ adw-wrap-box;
38
+
39
+ // Roots: re-root the inherited typographic properties (and the box model) so a
40
+ // host page's font / colour / spacing cannot flow into the widget. Every value
41
+ // is the Adwaita default; a component that wants something else overrides it on
42
+ // its own element (this rule is emitted first).
43
+ #{$adw-components} {
44
+ box-sizing: border-box;
45
+ color: var(--window-fg-color);
46
+ font-family: var(--font-family);
47
+ font-size: var(--font-size-base);
48
+ font-weight: 400;
49
+ font-style: normal;
50
+ font-variant: normal;
51
+ line-height: normal;
52
+ letter-spacing: normal;
53
+ word-spacing: normal;
54
+ text-align: start;
55
+ text-indent: 0;
56
+ text-transform: none;
57
+ text-shadow: none;
58
+ }
59
+
60
+ // Descendants: `box-sizing` does not inherit, so a host `*, *::before {
61
+ // box-sizing: content-box }` reset would still reach internal elements. Pin it
62
+ // to `border-box` (adwaita's model throughout) inside every component.
63
+ @each $c in $adw-components {
64
+ #{$c} *,
65
+ #{$c} *::before,
66
+ #{$c} *::after {
67
+ box-sizing: border-box;
68
+ }
69
+ }
@@ -11,6 +11,16 @@
11
11
 
12
12
  adw-view-switcher-bar {
13
13
  display: block;
14
+
15
+ // `revealed` drives visibility by toggling the `hidden` attribute
16
+ // (_applyRevealed → this.hidden). Re-assert display:none for [hidden] as an
17
+ // AUTHOR rule: the UA `[hidden] { display: none }` loses to this block's own
18
+ // author `display: block` (cascade ORIGIN beats specificity), so without this
19
+ // an unrevealed bar would stay visible. Author + higher specificity → wins.
20
+ &[hidden] {
21
+ display: none;
22
+ }
23
+
14
24
  box-sizing: border-box;
15
25
  // The bottom bar over a headerbar-toned surface with a top hairline (the
16
26
  // libadwaita `actionbar` inset top border), NOT a bottom border.
@@ -10,6 +10,9 @@
10
10
  @use 'variables';
11
11
  @use 'theme';
12
12
  @use 'root';
13
+ // Style-isolation boundary — emitted before the components so their own rules
14
+ // override this typographic/box-model floor (see _reset.scss).
15
+ @use 'reset';
13
16
  @use 'window';
14
17
  @use 'headerbar';
15
18
  @use 'window_title';
@@ -0,0 +1,31 @@
1
+ // adw-view-switcher-bar visibility regression (browser axis). Guards that the
2
+ // `revealed` flag actually shows/hides the bar. The bar's base scss sets
3
+ // `display: block`, an AUTHOR rule that would defeat the UA `[hidden]{display:none}`
4
+ // the component relies on (cascade origin beats specificity) — so an unrevealed
5
+ // bar rendered visible until scss/_view_switcher_bar.scss re-asserted
6
+ // `&[hidden] { display: none }`. This test pins that fix.
7
+ import { describe, expect, it } from '@gjsify/unit';
8
+
9
+ export const AdwViewSwitcherBarTest = async () => {
10
+ await describe('adw-view-switcher-bar revealed → visibility', async () => {
11
+ await it('is display:none by default (not revealed) and block once revealed', async () => {
12
+ const bar = document.createElement('adw-view-switcher-bar');
13
+ document.body.appendChild(bar);
14
+
15
+ // Default: `revealed` absent → the component sets `hidden`, and the
16
+ // scss `[hidden]` author rule must win over the base `display: block`.
17
+ expect(bar.hasAttribute('revealed')).toBe(false);
18
+ expect(getComputedStyle(bar).display).toBe('none');
19
+
20
+ // Reveal it → shown.
21
+ bar.setAttribute('revealed', '');
22
+ expect(getComputedStyle(bar).display).toBe('block');
23
+
24
+ // Hide it again → back to none (the round-trip, not a one-way latch).
25
+ bar.removeAttribute('revealed');
26
+ expect(getComputedStyle(bar).display).toBe('none');
27
+
28
+ bar.remove();
29
+ });
30
+ });
31
+ };
@@ -0,0 +1,36 @@
1
+ // Style-isolation regression test (browser axis). Guards the boundary reset
2
+ // (scss/_reset.scss, ADR 0010): a host page's inherited typography must not leak
3
+ // into an adwaita-web widget. It also guards that the widget's tag is listed in
4
+ // the reset's `$adw-components` — if it weren't, the reset wouldn't apply and
5
+ // these assertions would fail.
6
+ import { describe, expect, it } from '@gjsify/unit';
7
+
8
+ export const AdwStyleIsolationTest = async () => {
9
+ await describe('style isolation (boundary reset)', async () => {
10
+ await it('re-roots typography so a host font does not inherit into a widget', async () => {
11
+ // A container styled like a hostile host theme.
12
+ const host = document.createElement('div');
13
+ host.style.fontFamily = 'Georgia, "Times New Roman", serif';
14
+ host.style.color = 'rgb(255, 0, 255)';
15
+ host.style.lineHeight = '2.4';
16
+ host.style.letterSpacing = '3px';
17
+ host.style.textTransform = 'uppercase';
18
+ document.body.appendChild(host);
19
+
20
+ const row = document.createElement('adw-switch-row');
21
+ row.setAttribute('title', 'Wi-Fi');
22
+ host.appendChild(row);
23
+
24
+ const cs = getComputedStyle(row);
25
+ // The boundary reset re-roots the inherited typography to Adwaita's,
26
+ // so the host's serif / magenta / spacing / casing do not leak in.
27
+ expect(cs.fontFamily.includes('Adwaita Sans')).toBe(true);
28
+ expect(cs.fontFamily.includes('Georgia')).toBe(false);
29
+ expect(cs.letterSpacing).toBe('normal');
30
+ expect(cs.textTransform).toBe('none');
31
+ expect(cs.color === 'rgb(255, 0, 255)').toBe(false);
32
+
33
+ host.remove();
34
+ });
35
+ });
36
+ };