@skra/ui 0.2.0 → 0.3.1
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/LICENSE +201 -201
- package/NOTICE +7 -7
- package/README.md +39 -39
- package/consumer-guide/README.md +84 -84
- package/consumer-guide/forms-and-binding.md +19 -3
- package/consumer-guide/layout.md +19 -0
- package/consumer-guide/overlays.md +100 -100
- package/consumer-guide/setup-and-gotchas.md +165 -103
- package/consumer-guide/theming-and-encapsulation.md +129 -115
- package/fesm2022/skra-ui-accordion.mjs +61 -43
- package/fesm2022/skra-ui-accordion.mjs.map +1 -1
- package/fesm2022/skra-ui-alert.mjs +26 -18
- package/fesm2022/skra-ui-alert.mjs.map +1 -1
- package/fesm2022/skra-ui-avatar.mjs +12 -8
- package/fesm2022/skra-ui-avatar.mjs.map +1 -1
- package/fesm2022/skra-ui-badge.mjs +19 -13
- package/fesm2022/skra-ui-badge.mjs.map +1 -1
- package/fesm2022/skra-ui-button.mjs +28 -19
- package/fesm2022/skra-ui-button.mjs.map +1 -1
- package/fesm2022/skra-ui-checkbox.mjs +3 -3
- package/fesm2022/skra-ui-checkbox.mjs.map +1 -1
- package/fesm2022/skra-ui-chip.mjs +15 -11
- package/fesm2022/skra-ui-chip.mjs.map +1 -1
- package/fesm2022/skra-ui-combobox.mjs +135 -130
- package/fesm2022/skra-ui-combobox.mjs.map +1 -1
- package/fesm2022/skra-ui-core.mjs +95 -73
- package/fesm2022/skra-ui-core.mjs.map +1 -1
- package/fesm2022/skra-ui-counter.mjs +9 -6
- package/fesm2022/skra-ui-counter.mjs.map +1 -1
- package/fesm2022/skra-ui-datepicker.mjs +334 -307
- package/fesm2022/skra-ui-datepicker.mjs.map +1 -1
- package/fesm2022/skra-ui-dialog.mjs +5 -4
- package/fesm2022/skra-ui-dialog.mjs.map +1 -1
- package/fesm2022/skra-ui-field.mjs +65 -43
- package/fesm2022/skra-ui-field.mjs.map +1 -1
- package/fesm2022/skra-ui-icon.mjs +5 -4
- package/fesm2022/skra-ui-icon.mjs.map +1 -1
- package/fesm2022/skra-ui-input.mjs +53 -12
- package/fesm2022/skra-ui-input.mjs.map +1 -1
- package/fesm2022/skra-ui-kbd.mjs +3 -3
- package/fesm2022/skra-ui-kbd.mjs.map +1 -1
- package/fesm2022/skra-ui-layout.mjs +33 -21
- package/fesm2022/skra-ui-layout.mjs.map +1 -1
- package/fesm2022/skra-ui-link.mjs +3 -3
- package/fesm2022/skra-ui-link.mjs.map +1 -1
- package/fesm2022/skra-ui-loading-indicator.mjs +3 -3
- package/fesm2022/skra-ui-loading-indicator.mjs.map +1 -1
- package/fesm2022/skra-ui-menu.mjs +8 -7
- package/fesm2022/skra-ui-menu.mjs.map +1 -1
- package/fesm2022/skra-ui-multi-select.mjs +102 -98
- package/fesm2022/skra-ui-multi-select.mjs.map +1 -1
- package/fesm2022/skra-ui-native-select.mjs +35 -17
- package/fesm2022/skra-ui-native-select.mjs.map +1 -1
- package/fesm2022/skra-ui-popover.mjs +5 -4
- package/fesm2022/skra-ui-popover.mjs.map +1 -1
- package/fesm2022/skra-ui-progress.mjs +7 -5
- package/fesm2022/skra-ui-progress.mjs.map +1 -1
- package/fesm2022/skra-ui-radio.mjs +3 -3
- package/fesm2022/skra-ui-radio.mjs.map +1 -1
- package/fesm2022/skra-ui-rating-display.mjs +14 -9
- package/fesm2022/skra-ui-rating-display.mjs.map +1 -1
- package/fesm2022/skra-ui-select.mjs +98 -95
- package/fesm2022/skra-ui-select.mjs.map +1 -1
- package/fesm2022/skra-ui-skeleton.mjs +16 -13
- package/fesm2022/skra-ui-skeleton.mjs.map +1 -1
- package/fesm2022/skra-ui-star-rating.mjs +18 -11
- package/fesm2022/skra-ui-star-rating.mjs.map +1 -1
- package/fesm2022/skra-ui-status-dot.mjs +7 -5
- package/fesm2022/skra-ui-status-dot.mjs.map +1 -1
- package/fesm2022/skra-ui-switch.mjs +3 -3
- package/fesm2022/skra-ui-switch.mjs.map +1 -1
- package/fesm2022/skra-ui-tabs.mjs +43 -29
- package/fesm2022/skra-ui-tabs.mjs.map +1 -1
- package/fesm2022/skra-ui-textarea.mjs +41 -15
- package/fesm2022/skra-ui-textarea.mjs.map +1 -1
- package/fesm2022/skra-ui-toast.mjs +35 -23
- package/fesm2022/skra-ui-toast.mjs.map +1 -1
- package/fesm2022/skra-ui-tooltip.mjs +12 -9
- package/fesm2022/skra-ui-tooltip.mjs.map +1 -1
- package/fesm2022/skra-ui-typography.mjs +9 -6
- package/fesm2022/skra-ui-typography.mjs.map +1 -1
- package/package.json +6 -6
- package/types/skra-ui-field.d.ts +3 -3
- package/types/skra-ui-field.d.ts.map +1 -1
- package/types/skra-ui-input.d.ts +24 -1
- package/types/skra-ui-input.d.ts.map +1 -1
- package/types/skra-ui-native-select.d.ts +9 -1
- package/types/skra-ui-native-select.d.ts.map +1 -1
- package/types/skra-ui-textarea.d.ts +10 -1
- package/types/skra-ui-textarea.d.ts.map +1 -1
package/consumer-guide/README.md
CHANGED
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
# Consuming Skra — Agent Guide (Core)
|
|
2
|
-
|
|
3
|
-
> **DRAFT (2026-06-25).** All 7 sections drafted. Snippets are grounded in source (verified
|
|
4
|
-
> against `libs/ui/*`) + the `apps/dogfood` friction journal (`F-n`) + the Iron Boundaries.
|
|
5
|
-
> Still draft: not yet referenced from a real consumer repo, not lint-gated against ADR drift,
|
|
6
|
-
> and cross-engine/Safari caveats inherit Skra's own open item O-9.
|
|
7
|
-
|
|
8
|
-
This guide is for an **agent working inside a repository that consumes Skra** (imports
|
|
9
|
-
`@skra/*`), not for authoring Skra itself. It is written to be **copied into / referenced
|
|
10
|
-
from a consumer repo**.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## How to use this guide (read this first — it is the point)
|
|
15
|
-
|
|
16
|
-
This file is **tiered on purpose** (same model as `FORGE_ADR_SUMMARY.md`). To keep token
|
|
17
|
-
cost low:
|
|
18
|
-
|
|
19
|
-
1. **Always load this core** (it is small) — the Iron Rules + the Section Router below.
|
|
20
|
-
2. Then load **at most the ONE section** that matches your current task (the Router maps
|
|
21
|
-
task → file). Do **not** read every section "to be safe" — that defeats the design.
|
|
22
|
-
3. Open the full Skra ADR / spec only when a section explicitly points you there.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Iron Rules of Consumption (the 6 a consumer breaks on day one)
|
|
27
|
-
|
|
28
|
-
Violating these is a review blocker in a consumer repo just as inside Skra.
|
|
29
|
-
|
|
30
|
-
1. **Import only from public `@skra/ui/*` entry points** — never a deep relative `libs/...`
|
|
31
|
-
path. Skra ships as one package, `@skra/ui`, with a secondary entry point per component
|
|
32
|
-
(e.g. `@skra/ui/button`, `@skra/ui/typography`, `@skra/ui/select`); the primary
|
|
33
|
-
`@skra/ui` exports nothing. (Full entry-point list → `setup-and-gotchas.md`.)
|
|
34
|
-
2. **You own the value.** Skra form atoms do **not** implement `ControlValueAccessor` /
|
|
35
|
-
`FormValueControl` (ADR 037). Native-host atoms take `[formField]`/`[formControl]`/
|
|
36
|
-
`[(ngModel)]`; value-owned overlays need an explicit `[value]`/`(valueChange)` bridge.
|
|
37
|
-
(How → `forms-and-binding.md`.)
|
|
38
|
-
3. **Accessible name has exactly ONE path** (ADR 033). No Skra atom exposes an `ariaLabel`
|
|
39
|
-
input; never put `aria-label` next to visible text on the same host. (Paths →
|
|
40
|
-
`accessible-names.md`.)
|
|
41
|
-
4. **Inside `<skra-field>`, do not pass `id` / `for` / `aria-describedby` by hand** — the
|
|
42
|
-
DI context wires label↔control↔hint↔error automatically (ADR 013).
|
|
43
|
-
5. **Under Signal Forms, native constraint attributes go in the schema, not the template.**
|
|
44
|
-
`name` on grouped radios and `maxlength` / `min` / `pattern` on a `[formField]` host raise
|
|
45
|
-
`NG8022` — Signal Forms owns them (F-1/F-2). (Details → `forms-and-binding.md`.)
|
|
46
|
-
6. **Never theme with inline styles.** No `[style.--skra-*]` bindings or `style="…"` (breaks
|
|
47
|
-
CSP, ADR 021). Override tokens via a CSS class / `data-skra-*` scope; components are
|
|
48
|
-
`margin: 0` (ADR 022) — spacing comes from layout atoms, never a margin on the component.
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Section Router — load the ONE that matches your task
|
|
53
|
-
|
|
54
|
-
| Section | File | Load when | Status |
|
|
55
|
-
| --------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------- | -------- |
|
|
56
|
-
| **Setup & gotchas** | `setup-and-gotchas.md` | First integration; import fails; which `@skra/*` package exports what; boolean-attribute & theming pitfalls | ✅ draft |
|
|
57
|
-
| **Forms & value binding** | `forms-and-binding.md` | Wiring an input / select / checkbox / rating to Signal Forms, Reactive Forms, or `ngModel` | ✅ draft |
|
|
58
|
-
| **Accessible names** | `accessible-names.md` | Naming buttons, icon-only controls, overlays; using `skra-sr-only` | ✅ draft |
|
|
59
|
-
| **Theming & encapsulation** | `theming-and-encapsulation.md` | Skins, dark mode, density; mounting under Shadow DOM / a microfrontend / an iframe | ✅ draft |
|
|
60
|
-
| **Overlays** | `overlays.md` | Dialog / tooltip / popover / menu / select in the top layer; shadow & iframe limits | ✅ draft |
|
|
61
|
-
| **Layout** | `layout.md` | Spacing & composition with Stack / Box / Grid; the gap scale | ✅ draft |
|
|
62
|
-
| **Wrapping Skra** | `wrapping-patterns.md` | Building your own higher-level components over Skra atoms (simplified API) | ✅ draft |
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Quick reference — task → section
|
|
67
|
-
|
|
68
|
-
| I want to… | Go to |
|
|
69
|
-
| -------------------------------------------------------------------------- | ----------------------------------------- |
|
|
70
|
-
| Add `@skra/ui/*` to a project and import an atom | `setup-and-gotchas.md` |
|
|
71
|
-
| Bind a text input / textarea to a form | `forms-and-binding.md` |
|
|
72
|
-
| Bind a `skra-select` / `skra-datepicker` / `skra-star-rating` to a form | `forms-and-binding.md` (the value bridge) |
|
|
73
|
-
| Name an icon-only button | `accessible-names.md` |
|
|
74
|
-
| Switch skin / dark mode at runtime | `theming-and-encapsulation.md` |
|
|
75
|
-
| Mount Skra inside a Web Component / microfrontend | `theming-and-encapsulation.md` |
|
|
76
|
-
| Open a dialog or tooltip | `overlays.md` |
|
|
77
|
-
| Space components apart | `layout.md` |
|
|
78
|
-
| Wrap a Skra atom in a project-specific component | `wrapping-patterns.md` |
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
_Source of truth for the rules: Skra `FORGE_ADR_SUMMARY.md` + `adr/decisions/`. Real
|
|
83
|
-
consumption evidence: `apps/dogfood/FRICTION_JOURNAL.md`. This guide restates the consumer
|
|
84
|
-
slice of those — on divergence, the ADRs win._
|
|
1
|
+
# Consuming Skra — Agent Guide (Core)
|
|
2
|
+
|
|
3
|
+
> **DRAFT (2026-06-25).** All 7 sections drafted. Snippets are grounded in source (verified
|
|
4
|
+
> against `libs/ui/*`) + the `apps/dogfood` friction journal (`F-n`) + the Iron Boundaries.
|
|
5
|
+
> Still draft: not yet referenced from a real consumer repo, not lint-gated against ADR drift,
|
|
6
|
+
> and cross-engine/Safari caveats inherit Skra's own open item O-9.
|
|
7
|
+
|
|
8
|
+
This guide is for an **agent working inside a repository that consumes Skra** (imports
|
|
9
|
+
`@skra/*`), not for authoring Skra itself. It is written to be **copied into / referenced
|
|
10
|
+
from a consumer repo**.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## How to use this guide (read this first — it is the point)
|
|
15
|
+
|
|
16
|
+
This file is **tiered on purpose** (same model as `FORGE_ADR_SUMMARY.md`). To keep token
|
|
17
|
+
cost low:
|
|
18
|
+
|
|
19
|
+
1. **Always load this core** (it is small) — the Iron Rules + the Section Router below.
|
|
20
|
+
2. Then load **at most the ONE section** that matches your current task (the Router maps
|
|
21
|
+
task → file). Do **not** read every section "to be safe" — that defeats the design.
|
|
22
|
+
3. Open the full Skra ADR / spec only when a section explicitly points you there.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Iron Rules of Consumption (the 6 a consumer breaks on day one)
|
|
27
|
+
|
|
28
|
+
Violating these is a review blocker in a consumer repo just as inside Skra.
|
|
29
|
+
|
|
30
|
+
1. **Import only from public `@skra/ui/*` entry points** — never a deep relative `libs/...`
|
|
31
|
+
path. Skra ships as one package, `@skra/ui`, with a secondary entry point per component
|
|
32
|
+
(e.g. `@skra/ui/button`, `@skra/ui/typography`, `@skra/ui/select`); the primary
|
|
33
|
+
`@skra/ui` exports nothing. (Full entry-point list → `setup-and-gotchas.md`.)
|
|
34
|
+
2. **You own the value.** Skra form atoms do **not** implement `ControlValueAccessor` /
|
|
35
|
+
`FormValueControl` (ADR 037). Native-host atoms take `[formField]`/`[formControl]`/
|
|
36
|
+
`[(ngModel)]`; value-owned overlays need an explicit `[value]`/`(valueChange)` bridge.
|
|
37
|
+
(How → `forms-and-binding.md`.)
|
|
38
|
+
3. **Accessible name has exactly ONE path** (ADR 033). No Skra atom exposes an `ariaLabel`
|
|
39
|
+
input; never put `aria-label` next to visible text on the same host. (Paths →
|
|
40
|
+
`accessible-names.md`.)
|
|
41
|
+
4. **Inside `<skra-field>`, do not pass `id` / `for` / `aria-describedby` by hand** — the
|
|
42
|
+
DI context wires label↔control↔hint↔error automatically (ADR 013).
|
|
43
|
+
5. **Under Signal Forms, native constraint attributes go in the schema, not the template.**
|
|
44
|
+
`name` on grouped radios and `maxlength` / `min` / `pattern` on a `[formField]` host raise
|
|
45
|
+
`NG8022` — Signal Forms owns them (F-1/F-2). (Details → `forms-and-binding.md`.)
|
|
46
|
+
6. **Never theme with inline styles.** No `[style.--skra-*]` bindings or `style="…"` (breaks
|
|
47
|
+
CSP, ADR 021). Override tokens via a CSS class / `data-skra-*` scope; components are
|
|
48
|
+
`margin: 0` (ADR 022) — spacing comes from layout atoms, never a margin on the component.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Section Router — load the ONE that matches your task
|
|
53
|
+
|
|
54
|
+
| Section | File | Load when | Status |
|
|
55
|
+
| --------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------- | -------- |
|
|
56
|
+
| **Setup & gotchas** | `setup-and-gotchas.md` | First integration; import fails; which `@skra/*` package exports what; boolean-attribute & theming pitfalls | ✅ draft |
|
|
57
|
+
| **Forms & value binding** | `forms-and-binding.md` | Wiring an input / select / checkbox / rating to Signal Forms, Reactive Forms, or `ngModel` | ✅ draft |
|
|
58
|
+
| **Accessible names** | `accessible-names.md` | Naming buttons, icon-only controls, overlays; using `skra-sr-only` | ✅ draft |
|
|
59
|
+
| **Theming & encapsulation** | `theming-and-encapsulation.md` | Skins, dark mode, density; mounting under Shadow DOM / a microfrontend / an iframe | ✅ draft |
|
|
60
|
+
| **Overlays** | `overlays.md` | Dialog / tooltip / popover / menu / select in the top layer; shadow & iframe limits | ✅ draft |
|
|
61
|
+
| **Layout** | `layout.md` | Spacing & composition with Stack / Box / Grid; the gap scale | ✅ draft |
|
|
62
|
+
| **Wrapping Skra** | `wrapping-patterns.md` | Building your own higher-level components over Skra atoms (simplified API) | ✅ draft |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Quick reference — task → section
|
|
67
|
+
|
|
68
|
+
| I want to… | Go to |
|
|
69
|
+
| -------------------------------------------------------------------------- | ----------------------------------------- |
|
|
70
|
+
| Add `@skra/ui/*` to a project and import an atom | `setup-and-gotchas.md` |
|
|
71
|
+
| Bind a text input / textarea to a form | `forms-and-binding.md` |
|
|
72
|
+
| Bind a `skra-select` / `skra-datepicker` / `skra-star-rating` to a form | `forms-and-binding.md` (the value bridge) |
|
|
73
|
+
| Name an icon-only button | `accessible-names.md` |
|
|
74
|
+
| Switch skin / dark mode at runtime | `theming-and-encapsulation.md` |
|
|
75
|
+
| Mount Skra inside a Web Component / microfrontend | `theming-and-encapsulation.md` |
|
|
76
|
+
| Open a dialog or tooltip | `overlays.md` |
|
|
77
|
+
| Space components apart | `layout.md` |
|
|
78
|
+
| Wrap a Skra atom in a project-specific component | `wrapping-patterns.md` |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
_Source of truth for the rules: Skra `FORGE_ADR_SUMMARY.md` + `adr/decisions/`. Real
|
|
83
|
+
consumption evidence: `apps/dogfood/FRICTION_JOURNAL.md`. This guide restates the consumer
|
|
84
|
+
slice of those — on divergence, the ADRs win._
|
|
@@ -22,15 +22,31 @@ directives attach to the same host, so `[formField]`, `[formControl]`/`formContr
|
|
|
22
22
|
|
|
23
23
|
```html
|
|
24
24
|
<!-- text: Signal Forms / Reactive / ngModel — all valid -->
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
<input skraInput [
|
|
25
|
+
<skra-field>
|
|
26
|
+
<label skraLabelFor>Email</label>
|
|
27
|
+
<input skraInput [formField]="form().email" />
|
|
28
|
+
</skra-field>
|
|
29
|
+
|
|
30
|
+
<skra-field>
|
|
31
|
+
<label skraLabelFor>Email</label>
|
|
32
|
+
<input skraInput [formControl]="emailCtrl" />
|
|
33
|
+
</skra-field>
|
|
34
|
+
|
|
35
|
+
<skra-field>
|
|
36
|
+
<label skraLabelFor>Email</label>
|
|
37
|
+
<input skraInput [(ngModel)]="email" />
|
|
38
|
+
</skra-field>
|
|
28
39
|
|
|
29
40
|
<!-- checkbox / switch: native checked + change (or any form directive) -->
|
|
30
41
|
<input type="checkbox" skraCheckbox
|
|
31
42
|
[checked]="accepted()" (change)="accepted.set($any($event.target).checked)" />
|
|
32
43
|
```
|
|
33
44
|
|
|
45
|
+
> The `<skra-field>` wrapper above is about the **label**, not the binding — the form
|
|
46
|
+
> directive attaches to the native host either way. A control that needs no visible label,
|
|
47
|
+
> hint or error can stand alone (`<label>Search <input skraInput /></label>`); see
|
|
48
|
+
> `setup-and-gotchas.md` Gotcha 5.
|
|
49
|
+
|
|
34
50
|
**Radios group natively** — `<fieldset skraFieldset>` + `<legend skraLegend>`, with
|
|
35
51
|
selection coordinated through the shared `name`:
|
|
36
52
|
|
package/consumer-guide/layout.md
CHANGED
|
@@ -15,6 +15,25 @@ a native host** (a bounded allowlist of `div`/`section`/`nav`/`ul`/…), **never
|
|
|
15
15
|
<ul skraStack gap="sm">…</ul> <!-- list markers normalized, restorable -->
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## Sizing container-filling components (e.g. `skra-select`)
|
|
19
|
+
|
|
20
|
+
Layout isolation (ADR 022) means a component never imposes its own outer size either. Some
|
|
21
|
+
components are **`display: block` and fill their container's inline size** by design — the
|
|
22
|
+
form controls especially (`skra-select`, `skra-combobox`, `input[skraInput]`, …), because
|
|
23
|
+
their primary home is a full-width form field. A **standalone** one (a toolbar select, a
|
|
24
|
+
filter control) therefore needs the consumer to size it — give it a width-bearing wrapper:
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<div style="inline-size: 16rem"><skra-select …>…</skra-select></div>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Gotcha:** dropped straight into a `display: flex` / `display: grid` row with no explicit
|
|
31
|
+
`flex` / `inline-size` / `min-inline-size`, a container-filling component collapses toward its
|
|
32
|
+
content width — and when it holds no value yet it can shrink to just its padding + icon (looks
|
|
33
|
+
"broken"). This is the isolation contract working as intended, not a component bug: size the
|
|
34
|
+
component (wrapper width, a `skraGrid` track, or a `flex` basis), don't expect an intrinsic
|
|
35
|
+
width.
|
|
36
|
+
|
|
18
37
|
## Stack — 1D flex (`[skraStack]`)
|
|
19
38
|
|
|
20
39
|
Arranges children in a row or column.
|
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
# Overlays
|
|
2
|
-
|
|
3
|
-
> Load this for: opening a dialog, tooltip, popover, or menu in the native top layer, and the
|
|
4
|
-
> shadow/iframe limits. Governed by ADR 0044 (native top-layer substrate — no CDK portal, no
|
|
5
|
-
> z-index). For `select` / `combobox` / `datepicker` **value binding**, see `forms-and-binding.md`
|
|
6
|
-
> (they are value-owned overlays).
|
|
7
|
-
|
|
8
|
-
## Shared model
|
|
9
|
-
|
|
10
|
-
All Skra overlays render in the **browser top layer** via native platform APIs (`<dialog>` +
|
|
11
|
-
the Popover API), not a `document.body` portal. Consequences for you:
|
|
12
|
-
|
|
13
|
-
- **No z-index management.** Stacking is invocation-order; nesting is always correct.
|
|
14
|
-
- **Escape, light-dismiss, `::backdrop`** are platform-owned (per overlay, below).
|
|
15
|
-
- They open correctly **from inside a Shadow DOM root**; per-context limits at the bottom.
|
|
16
|
-
|
|
17
|
-
## Dialog (modal) — `dialog[skraDialog]`
|
|
18
|
-
|
|
19
|
-
A Component on the native `<dialog>`, opened with the **native** `showModal()` and closed with
|
|
20
|
-
`close()`. `role="dialog"`, `aria-modal`, Escape, the `::backdrop` scrim, scroll-lock and focus
|
|
21
|
-
containment are native:
|
|
22
|
-
|
|
23
|
-
```html
|
|
24
|
-
<button skraButton (click)="dlg.showModal()">Delete…</button>
|
|
25
|
-
|
|
26
|
-
<dialog skraDialog #dlg aria-labelledby="confirm-title" size="sm">
|
|
27
|
-
<h2 id="confirm-title">Delete item?</h2>
|
|
28
|
-
<p>This can't be undone.</p>
|
|
29
|
-
<button skraButton autofocus (click)="dlg.close()">Cancel</button>
|
|
30
|
-
<button skraButton (click)="confirm(); dlg.close()">Delete</button>
|
|
31
|
-
</dialog>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
- **Name it** with `aria-labelledby` → a projected heading (no `ariaLabel` input — ADR 033).
|
|
35
|
-
- **Initial focus** is the consumer-placed native `autofocus` attribute.
|
|
36
|
-
- `size` is `sm | md | lg` (ADR 035).
|
|
37
|
-
|
|
38
|
-
## Tooltip — `[skraTooltip]` on your own trigger
|
|
39
|
-
|
|
40
|
-
A supplementary, non-interactive **description** shown on hover AND focus. It is **not** the
|
|
41
|
-
accessible name — it merges into the trigger's `aria-describedby`:
|
|
42
|
-
|
|
43
|
-
```html
|
|
44
|
-
<button skraButton [skraTooltip]="'Open settings'" aria-label="Settings">⚙</button>
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
An icon-only trigger **still needs its own accessible name** (Path 3 — see
|
|
48
|
-
`accessible-names.md`); the tooltip never substitutes for it.
|
|
49
|
-
|
|
50
|
-
## Popover (non-modal panel) — `skra-popover`
|
|
51
|
-
|
|
52
|
-
A Component on the panel with projected interactive content. The trigger is **your own button**
|
|
53
|
-
linked by the native `popovertarget`; toggle, light-dismiss, Escape, and stacking are
|
|
54
|
-
platform-owned. **You MUST give the panel an `id`:**
|
|
55
|
-
|
|
56
|
-
```html
|
|
57
|
-
<button skraButton popovertarget="account-menu">Account</button>
|
|
58
|
-
<skra-popover id="account-menu" aria-labelledby="account-menu-title">
|
|
59
|
-
<h3 id="account-menu-title">Signed in as…</h3>
|
|
60
|
-
<!-- interactive content -->
|
|
61
|
-
</skra-popover>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Focus is **not** trapped/force-moved (non-modal). Name via `aria-labelledby` → projected
|
|
65
|
-
heading.
|
|
66
|
-
|
|
67
|
-
## Menu (commands) — `skra-menu` + `button[skraMenuItem]`
|
|
68
|
-
|
|
69
|
-
A WAI-ARIA APG menu-button: a homogeneous command set, arrow-key navigated, activating an item
|
|
70
|
-
closes it. Trigger is your own button with `popovertarget` + `aria-haspopup="menu"`; **give the
|
|
71
|
-
panel an `id`**. Focus moves **into** the menu on open:
|
|
72
|
-
|
|
73
|
-
```html
|
|
74
|
-
<button skraButton popovertarget="row-actions" aria-haspopup="menu">Actions</button>
|
|
75
|
-
<skra-menu id="row-actions">
|
|
76
|
-
<button skraMenuItem (click)="edit()">Edit</button>
|
|
77
|
-
<button skraMenuItem disabled (click)="archive()">Archive</button>
|
|
78
|
-
<button skraMenuItem (click)="remove()">Delete</button>
|
|
79
|
-
</skra-menu>
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
- **Side effects on open/close:** bind the **native `(toggle)`** event — there is no Skra
|
|
83
|
-
output (native-first).
|
|
84
|
-
- A right-click context menu is **not** a menu trigger mode — use a visible button (SRP +
|
|
85
|
-
WCAG 2.1.1).
|
|
86
|
-
|
|
87
|
-
## Selection overlays — value binding lives elsewhere
|
|
88
|
-
|
|
89
|
-
`skra-select`, `skra-multi-select`, `skra-combobox`, `skra-datepicker` render their listbox
|
|
90
|
-
in the top layer like the above, **but their value is consumer-owned** — bind with the
|
|
91
|
-
`[value]`/`(valueChange)` bridge documented in `forms-and-binding.md` (class B). The combobox
|
|
92
|
-
filters with consumer-owned data (ADR 0049): you own the filtered option list.
|
|
93
|
-
|
|
94
|
-
## Limits across boundaries (same as theming — recap)
|
|
95
|
-
|
|
96
|
-
- Overlays **open** from inside a Shadow DOM root (top layer + positioning cross the boundary,
|
|
97
|
-
F-10). But the global-slice pieces — `::backdrop` scrim and `html:has()` scroll-lock — need
|
|
98
|
-
the bridge / don't pierce the boundary (F-6/F-7). See `theming-and-encapsulation.md`.
|
|
99
|
-
- **iframe**: overlays are contained to the frame's own top layer — they cannot overlay the
|
|
100
|
-
parent app (F-11).
|
|
1
|
+
# Overlays
|
|
2
|
+
|
|
3
|
+
> Load this for: opening a dialog, tooltip, popover, or menu in the native top layer, and the
|
|
4
|
+
> shadow/iframe limits. Governed by ADR 0044 (native top-layer substrate — no CDK portal, no
|
|
5
|
+
> z-index). For `select` / `combobox` / `datepicker` **value binding**, see `forms-and-binding.md`
|
|
6
|
+
> (they are value-owned overlays).
|
|
7
|
+
|
|
8
|
+
## Shared model
|
|
9
|
+
|
|
10
|
+
All Skra overlays render in the **browser top layer** via native platform APIs (`<dialog>` +
|
|
11
|
+
the Popover API), not a `document.body` portal. Consequences for you:
|
|
12
|
+
|
|
13
|
+
- **No z-index management.** Stacking is invocation-order; nesting is always correct.
|
|
14
|
+
- **Escape, light-dismiss, `::backdrop`** are platform-owned (per overlay, below).
|
|
15
|
+
- They open correctly **from inside a Shadow DOM root**; per-context limits at the bottom.
|
|
16
|
+
|
|
17
|
+
## Dialog (modal) — `dialog[skraDialog]`
|
|
18
|
+
|
|
19
|
+
A Component on the native `<dialog>`, opened with the **native** `showModal()` and closed with
|
|
20
|
+
`close()`. `role="dialog"`, `aria-modal`, Escape, the `::backdrop` scrim, scroll-lock and focus
|
|
21
|
+
containment are native:
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<button skraButton (click)="dlg.showModal()">Delete…</button>
|
|
25
|
+
|
|
26
|
+
<dialog skraDialog #dlg aria-labelledby="confirm-title" size="sm">
|
|
27
|
+
<h2 id="confirm-title">Delete item?</h2>
|
|
28
|
+
<p>This can't be undone.</p>
|
|
29
|
+
<button skraButton autofocus (click)="dlg.close()">Cancel</button>
|
|
30
|
+
<button skraButton (click)="confirm(); dlg.close()">Delete</button>
|
|
31
|
+
</dialog>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **Name it** with `aria-labelledby` → a projected heading (no `ariaLabel` input — ADR 033).
|
|
35
|
+
- **Initial focus** is the consumer-placed native `autofocus` attribute.
|
|
36
|
+
- `size` is `sm | md | lg` (ADR 035).
|
|
37
|
+
|
|
38
|
+
## Tooltip — `[skraTooltip]` on your own trigger
|
|
39
|
+
|
|
40
|
+
A supplementary, non-interactive **description** shown on hover AND focus. It is **not** the
|
|
41
|
+
accessible name — it merges into the trigger's `aria-describedby`:
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<button skraButton [skraTooltip]="'Open settings'" aria-label="Settings">⚙</button>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
An icon-only trigger **still needs its own accessible name** (Path 3 — see
|
|
48
|
+
`accessible-names.md`); the tooltip never substitutes for it.
|
|
49
|
+
|
|
50
|
+
## Popover (non-modal panel) — `skra-popover`
|
|
51
|
+
|
|
52
|
+
A Component on the panel with projected interactive content. The trigger is **your own button**
|
|
53
|
+
linked by the native `popovertarget`; toggle, light-dismiss, Escape, and stacking are
|
|
54
|
+
platform-owned. **You MUST give the panel an `id`:**
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<button skraButton popovertarget="account-menu">Account</button>
|
|
58
|
+
<skra-popover id="account-menu" aria-labelledby="account-menu-title">
|
|
59
|
+
<h3 id="account-menu-title">Signed in as…</h3>
|
|
60
|
+
<!-- interactive content -->
|
|
61
|
+
</skra-popover>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Focus is **not** trapped/force-moved (non-modal). Name via `aria-labelledby` → projected
|
|
65
|
+
heading.
|
|
66
|
+
|
|
67
|
+
## Menu (commands) — `skra-menu` + `button[skraMenuItem]`
|
|
68
|
+
|
|
69
|
+
A WAI-ARIA APG menu-button: a homogeneous command set, arrow-key navigated, activating an item
|
|
70
|
+
closes it. Trigger is your own button with `popovertarget` + `aria-haspopup="menu"`; **give the
|
|
71
|
+
panel an `id`**. Focus moves **into** the menu on open:
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<button skraButton popovertarget="row-actions" aria-haspopup="menu">Actions</button>
|
|
75
|
+
<skra-menu id="row-actions">
|
|
76
|
+
<button skraMenuItem (click)="edit()">Edit</button>
|
|
77
|
+
<button skraMenuItem disabled (click)="archive()">Archive</button>
|
|
78
|
+
<button skraMenuItem (click)="remove()">Delete</button>
|
|
79
|
+
</skra-menu>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- **Side effects on open/close:** bind the **native `(toggle)`** event — there is no Skra
|
|
83
|
+
output (native-first).
|
|
84
|
+
- A right-click context menu is **not** a menu trigger mode — use a visible button (SRP +
|
|
85
|
+
WCAG 2.1.1).
|
|
86
|
+
|
|
87
|
+
## Selection overlays — value binding lives elsewhere
|
|
88
|
+
|
|
89
|
+
`skra-select`, `skra-multi-select`, `skra-combobox`, `skra-datepicker` render their listbox
|
|
90
|
+
in the top layer like the above, **but their value is consumer-owned** — bind with the
|
|
91
|
+
`[value]`/`(valueChange)` bridge documented in `forms-and-binding.md` (class B). The combobox
|
|
92
|
+
filters with consumer-owned data (ADR 0049): you own the filtered option list.
|
|
93
|
+
|
|
94
|
+
## Limits across boundaries (same as theming — recap)
|
|
95
|
+
|
|
96
|
+
- Overlays **open** from inside a Shadow DOM root (top layer + positioning cross the boundary,
|
|
97
|
+
F-10). But the global-slice pieces — `::backdrop` scrim and `html:has()` scroll-lock — need
|
|
98
|
+
the bridge / don't pierce the boundary (F-6/F-7). See `theming-and-encapsulation.md`.
|
|
99
|
+
- **iframe**: overlays are contained to the frame's own top layer — they cannot overlay the
|
|
100
|
+
parent app (F-11).
|