@junoput01/junoui 0.2.0 → 0.4.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 +251 -0
- package/README.md +23 -19
- package/dist/css/juno-custom-media.css +32 -0
- package/dist/css/juno.css +1355 -40
- package/dist/icons/inline.js +22 -0
- package/docs/accessibility.md +188 -0
- package/docs/boot-shell.md +295 -0
- package/docs/components/README.md +71 -0
- package/docs/components/accordion.md +49 -0
- package/docs/components/alert.md +46 -0
- package/docs/components/avatar.md +45 -0
- package/docs/components/badge.md +35 -0
- package/docs/components/breadcrumb.md +31 -0
- package/docs/components/button.md +32 -0
- package/docs/components/card.md +41 -0
- package/docs/components/checkbox.md +41 -0
- package/docs/components/chip.md +44 -0
- package/docs/components/divider.md +32 -0
- package/docs/components/dock.md +215 -0
- package/docs/components/drawer.md +100 -0
- package/docs/components/field.md +44 -0
- package/docs/components/fold-slot.md +31 -0
- package/docs/components/gauge.md +48 -0
- package/docs/components/icon-loader.md +122 -0
- package/docs/components/icon.md +70 -0
- package/docs/components/input.md +45 -0
- package/docs/components/list.md +76 -0
- package/docs/components/load-state.md +131 -0
- package/docs/components/loader.md +88 -0
- package/docs/components/menu.md +54 -0
- package/docs/components/modal.md +52 -0
- package/docs/components/navbar.md +53 -0
- package/docs/components/pagination.md +42 -0
- package/docs/components/pillbar.md +211 -0
- package/docs/components/popover.md +43 -0
- package/docs/components/rail.md +54 -0
- package/docs/components/readout.md +39 -0
- package/docs/components/reload.md +41 -0
- package/docs/components/segmented.md +46 -0
- package/docs/components/select.md +33 -0
- package/docs/components/skeleton.md +45 -0
- package/docs/components/slider.md +48 -0
- package/docs/components/spark.md +51 -0
- package/docs/components/status.md +30 -0
- package/docs/components/stepper.md +46 -0
- package/docs/components/switch.md +38 -0
- package/docs/components/table.md +126 -0
- package/docs/components/tabs.md +61 -0
- package/docs/components/thumb.md +81 -0
- package/docs/components/toast.md +48 -0
- package/docs/components/toggle-button.md +40 -0
- package/docs/components/tooltip.md +63 -0
- package/docs/design-guidelines.md +173 -0
- package/docs/flutter.md +42 -0
- package/docs/getting-started.md +93 -0
- package/docs/integration.md +95 -0
- package/docs/ios-conformance.md +224 -0
- package/docs/layout.md +271 -0
- package/docs/native.md +52 -0
- package/docs/roadmap.md +106 -0
- package/docs/tokens-reference.md +223 -0
- package/docs/web.md +95 -0
- package/package.json +7 -3
- package/src/css/base.css +171 -1
- package/src/css/components/dock.css +335 -0
- package/src/css/components/drawer.css +40 -3
- package/src/css/components/fold-slot.css +44 -0
- package/src/css/components/icon-loader.css +67 -0
- package/src/css/components/icon.css +6 -4
- package/src/css/components/load-state.css +136 -0
- package/src/css/components/loader.css +6 -0
- package/src/css/components/menu.css +4 -0
- package/src/css/components/modal.css +24 -3
- package/src/css/components/navbar.css +5 -1
- package/src/css/components/pillbar.css +222 -7
- package/src/css/components/rail.css +8 -0
- package/src/css/components/reload.css +48 -0
- package/src/css/components/skeleton.css +41 -13
- package/src/css/components/tabs.css +5 -0
- package/src/css/components/thumb.css +63 -1
- package/src/css/components/toast.css +5 -1
- package/src/css/density.css +22 -0
- package/src/css/layout.css +95 -5
- package/src/css/utilities.css +4 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Stepper
|
|
2
|
+
|
|
3
|
+
A sequence of steps with numbered markers and connectors that shows progress through a
|
|
4
|
+
multi-step flow. Each step carries `data-state` — `complete` · `current` · `upcoming`;
|
|
5
|
+
the active one gets `aria-current="step"`. Built on a real `<ol>`; the app sets the
|
|
6
|
+
states. Zero JS. Reads `--juno-role` (default `active`) for the accent.
|
|
7
|
+
|
|
8
|
+
## Web
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<ol class="juno-stepper">
|
|
12
|
+
<li class="juno-stepper__step" data-state="complete">
|
|
13
|
+
<span class="juno-stepper__marker">
|
|
14
|
+
<svg class="juno-icon juno-icon--sm" aria-hidden="true"><use href="…#juno-i-check" /></svg>
|
|
15
|
+
</span>
|
|
16
|
+
<span class="juno-stepper__label">Plan</span>
|
|
17
|
+
</li>
|
|
18
|
+
<li class="juno-stepper__step" data-state="current" aria-current="step">
|
|
19
|
+
<span class="juno-stepper__marker">2</span>
|
|
20
|
+
<span class="juno-stepper__label">Build</span>
|
|
21
|
+
</li>
|
|
22
|
+
<li class="juno-stepper__step" data-state="upcoming">
|
|
23
|
+
<span class="juno-stepper__marker">3</span>
|
|
24
|
+
<span class="juno-stepper__label">Ship</span>
|
|
25
|
+
</li>
|
|
26
|
+
</ol>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Part / attr | Effect |
|
|
30
|
+
| ------------------------- | ----------------------------------------------------------- |
|
|
31
|
+
| `.juno-stepper` | `<ol>` row; `--juno-stepper-marker` sizes the circle. |
|
|
32
|
+
| `.juno-stepper__step` | One step; set `data-state` + connector lights when reached. |
|
|
33
|
+
| `.juno-stepper__marker` | Numbered circle (or a `check` icon when complete). |
|
|
34
|
+
| `.juno-stepper__label` | Step caption. |
|
|
35
|
+
| `data-state="complete"` | Filled accent marker + lit connector. |
|
|
36
|
+
| `data-state="current"` | Ringed accent marker; pair with `aria-current="step"`. |
|
|
37
|
+
| `data-state="upcoming"` | Muted marker + connector. |
|
|
38
|
+
| `.juno-stepper--vertical` | Stack steps; connector runs down the marker column. |
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
- Set `aria-current="step"` on the current step so assistive tech announces position.
|
|
43
|
+
- The **state drives the color**, not vice-versa — `complete` and `current` both light
|
|
44
|
+
the accent + their incoming connector; `upcoming` stays muted.
|
|
45
|
+
- Use a `check` icon for completed markers, the number for current / upcoming.
|
|
46
|
+
- Change the accent with a role class on `.juno-stepper` (e.g. `.juno--nominal`).
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Switch
|
|
2
|
+
|
|
3
|
+
A labeled rocker: a squared track that lights green (`nominal`) when ON, with an
|
|
4
|
+
**ON / OFF legend** and a sliding knob. A real checkbox drives it; the app owns state.
|
|
5
|
+
|
|
6
|
+
## Web
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<label class="juno-switch">
|
|
10
|
+
<input class="juno-switch__input" type="checkbox" role="switch" checked />
|
|
11
|
+
<span class="juno-switch__track"></span>
|
|
12
|
+
<span>AUTO-SCALING</span>
|
|
13
|
+
</label>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
| Class | Effect |
|
|
17
|
+
| ------------------------ | ---------------------------------------------------------------------------------- |
|
|
18
|
+
| `.juno-switch` | Inline-flex label row; `gap-control`, `data` text. |
|
|
19
|
+
| `.juno-switch__input` | The checkbox — visually hidden, still focusable / tab-ordered. |
|
|
20
|
+
| `.juno-switch__track` | 70 × `space.28` track; OFF = `control-edge`, ON = role (`nominal`). Legend + knob. |
|
|
21
|
+
| `.juno-switch--sm` | Quiet 40 × `space.20` track: no printed legend, smaller knob. For per-row toggles. |
|
|
22
|
+
| `.juno--<role>` | On-color of the track (put on `__track`). |
|
|
23
|
+
| `:checked` / `:disabled` | Slides the knob to inline-end + legend ON / dims. |
|
|
24
|
+
|
|
25
|
+
## Anatomy (any platform)
|
|
26
|
+
|
|
27
|
+
- Track 70 × `space.28`, radius `4`, inset shadow. Knob 26 × 22, radius `4`, gradient
|
|
28
|
+
`s3`→`s2`, three grip lines; printed ON / OFF legend (mono 10px, `muted` → role).
|
|
29
|
+
- Knob travels via `inset-inline-start` (mirrors under RTL), `motion.duration.quick`;
|
|
30
|
+
honors `prefers-reduced-motion`.
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
- Switch = immediate state change (a setting that takes effect now). For form values
|
|
35
|
+
submitted later, prefer a [checkbox](./checkbox.md).
|
|
36
|
+
- The default rocker is for settings panels; `--sm` for columns of row toggles
|
|
37
|
+
(plugin lists, table rows) where five rockers would shout.
|
|
38
|
+
- Add `role="switch"`; the app toggles `checked` + `aria-checked`.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Table / data grid
|
|
2
|
+
|
|
3
|
+
Dense, scannable rows that read like instrument readouts — numbers in mono and
|
|
4
|
+
right-aligned, semantic color reserved for status, and the active-cyan rail marking the
|
|
5
|
+
row in focus. junoui dresses a **real `<table>`** and ships the **look + the ARIA
|
|
6
|
+
contract**; the app owns sort, selection, inline-edit, pagination, and filtering.
|
|
7
|
+
|
|
8
|
+
## Web
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<div class="juno-table-scroll">
|
|
12
|
+
<table class="juno-table juno-table--zebra juno-table--sticky">
|
|
13
|
+
<thead>
|
|
14
|
+
<tr>
|
|
15
|
+
<th aria-sort="ascending">SERVICE</th>
|
|
16
|
+
<th class="juno-table__num" aria-sort="none">CPU</th>
|
|
17
|
+
<th>STATUS</th>
|
|
18
|
+
</tr>
|
|
19
|
+
</thead>
|
|
20
|
+
<tbody>
|
|
21
|
+
<tr aria-selected="true">
|
|
22
|
+
<td class="juno-table__id">api-gateway</td>
|
|
23
|
+
<td class="juno-table__num">62</td>
|
|
24
|
+
<td><span class="juno-badge juno-badge--soft juno--nominal">HEALTHY</span></td>
|
|
25
|
+
</tr>
|
|
26
|
+
</tbody>
|
|
27
|
+
</table>
|
|
28
|
+
</div>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Class | Effect |
|
|
32
|
+
| -------------------------- | ----------------------------------------------------------------------- |
|
|
33
|
+
| `.juno-table-scroll` | Overflow-scrolling viewport (`max-block-size: 480px`) + thin scrollbar. |
|
|
34
|
+
| `.juno-table` | The `<table>`: header `s2`, mono numerics, `border` row rules. |
|
|
35
|
+
| `.juno-table--sticky` | Header holds (`position: sticky`) while the body scrolls. |
|
|
36
|
+
| `.juno-table--zebra` | Stripes even body rows (`s2` dark / `s1` light). |
|
|
37
|
+
| `.juno-table--compact` | Tighter row padding (per-table; independent of global density). |
|
|
38
|
+
| `.juno-table--stack` | Phone mode: rows become label/value cards below 480px (see below). |
|
|
39
|
+
| `th[aria-sort]` | Marks a sortable column; `ascending` / `descending` draw the arrow. |
|
|
40
|
+
| `tr[aria-selected="true"]` | Active rail (left) + cyan row wash. |
|
|
41
|
+
|
|
42
|
+
### Cell flavors
|
|
43
|
+
|
|
44
|
+
| Class | Use |
|
|
45
|
+
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
46
|
+
| `.juno-table__id` | Identifier — mono, bold (codes, hostnames, IDs). |
|
|
47
|
+
| `.juno-table__num` | Numeric — mono, bold, end-aligned (measured values). |
|
|
48
|
+
| `.juno-table__mono` | Secondary mono (routes, sub-codes) — quieter `label` color. |
|
|
49
|
+
| `.juno-table__time` | Timestamp — mono, end-aligned, muted. |
|
|
50
|
+
| `.juno-table__trend` | Role-colored mono delta; author supplies the `▲` / `▼` + sign. |
|
|
51
|
+
| `.juno-table__meter` | Inline track + role fill + value; set `--juno-table-fill` (0–100). |
|
|
52
|
+
| `.juno-table__actions` | Icon buttons (`__action`), revealed on row hover / focus. |
|
|
53
|
+
| `.juno-badge--soft` | Status as a low-fill role chip (see [badge](./badge.md)). |
|
|
54
|
+
| `.juno-table__check` | Selection-column cell (44px, centered). Holds a `.juno-checkbox`. |
|
|
55
|
+
| `.juno-table__editable` | Editable cell: dashed `__mark` underline + hover ring. App swaps `__mark` for a `.juno-table__edit-input` on double-click. |
|
|
56
|
+
|
|
57
|
+
### Overflow (set on a cell)
|
|
58
|
+
|
|
59
|
+
| Class | Behavior |
|
|
60
|
+
| ----------------------- | --------------------------------------------------------------------- |
|
|
61
|
+
| `.juno-table__truncate` | Single line + ellipsis (default). Pair with a `title` / tooltip. |
|
|
62
|
+
| `.juno-table__clamp` | Two lines, then ellipsis. Wrap the text in `.juno-table__clamp-text`. |
|
|
63
|
+
| `.juno-table__wrap` | Full value; row grows. Reserve for one descriptive column. |
|
|
64
|
+
|
|
65
|
+
All three cap at `--juno-cell-max` (default 240px).
|
|
66
|
+
|
|
67
|
+
### Stacked mode (phone widths)
|
|
68
|
+
|
|
69
|
+
Wide tables don't shrink — they either scroll (the default: `.juno-table-scroll`
|
|
70
|
+
scrolls sideways too) or **stack**. Opt in with `.juno-table--stack`, give every
|
|
71
|
+
`td` a `data-label` echoing its column header, and make the wrapper a container:
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<div class="juno-table-scroll" style="container-type: inline-size">
|
|
75
|
+
<table class="juno-table juno-table--stack">
|
|
76
|
+
<tbody>
|
|
77
|
+
<tr>
|
|
78
|
+
<td data-label="FLIGHT" class="juno-table__id">JU-204</td>
|
|
79
|
+
<td data-label="ALT" class="juno-table__num">37,000</td>
|
|
80
|
+
</tr>
|
|
81
|
+
</tbody>
|
|
82
|
+
</table>
|
|
83
|
+
</div>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Below a 480px container the header row hides, each row becomes a bordered card,
|
|
87
|
+
and each cell renders as a label/value pair (the `data-label` becomes the label).
|
|
88
|
+
The selection rail moves to the card's edge, and row actions stay visible (no
|
|
89
|
+
hover on touch). Semantics stay a real `<table>` — only the display flips.
|
|
90
|
+
|
|
91
|
+
### Framing rows
|
|
92
|
+
|
|
93
|
+
`.juno-table__toolbar` (top), `.juno-table__foot` (bottom), and `.juno-table__bulk`
|
|
94
|
+
(the selection bar — role `active`, with `.juno-table__bulk-count`) are flex rows you
|
|
95
|
+
stack around the scroll viewport. Frame the whole thing in a [`.juno-card`](./card.md)
|
|
96
|
+
for the border + radius + clipped corners.
|
|
97
|
+
|
|
98
|
+
### States
|
|
99
|
+
|
|
100
|
+
- `.juno-table__skeleton` — shimmer bar for loading rows (honors `prefers-reduced-motion`).
|
|
101
|
+
- `.juno-table__empty` + `.juno-table__empty-icon` — the no-data block.
|
|
102
|
+
|
|
103
|
+
## Anatomy (any platform)
|
|
104
|
+
|
|
105
|
+
- Header: `s2`, `font.size.10` uppercase `label`, `control-edge` underline, sticky.
|
|
106
|
+
- Body cell: `space.12`/`space.16` padding (`space.8` block when compact), `border` rule,
|
|
107
|
+
`data` text. Numerics mono + bold + end-aligned.
|
|
108
|
+
- Selected row: `active` left rail (`border.width.3`) + `color-mix(active 11%)` wash.
|
|
109
|
+
- Status is a soft badge per row; caution / warning tint **only the note**, never the
|
|
110
|
+
whole row, so the grid stays calm.
|
|
111
|
+
|
|
112
|
+
## Usage (the app's half)
|
|
113
|
+
|
|
114
|
+
junoui can't sort or select in CSS — wire these and keep the ARIA in sync:
|
|
115
|
+
|
|
116
|
+
- **Sort:** click a `th`; set its `aria-sort` to `ascending` / `descending` (others to
|
|
117
|
+
`none`) and reorder the rows.
|
|
118
|
+
- **Select:** a `.juno-checkbox` per row (in a `.juno-table__check` cell) toggles
|
|
119
|
+
`aria-selected` on the `<tr>`; reflect the count in a `.juno-table__bulk` bar. The
|
|
120
|
+
header "select all" checkbox drives every visible row (use `indeterminate` for a
|
|
121
|
+
partial set).
|
|
122
|
+
- **Inline edit:** swap the cell's text for an [`.juno-input`](./input.md) on
|
|
123
|
+
double-click; Enter commits, Esc cancels.
|
|
124
|
+
- **Paginate / filter:** owned by the app; `.juno-table__foot` is just the frame.
|
|
125
|
+
|
|
126
|
+
`showcase/app.js` (`initTables`) is a reference driver for sort + selection.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Tabs
|
|
2
|
+
|
|
3
|
+
A horizontal tablist with an active-cyan underline; the selected tab shows its panel.
|
|
4
|
+
junoui ships the look + the ARIA contract; the app owns switching, panel visibility, and
|
|
5
|
+
arrow-key roving focus.
|
|
6
|
+
|
|
7
|
+
## Web
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<div class="juno-tabs">
|
|
11
|
+
<div class="juno-tabs__list" role="tablist" aria-label="Service detail">
|
|
12
|
+
<button class="juno-tabs__tab" role="tab" id="t1" aria-controls="p1" aria-selected="true">
|
|
13
|
+
OVERVIEW
|
|
14
|
+
</button>
|
|
15
|
+
<button class="juno-tabs__tab" role="tab" id="t2" aria-controls="p2" aria-selected="false">
|
|
16
|
+
METRICS
|
|
17
|
+
</button>
|
|
18
|
+
<button
|
|
19
|
+
class="juno-tabs__tab"
|
|
20
|
+
role="tab"
|
|
21
|
+
id="t3"
|
|
22
|
+
aria-controls="p3"
|
|
23
|
+
aria-selected="false"
|
|
24
|
+
disabled
|
|
25
|
+
>
|
|
26
|
+
CONFIG
|
|
27
|
+
</button>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="juno-tabs__panel" role="tabpanel" id="p1" aria-labelledby="t1">…</div>
|
|
30
|
+
<div class="juno-tabs__panel" role="tabpanel" id="p2" aria-labelledby="t2" hidden>…</div>
|
|
31
|
+
<div class="juno-tabs__panel" role="tabpanel" id="p3" aria-labelledby="t3" hidden>…</div>
|
|
32
|
+
</div>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Class | Effect |
|
|
36
|
+
| -------------------------------- | -------------------------------------------------------------- |
|
|
37
|
+
| `.juno-tabs__list` | The `role="tablist"` row; bottom rule the tabs sit on. |
|
|
38
|
+
| `.juno-tabs__tab` | A tab button. `label` at rest → `data` on hover. |
|
|
39
|
+
| `.juno-tabs__tab[aria-selected]` | Selected: `active` text + `active` underline indicator. |
|
|
40
|
+
| `.juno-tabs__tab:disabled` | Dimmed, not selectable. |
|
|
41
|
+
| `.juno-tabs__panel` | The `role="tabpanel"`; `[hidden]` when its tab isn't selected. |
|
|
42
|
+
|
|
43
|
+
## Anatomy (any platform)
|
|
44
|
+
|
|
45
|
+
- Tabs sit on a 1px `border` rule; the selected tab paints a `border.width.2` `active`
|
|
46
|
+
underline that overlaps the rule. Text `label` → `active` when selected.
|
|
47
|
+
- Panel gets `space.20` of leading space above its content.
|
|
48
|
+
|
|
49
|
+
## Usage (the app's half)
|
|
50
|
+
|
|
51
|
+
junoui can't switch panels in CSS — wire it and keep the ARIA in sync:
|
|
52
|
+
|
|
53
|
+
- On tab activation: set its `aria-selected="true"` (others `false`), unhide its panel
|
|
54
|
+
(`[hidden]` on the rest), and move the roving `tabindex` (selected = `0`, rest = `-1`).
|
|
55
|
+
- **Keyboard:** `←` / `→` move between tabs (wrapping), `Home` / `End` jump to the ends;
|
|
56
|
+
activation follows focus. `showcase/app.js` (`initTabs`) is a reference driver.
|
|
57
|
+
- For a stable layout, give panels equal-ish height or let content flow; don't animate
|
|
58
|
+
height unless you measure it.
|
|
59
|
+
- Tabs never wrap: when the strip runs out of room (phone widths) it scrolls
|
|
60
|
+
sideways, so every tab stays reachable. Keep labels short anyway — a scrolled
|
|
61
|
+
tab is a hidden tab until swiped to.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Thumb
|
|
2
|
+
|
|
3
|
+
A media frame that never shows the browser's broken-image glyph. A muted
|
|
4
|
+
placeholder (icon on `s2`) sits under the media; the image covers it while
|
|
5
|
+
present. **Loading** is [skeleton](./skeleton.md)'s job — thumb handles media
|
|
6
|
+
that is **missing or failed**.
|
|
7
|
+
|
|
8
|
+
## Web
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<!-- normal: image covers the placeholder; aspect defaults to square -->
|
|
12
|
+
<figure class="juno-thumb">
|
|
13
|
+
<img src="…" alt="Sunset clip" onerror="this.remove()" />
|
|
14
|
+
</figure>
|
|
15
|
+
|
|
16
|
+
<!-- non-square: override the ratio, not the aspect-ratio property -->
|
|
17
|
+
<figure
|
|
18
|
+
class="juno-thumb juno-thumb--video"
|
|
19
|
+
style="--juno-thumb-ratio: 16/9"
|
|
20
|
+
role="img"
|
|
21
|
+
aria-label="Preview unavailable"
|
|
22
|
+
>
|
|
23
|
+
<figcaption class="juno-thumb__label">Unavailable</figcaption>
|
|
24
|
+
</figure>
|
|
25
|
+
|
|
26
|
+
<!-- selected, with corner overlays: a check top-left, a duration top-right -->
|
|
27
|
+
<figure class="juno-thumb juno-thumb--selected">
|
|
28
|
+
<img src="…" alt="Sunset clip" onerror="this.remove()" />
|
|
29
|
+
<span class="juno-thumb__corner juno-thumb__corner--top-start badge badge--sm">✓</span>
|
|
30
|
+
<span class="juno-thumb__corner juno-thumb__corner--top-end badge badge--sm">0:42</span>
|
|
31
|
+
</figure>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Class / attr | Effect |
|
|
35
|
+
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
36
|
+
| `.juno-thumb` | Frame: `s2` fill, hairline border, `radius.3`, centered glyph, aspect locked to `--juno-thumb-ratio` (default `1`). |
|
|
37
|
+
| `.juno-thumb--flush` | Drops the border/radius — full-bleed tiles in a tight wall. |
|
|
38
|
+
| `.juno-thumb--selected` | Inset outline (`--juno-active`) — never a border, so nothing reflows on toggle. Apps own the state; junoui never adds/removes the class. |
|
|
39
|
+
| `.juno-thumb--video` | Play glyph instead of the image glyph. |
|
|
40
|
+
| `.juno-thumb__label` | Optional uppercase micro-caption under the glyph. |
|
|
41
|
+
| `.juno-thumb__corner` | Absolutely-positioned slot over the media, `space.4` inset from the frame edge, above the media (`z-index: 1`). Pair with one position modifier. |
|
|
42
|
+
| `.juno-thumb__corner--top-start` / `--top-right` / `--bottom-left` / `--bottom-right` | Anchors the slot to a corner using logical `inset-block-*` / `inset-inline-*` — start/end swap correctly under `dir="rtl"`. |
|
|
43
|
+
| `> img` / `> video` | Covers the frame (`object-fit: cover`). |
|
|
44
|
+
| `onerror="this.remove()"` | The whole JS contract — optional, stateless, one attribute. |
|
|
45
|
+
|
|
46
|
+
## Anatomy (any platform)
|
|
47
|
+
|
|
48
|
+
- Frame: surface `s2`, 1px `border`, radius `3`; aspect locked by
|
|
49
|
+
`--juno-thumb-ratio` (default square) so a media wall's scroll height is
|
|
50
|
+
stable before anything loads — override per instance
|
|
51
|
+
(`style="--juno-thumb-ratio: 16/9"`) or via the [tiles grid](../layout.md).
|
|
52
|
+
- Glyph: 28% of the frame (capped `space.32`), `muted` color — a missing thumb
|
|
53
|
+
is **not** a warning state; the placeholder stays neutral.
|
|
54
|
+
- Media covers the full frame, center-cropped.
|
|
55
|
+
- Selection is an inset outline, not a border — the frame's box never
|
|
56
|
+
changes size, so a wall re-flowing selection doesn't jitter.
|
|
57
|
+
- Corner slots are presentational anchors only; what occupies them (check
|
|
58
|
+
icon, duration chip, storage-tier badge) is app vocabulary.
|
|
59
|
+
|
|
60
|
+
## Failure contract
|
|
61
|
+
|
|
62
|
+
There is no portable CSS-only way to detect a broken image, so the contract is
|
|
63
|
+
explicit:
|
|
64
|
+
|
|
65
|
+
- **Failed to load** → `onerror="this.remove()"`: the broken element removes
|
|
66
|
+
itself, the placeholder underneath shows.
|
|
67
|
+
- **Known missing** (offline node, purged cache, no permission) → render no
|
|
68
|
+
media element at all.
|
|
69
|
+
- When no media renders, the alt text is gone too — put the accessible name on
|
|
70
|
+
the figure (`role="img"` + `aria-label`) or show a `__label`.
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
- Media walls (pairs with `.juno-grid-auto--tiles`), avatars' big cousin,
|
|
75
|
+
video poster slots, attachment previews.
|
|
76
|
+
- Keep the placeholder neutral; if failure _matters_ (broken pipeline), say it
|
|
77
|
+
with a [badge](./badge.md) or [alert](./alert.md) next to the thumb.
|
|
78
|
+
- Multi-select galleries: toggle `--selected` per tile and put a check in a
|
|
79
|
+
`__corner` slot; duration/storage-tier chips are `__corner` occupants too.
|
|
80
|
+
- Retry, lazy-load, LQIP/blur-up, and the selection/click behavior itself:
|
|
81
|
+
app or `junoui-<framework>` territory.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Toast / snackbar
|
|
2
|
+
|
|
3
|
+
A transient, floating notification. Same role-rail language as the [alert](./alert.md),
|
|
4
|
+
but elevated and stacked in a fixed corner on the reserved **alert layer**
|
|
5
|
+
(`--juno-z-alert`, above modals). junoui ships the look + enter/exit motion; the app owns
|
|
6
|
+
creation, auto-dismiss timing, and the live-region announcement.
|
|
7
|
+
|
|
8
|
+
## Web
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<!-- one stack per corner; the app appends toasts into it -->
|
|
12
|
+
<div class="juno-toast-stack" id="toasts" aria-live="polite"></div>
|
|
13
|
+
|
|
14
|
+
<!-- a toast (app-created) -->
|
|
15
|
+
<div class="juno-toast juno--nominal" role="status">
|
|
16
|
+
<span class="juno-toast__icon" aria-hidden="true">✓</span>
|
|
17
|
+
<span class="juno-toast__text">Build promoted.</span>
|
|
18
|
+
<button class="juno-toast__close" aria-label="Dismiss">✕</button>
|
|
19
|
+
</div>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Class | Effect |
|
|
23
|
+
| ------------------------------------------ | ------------------------------------------------------------------- |
|
|
24
|
+
| `.juno-toast-stack` | Fixed container on `z.alert`; bottom-end, stacks its toasts. |
|
|
25
|
+
| `.juno-toast-stack--top` / `--start` | Move the stack to the top / inline-start. |
|
|
26
|
+
| `.juno-toast` | `s2` surface, `shadow.2`, role start-rail. Default `active`. |
|
|
27
|
+
| `.juno-toast--leaving` | Exit state (app adds it, then removes the node on `transitionend`). |
|
|
28
|
+
| `.juno-toast__icon` / `__text` / `__close` | Glyph · message · dismiss. |
|
|
29
|
+
| `.juno--<role>` | Sets the rail + icon color. |
|
|
30
|
+
|
|
31
|
+
## Anatomy (any platform)
|
|
32
|
+
|
|
33
|
+
- Stack: `position: fixed`, `z.alert` (5000), `inline-size: min(360px, …)`, `pointer-events:
|
|
34
|
+
none` so only the toasts catch clicks.
|
|
35
|
+
- Toast: solid `s2` + `shadow.2` + role rail. Enters via `@starting-style` (fade + slide),
|
|
36
|
+
exits on `.juno-toast--leaving`; both honor `prefers-reduced-motion`.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
- The app creates and destroys toasts: append to the stack, start a timer (~4s), then add
|
|
41
|
+
`.juno-toast--leaving` and remove on `transitionend`. `showcase/app.js` (`showToast`) is a
|
|
42
|
+
reference driver.
|
|
43
|
+
- Put `aria-live="polite"` on the stack (`assertive` for errors) so new toasts announce.
|
|
44
|
+
- Keep messages short and self-contained; one line. For anything needing a decision, use a
|
|
45
|
+
[modal](./modal.md) or inline [alert](./alert.md).
|
|
46
|
+
- **Phone widths (< `bp.sm`) are automatic:** the stack goes full-width along the
|
|
47
|
+
bottom edge (thumb reach), clear of the home indicator, and toasts slide up
|
|
48
|
+
instead of sideways. No extra class.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Toggle button
|
|
2
|
+
|
|
3
|
+
An Airbus-style illuminated-legend pushbutton: the body stays dark; a top strip lights
|
|
4
|
+
(`nominal`) and the surround glows when engaged. A real `<button aria-pressed>`; the app
|
|
5
|
+
flips `aria-pressed`. Use for panel-style on/off controls where the lit legend matters.
|
|
6
|
+
|
|
7
|
+
## Web
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<button class="juno-toggle-btn" aria-pressed="true">
|
|
11
|
+
<span class="juno-toggle-btn__strip"></span>
|
|
12
|
+
<span class="juno-toggle-btn__row">
|
|
13
|
+
<span class="juno-toggle-btn__text">
|
|
14
|
+
<span class="juno-toggle-btn__legend">AUTO-SCALING</span>
|
|
15
|
+
<span class="juno-toggle-btn__desc">Scale workers with load</span>
|
|
16
|
+
</span>
|
|
17
|
+
<span class="juno-toggle-btn__status">ON</span>
|
|
18
|
+
</span>
|
|
19
|
+
</button>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Class | Effect |
|
|
23
|
+
| -------------------------------------------------- | --------------------------------------------------- |
|
|
24
|
+
| `.juno-toggle-btn` | Pushbutton tile on `control-surface`. |
|
|
25
|
+
| `[aria-pressed="true"]` | Border → role, surround glow, strip + status light. |
|
|
26
|
+
| `.juno-toggle-btn__strip` | Top legend strip; `s3` (off) → role (on) with glow. |
|
|
27
|
+
| `.juno-toggle-btn__legend` / `__desc` / `__status` | Mono legend, sub-label, ON/OFF status. |
|
|
28
|
+
| `.juno--<role>` | Lit color (default `nominal`). |
|
|
29
|
+
| `:disabled` | Dimmed, not-allowed. |
|
|
30
|
+
|
|
31
|
+
## Anatomy (any platform)
|
|
32
|
+
|
|
33
|
+
- Tile border `control-edge` → role when pressed, plus a 20% role outer glow. Strip
|
|
34
|
+
`space.4` tall lights to role with an 8px glow. `motion.duration.quick` transitions.
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
- A latching control whose engaged state must read at a glance (system arm/enable).
|
|
39
|
+
- Use a real `<button>` and keep `aria-pressed` in sync; for inline on/off in a form,
|
|
40
|
+
prefer the [switch](./switch.md).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Tooltip
|
|
2
|
+
|
|
3
|
+
A transient hover/focus label. Pure CSS reveal — no JS. Four placements with an arrow.
|
|
4
|
+
|
|
5
|
+
## Web
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<span class="juno-tooltip">
|
|
9
|
+
<button tabindex="0">SPD</button>
|
|
10
|
+
<span class="juno-tooltip__bubble" role="tooltip">
|
|
11
|
+
Requests / sec · 248
|
|
12
|
+
<span class="juno-tooltip__arrow"></span>
|
|
13
|
+
</span>
|
|
14
|
+
</span>
|
|
15
|
+
|
|
16
|
+
<!-- placements -->
|
|
17
|
+
<span class="juno-tooltip__bubble juno-tooltip__bubble--right">…</span>
|
|
18
|
+
<span class="juno-tooltip__bubble juno-tooltip__bubble--bottom">…</span>
|
|
19
|
+
<span class="juno-tooltip__bubble juno-tooltip__bubble--left">…</span>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Class | Effect |
|
|
23
|
+
| ----------------------------------------------- | -------------------------------------------------------- |
|
|
24
|
+
| `.juno-tooltip` | Relative wrapper around the trigger. |
|
|
25
|
+
| `.juno-tooltip__bubble` | `s3` bubble, mono 11px, shadow `2`, `z.anchored` (2000). |
|
|
26
|
+
| `--top` (default) `--right` `--bottom` `--left` | Placement of the bubble + arrow. |
|
|
27
|
+
| `.juno-tooltip__arrow` | Rotated-square pointer back to the trigger. |
|
|
28
|
+
|
|
29
|
+
Shows on `:hover` or `:focus-within` of the wrapper; `motion.duration.quick` (140ms)
|
|
30
|
+
/ `ease.decel` rise.
|
|
31
|
+
|
|
32
|
+
## Top-layer mode (escaping clipping)
|
|
33
|
+
|
|
34
|
+
The pure-CSS reveal is clipped if an ancestor sets `overflow`/`clip` (cards, scroll
|
|
35
|
+
areas). To lift it above everything, promote the bubble to a `popover="hint"` — it then
|
|
36
|
+
renders in the browser **top layer**, immune to ancestor clipping. The bubble already
|
|
37
|
+
carries `:popover-open` + anchor-positioning styles; a tiny stateless enhancer toggles it
|
|
38
|
+
and points `position-anchor` at the trigger:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
const name = `--juno-tip-${i}`;
|
|
42
|
+
trigger.style.anchorName = name;
|
|
43
|
+
bubble.style.positionAnchor = name;
|
|
44
|
+
bubble.popover = 'hint';
|
|
45
|
+
trigger.addEventListener('pointerenter', () => bubble.showPopover());
|
|
46
|
+
trigger.addEventListener('pointerleave', () => bubble.hidePopover());
|
|
47
|
+
trigger.addEventListener('focus', () => bubble.showPopover());
|
|
48
|
+
trigger.addEventListener('blur', () => bubble.hidePopover());
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
(`showcase/app.js` ships this as `initTooltips()`.) With no enhancer the component still
|
|
52
|
+
works as the CSS-only hover tooltip — just clippable by its container.
|
|
53
|
+
|
|
54
|
+
## Anatomy (any platform)
|
|
55
|
+
|
|
56
|
+
- Bubble offset `space.8` from the trigger edge; small rise on reveal.
|
|
57
|
+
- Content is mono (codes/values); single line (`white-space: nowrap`).
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
- Reference text only — never put focusable controls in a tooltip (use a [popover](./popover.md)).
|
|
62
|
+
- Give the trigger a tabstop and the bubble `role="tooltip"` + `aria-describedby` so it
|
|
63
|
+
reveals on keyboard focus, not just hover.
|