@junoput01/junoui 0.2.0 → 0.3.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 +32 -0
- package/dist/css/juno.css +162 -3
- package/docs/accessibility.md +167 -0
- package/docs/components/README.md +68 -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 +56 -0
- package/docs/components/drawer.md +60 -0
- package/docs/components/field.md +44 -0
- package/docs/components/gauge.md +48 -0
- package/docs/components/icon-loader.md +55 -0
- package/docs/components/icon.md +49 -0
- package/docs/components/input.md +45 -0
- package/docs/components/list.md +76 -0
- package/docs/components/loader.md +80 -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 +64 -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/segmented.md +46 -0
- package/docs/components/select.md +33 -0
- package/docs/components/skeleton.md +38 -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 +61 -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 +147 -0
- package/docs/flutter.md +42 -0
- package/docs/getting-started.md +70 -0
- package/docs/integration.md +95 -0
- package/docs/layout.md +201 -0
- package/docs/native.md +52 -0
- package/docs/roadmap.md +106 -0
- package/docs/tokens-reference.md +223 -0
- package/docs/web.md +89 -0
- package/package.json +3 -2
- package/src/css/base.css +7 -0
- package/src/css/components/dock.css +13 -0
- package/src/css/components/icon-loader.css +53 -0
- package/src/css/components/pillbar.css +15 -0
- package/src/css/components/rail.css +8 -0
- package/src/css/layout.css +65 -3
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Badge / status indicator
|
|
2
|
+
|
|
3
|
+
A compact, uppercase status label.
|
|
4
|
+
|
|
5
|
+
## Web
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<span class="juno-badge juno--nominal">NOMINAL</span>
|
|
9
|
+
<span class="juno-badge juno-badge--outline juno--caution">CAUTION</span>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Class | Effect |
|
|
13
|
+
| ---------------------- | ---------------------------------------------- |
|
|
14
|
+
| `.juno-badge` | Base. Filled: background = role, text = `s0`. |
|
|
15
|
+
| `.juno-badge--outline` | Transparent fill, text + border = role. |
|
|
16
|
+
| `.juno-badge--soft` | Low-fill chip: role text on a 13% role wash. |
|
|
17
|
+
| `.juno-badge--micro` | Data-UI atom: mono 10px, hairline role border. |
|
|
18
|
+
| `.juno--<role>` | Sets the color (required). |
|
|
19
|
+
|
|
20
|
+
## Anatomy (any platform)
|
|
21
|
+
|
|
22
|
+
- Font: B612, 700 weight, size `font.size.11`, uppercase, tracking `font.tracking.caps` (0.15em).
|
|
23
|
+
- Padding: `space.4` vertical, `space.10` horizontal. Radius: `radius.3`.
|
|
24
|
+
- **Filled:** fill = role color, text = `s0` (base surface).
|
|
25
|
+
- **Outline:** transparent fill, text + 1px border = role color.
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
- Use the semantic roles for status; `muted` for inactive/disabled.
|
|
30
|
+
- Keep the text the literal status word — color reinforces, never replaces it.
|
|
31
|
+
- `--micro` is for provenance/kind tags (`device`, `TRANSCODE`, model names) and
|
|
32
|
+
threshold values that repeat dozens of times per screen. Threshold coloring is app
|
|
33
|
+
policy — map value → role class yourself, e.g.
|
|
34
|
+
`juno-badge--micro juno--nominal` for a ≥ 90% confidence. Same recipe as the
|
|
35
|
+
[gauge](./gauge.md) thresholds.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Breadcrumb
|
|
2
|
+
|
|
3
|
+
A horizontal trail of links to ancestor pages, ending at the current page. Built on a
|
|
4
|
+
real `<nav><ol>`; the separator is a CSS chevron (no glyph font). Zero JS.
|
|
5
|
+
|
|
6
|
+
## Web
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<nav class="juno-breadcrumb" aria-label="Breadcrumb">
|
|
10
|
+
<ol>
|
|
11
|
+
<li><a href="/">Home</a></li>
|
|
12
|
+
<li><a href="/fleet">Fleet</a></li>
|
|
13
|
+
<li><a aria-current="page">api-gateway</a></li>
|
|
14
|
+
</ol>
|
|
15
|
+
</nav>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Part / attr | Effect |
|
|
19
|
+
| ----------------------- | ---------------------------------------------------- |
|
|
20
|
+
| `.juno-breadcrumb` | `<nav>` wrapper; lay out an `<ol>` of `<li>` inside. |
|
|
21
|
+
| `li + li::before` | CSS chevron separator (rotates under RTL). |
|
|
22
|
+
| `a[href]` | `label` link → `data` + underline on hover. |
|
|
23
|
+
| `[aria-current="page"]` | The current crumb — brightest, semibold, not a link. |
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
- Always `aria-label="Breadcrumb"` on the `<nav>`, and `aria-current="page"` on the last
|
|
28
|
+
crumb (drop its `href` so it isn't a link).
|
|
29
|
+
- Order matters: root → … → current, left to right (mirrors under `dir="rtl"`).
|
|
30
|
+
- For very deep trails, collapse the middle to an ellipsis crumb the app expands — junoui
|
|
31
|
+
ships the look, the app owns the collapse.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Button
|
|
2
|
+
|
|
3
|
+
## Web
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<button class="juno-btn juno--nominal">CONFIRM</button>
|
|
7
|
+
<button class="juno-btn juno-btn--ghost">CANCEL</button>
|
|
8
|
+
<button class="juno-btn juno-btn--sm juno-btn--ghost">EDIT</button>
|
|
9
|
+
<button class="juno-btn" disabled>DISABLED</button>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Class | Effect |
|
|
13
|
+
| ------------------ | -------------------------------------------------------------------------------- |
|
|
14
|
+
| `.juno-btn` | Base. Primary (filled): background = role, text = `s0`. Default role = `active`. |
|
|
15
|
+
| `.juno-btn--ghost` | Transparent, `data` text, `border` outline; hover → `s2`. |
|
|
16
|
+
| `.juno-btn--sm` | Dense-toolbar size: `font.size.11`, `space.4` × `space.10`, `radius.3`. |
|
|
17
|
+
| `.juno--<role>` | Sets the primary fill color. |
|
|
18
|
+
| `:disabled` | `muted` fill, `label` text, not-allowed. |
|
|
19
|
+
|
|
20
|
+
## Anatomy (any platform)
|
|
21
|
+
|
|
22
|
+
- Font: B612, 700 weight, size `font.size.13`, uppercase, tracking `font.tracking.caps`.
|
|
23
|
+
- Padding: `space.10` × `space.20`. Radius: `radius.4`. Min height: `size.tap.min` (24px; use 44px on mobile).
|
|
24
|
+
- States: hover brighten ~8%, active darken ~6%, disabled = `muted`/`label`.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
- Primary action filled with `nominal` (confirm) or `active` (apply).
|
|
29
|
+
- `warning` fill only for genuinely critical/destructive actions.
|
|
30
|
+
- One primary per group; everything else is ghost.
|
|
31
|
+
- `--sm` drops below the WCAG tap-minimum on purpose — it is for dense **desktop**
|
|
32
|
+
toolbars (40–46px chrome bars). Keep the default size anywhere touch is expected.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Card / panel
|
|
2
|
+
|
|
3
|
+
A surface grouping a titled header and a body.
|
|
4
|
+
|
|
5
|
+
## Web
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<article class="juno-card juno-card--accent juno--caution">
|
|
9
|
+
<header class="juno-card__head">
|
|
10
|
+
HYD SYS B
|
|
11
|
+
<span class="juno-badge juno-badge--outline juno--caution">CAUTION</span>
|
|
12
|
+
</header>
|
|
13
|
+
<div class="juno-card__body">
|
|
14
|
+
<div class="juno-card__row">
|
|
15
|
+
<span class="juno-label">Pressure</span>
|
|
16
|
+
<span class="juno-value juno-text-caution">2,650</span>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</article>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Class | Effect |
|
|
23
|
+
| -------------------- | ------------------------------------------------------ |
|
|
24
|
+
| `.juno-card` | `s1` surface, 1px `border`, radius `radius.8`. |
|
|
25
|
+
| `.juno-card--accent` | 2px top edge in the role color (status hint). |
|
|
26
|
+
| `.juno-card--alert` | Full border in role + tinted header — critical panels. |
|
|
27
|
+
| `.juno-card__head` | Uppercase title row; holds a status badge. |
|
|
28
|
+
| `.juno-card__body` | Padded content column. |
|
|
29
|
+
| `.juno-card__row` | Label-left / value-right baseline row. |
|
|
30
|
+
|
|
31
|
+
## Anatomy (any platform)
|
|
32
|
+
|
|
33
|
+
- Surface `s1`, border `border` 1px, radius `radius.8`.
|
|
34
|
+
- Header: padding `space.12`/`space.16`, bottom 1px divider, title B612 600 uppercase tracking `wide`.
|
|
35
|
+
- Body: padding `space.16`, rows gapped `space.12`.
|
|
36
|
+
- Escalation: accent (2px top) → alert (full role border + `s2` header tinted in role).
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
- One subject per card. Header carries the identifier + a status badge.
|
|
41
|
+
- Match accent/alert role to the card's worst current status.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Checkbox & Radio
|
|
2
|
+
|
|
3
|
+
Custom-styled native inputs (`appearance: none`) — keyboard and screen-reader support
|
|
4
|
+
come for free. The checkbox is a **targeting-reticle** square whose solid core drops in
|
|
5
|
+
on check; the radio is a ring with a center dot. Wrap with `.juno-choice` for a label row.
|
|
6
|
+
|
|
7
|
+
## Web
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<label class="juno-choice"> <input class="juno-checkbox" type="checkbox" checked /> TCAS </label>
|
|
11
|
+
|
|
12
|
+
<label class="juno-choice"> <input class="juno-radio" type="radio" name="mode" /> SELECTED </label>
|
|
13
|
+
<label class="juno-choice">
|
|
14
|
+
<input class="juno-radio juno--target" type="radio" name="mode" checked /> MANAGED
|
|
15
|
+
</label>
|
|
16
|
+
|
|
17
|
+
<label class="juno-choice">
|
|
18
|
+
<input class="juno-checkbox" type="checkbox" disabled /> Restricted
|
|
19
|
+
</label>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Class | Effect |
|
|
23
|
+
| ---------------- | --------------------------------------------------------- |
|
|
24
|
+
| `.juno-checkbox` | `space.16` reticle square; checked core + role ring-glow. |
|
|
25
|
+
| `.juno-radio` | Same as a circle with a center dot. |
|
|
26
|
+
| `.juno-choice` | Inline-flex label row; `gap-control`, `data` text. |
|
|
27
|
+
| `.juno--<role>` | Recolors the core/dot (default `active`). |
|
|
28
|
+
| `:checked` | Border → role, 3px role glow, core scales in (spring). |
|
|
29
|
+
| `:disabled` | `s1` + dimmed; row text → `muted`. |
|
|
30
|
+
|
|
31
|
+
## Anatomy (any platform)
|
|
32
|
+
|
|
33
|
+
- Box `space.16` on `control-surface` with a `control-edge` border; checked adds a
|
|
34
|
+
`border-width.3` ring at 22% role and a `space.8` core (spring scale-in).
|
|
35
|
+
- Label row: B612 `font.size.13`, `data`, `gap-control` between box and text.
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
- Checkbox = independent toggles; radio = one-of-many (share a `name`).
|
|
40
|
+
- Keep the label inside the same `<label>` so the hit area covers both.
|
|
41
|
+
- For a single on/off with an emphasized track, use the [switch](./switch.md).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Chip / Tag
|
|
2
|
+
|
|
3
|
+
A compact pill for a discrete entity — a filter, a selected value, a removable tag.
|
|
4
|
+
Where a [badge](./badge.md) is a **static** status label, a chip is **interactive**:
|
|
5
|
+
selectable and/or dismissible. Reads `--juno-role` for its accent; the app owns
|
|
6
|
+
selection and removal (zero JS).
|
|
7
|
+
|
|
8
|
+
## Web
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<!-- plain tag -->
|
|
12
|
+
<span class="juno-chip">us-east-1</span>
|
|
13
|
+
|
|
14
|
+
<!-- role-tinted -->
|
|
15
|
+
<span class="juno-chip juno--active">live</span>
|
|
16
|
+
|
|
17
|
+
<!-- toggle (filter) chip -->
|
|
18
|
+
<button class="juno-chip juno-chip--toggle juno--active" aria-pressed="true">Errors</button>
|
|
19
|
+
|
|
20
|
+
<!-- removable -->
|
|
21
|
+
<span class="juno-chip">
|
|
22
|
+
filter:prod
|
|
23
|
+
<button class="juno-chip__remove" aria-label="Remove prod filter">
|
|
24
|
+
<svg class="juno-icon juno-icon--sm" aria-hidden="true"><use href="…#juno-i-x" /></svg>
|
|
25
|
+
</button>
|
|
26
|
+
</span>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Class | Effect |
|
|
30
|
+
| -------------------- | ------------------------------------------------------------ |
|
|
31
|
+
| `.juno-chip` | Pill; `control-surface` fill, strong border, `data` text. |
|
|
32
|
+
| `.juno--<role>` | Role accent (border + tinted fill + role text). |
|
|
33
|
+
| `.juno-chip--toggle` | Use on a `<button>`; `aria-pressed="true"` fills the accent. |
|
|
34
|
+
| `.juno-chip__remove` | Trailing dismiss button (put an `x` icon inside; label it). |
|
|
35
|
+
| `:disabled` | Dims + blocks pointer. |
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
- **Toggle chip:** a real `<button>`; the app flips `aria-pressed`. Use for filter sets.
|
|
40
|
+
- **Removable chip:** the `__remove` button needs an `aria-label` ("Remove X"); the app
|
|
41
|
+
deletes the chip on click.
|
|
42
|
+
- Chip vs badge: chip = interactive / user data; badge = read-only status. Don't make a
|
|
43
|
+
badge clickable — reach for a chip.
|
|
44
|
+
- Color is never the only signal — the chip's text carries the meaning; role is accent.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Divider
|
|
2
|
+
|
|
3
|
+
A hairline rule that separates content. Horizontal by default; vertical for a column
|
|
4
|
+
separator; or labeled to break the line with a centered caption.
|
|
5
|
+
|
|
6
|
+
## Web
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<!-- semantic horizontal break -->
|
|
10
|
+
<hr class="juno-divider" />
|
|
11
|
+
|
|
12
|
+
<!-- labeled -->
|
|
13
|
+
<div class="juno-divider juno-divider--label">OR</div>
|
|
14
|
+
|
|
15
|
+
<!-- vertical (inside a flex row) -->
|
|
16
|
+
<span class="juno-divider juno-divider--vertical"></span>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Class | Effect |
|
|
20
|
+
| ------------------------- | ------------------------------------------------------------------- |
|
|
21
|
+
| `.juno-divider` | Full-width `border`-colored hairline. |
|
|
22
|
+
| `.juno-divider--vertical` | Hairline column rule; stretches to the row (`align-self: stretch`). |
|
|
23
|
+
| `.juno-divider--label` | Caption centered between two rules (uppercase `label`). |
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
- Use a real `<hr>` for a **semantic** break; a `<span>` / `<div>` when it's purely
|
|
28
|
+
decorative.
|
|
29
|
+
- The vertical variant needs a parent that gives it block size — a flex row works
|
|
30
|
+
(`align-self: stretch`); otherwise set a height.
|
|
31
|
+
- Don't over-divide: whitespace separates most things. Reach for a rule only when groups
|
|
32
|
+
would otherwise read as one.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Dock
|
|
2
|
+
|
|
3
|
+
The bottom navigation bar of the app shell on narrow viewports — 3–5 primary
|
|
4
|
+
destinations as icon-over-label tap targets. The phone-width counterpart of the
|
|
5
|
+
[rail](./rail.md); the swap recipe is in [layout.md](../layout.md#app-shell).
|
|
6
|
+
|
|
7
|
+
## Web
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<nav class="juno-dock" aria-label="Primary">
|
|
11
|
+
<a class="juno-dock__item" href="/library" aria-current="page">
|
|
12
|
+
<svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
|
|
13
|
+
<span class="juno-dock__label">Library</span>
|
|
14
|
+
</a>
|
|
15
|
+
<a class="juno-dock__item" href="/nodes">
|
|
16
|
+
<svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-hexagon" /></svg>
|
|
17
|
+
<span class="juno-dock__label">Nodes</span>
|
|
18
|
+
</a>
|
|
19
|
+
</nav>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Class / prop | Effect |
|
|
23
|
+
| ------------------- | --------------------------------------------------------------------------------------------- |
|
|
24
|
+
| `.juno-dock` | Sticky bottom `s1` bar, 1px `border` seam on top, safe-area pad. |
|
|
25
|
+
| `.juno-dock__item` | Equal-width icon-over-label target, ≥ `size.tap.comfortable` tall. |
|
|
26
|
+
| `.juno-dock__label` | The text — truncates with an ellipsis, never wraps. |
|
|
27
|
+
| `[aria-current]` | Active item: `s2` fill + 2px role edge on top. Attribute, not class. |
|
|
28
|
+
| `.juno-dock--fixed` | Pin to the viewport foot (`position: fixed`) — for page-scroll shells where sticky won't pin. |
|
|
29
|
+
| `.juno--<role>` | Active-edge color (default `active`). |
|
|
30
|
+
|
|
31
|
+
## Anatomy (any platform)
|
|
32
|
+
|
|
33
|
+
- Full-width bar on `s1`, hairline seam on the block-start edge; items split the
|
|
34
|
+
width evenly, icon above a `font.size.10` uppercase label.
|
|
35
|
+
- Active = `s2` fill + `border.width.2` block-start edge in the role color —
|
|
36
|
+
the rail's active language rotated 90°.
|
|
37
|
+
- Bottom padding extends into the safe area (`env(safe-area-inset-bottom)`)
|
|
38
|
+
so the home indicator never covers a target.
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
- Keep it to 3–5 destinations; overflow belongs in a "More" item opening a
|
|
43
|
+
[drawer](./drawer.md) or [menu](./menu.md).
|
|
44
|
+
- Sticky, not fixed: place it last inside the scrolling column and it pins
|
|
45
|
+
itself without overlapping content (no bottom-padding hacks). Best is the
|
|
46
|
+
[`.juno-app-shell`](../layout.md#app-shell) frame, whose `__main` region is
|
|
47
|
+
the scroller — the dock then sits at the body foot in flow.
|
|
48
|
+
- **Short-page caveat:** sticky only pins while the column overflows. If the
|
|
49
|
+
_whole page_ scrolls and content is shorter than the viewport, the dock
|
|
50
|
+
lands mid-content. For that layout use `.juno-dock--fixed` (viewport-pinned)
|
|
51
|
+
and reserve its height at the page foot so it doesn't cover the last row.
|
|
52
|
+
- Pair with the rail via the viewport helpers: `.juno-hide-below-md` on the
|
|
53
|
+
rail, `.juno-hide-from-md` on the dock. One nav is hidden from the
|
|
54
|
+
accessibility tree at a time, so both may share `aria-label="Primary"`.
|
|
55
|
+
- The app sets `aria-current="page"` on the active item — junoui styles the
|
|
56
|
+
attribute so nav semantics stay honest.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Drawer
|
|
2
|
+
|
|
3
|
+
An edge-anchored `<dialog>` for secondary tasks and settings — same scrim and layer
|
|
4
|
+
as the [modal](./modal.md), but it slides along one axis. Reuses `.juno-modal` for the
|
|
5
|
+
surface; `.juno-drawer` re-pins and re-slides it.
|
|
6
|
+
|
|
7
|
+
## Web
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<dialog class="juno-modal juno-drawer">
|
|
11
|
+
<!-- header / body / footer, same parts as a modal -->
|
|
12
|
+
</dialog>
|
|
13
|
+
|
|
14
|
+
<dialog class="juno-modal juno-drawer juno-drawer--start">…</dialog>
|
|
15
|
+
<dialog class="juno-modal juno-drawer juno-drawer--bottom">…</dialog>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Class | Effect |
|
|
19
|
+
| ---------------------- | ------------------------------------------------------ |
|
|
20
|
+
| `.juno-drawer` | 380px, full height, pinned to the **inline-end** edge. |
|
|
21
|
+
| `.juno-drawer--start` | Pins to the inline-start edge. |
|
|
22
|
+
| `.juno-drawer--bottom` | Full width, 60dvh, pinned to the bottom edge. |
|
|
23
|
+
|
|
24
|
+
## Anatomy (any platform)
|
|
25
|
+
|
|
26
|
+
- Slide in from its edge, `motion.duration.base` (200ms) / `ease.decel`. Same scrim
|
|
27
|
+
(`opacity.scrim`) and shadow (`shadow.3`) as the modal.
|
|
28
|
+
- Edge anchoring is logical (`margin-inline`), so start/end mirror under RTL.
|
|
29
|
+
|
|
30
|
+
## The slide-over pattern
|
|
31
|
+
|
|
32
|
+
The full production composition — scrim, end-anchored panel on `s1`, header row,
|
|
33
|
+
scrolling body, pinned footer — assembled from existing parts. Copy-paste:
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<dialog class="juno-modal juno-drawer" aria-labelledby="tray-tag">
|
|
37
|
+
<div class="juno-modal__stripe"></div>
|
|
38
|
+
<div class="juno-modal__head">
|
|
39
|
+
<span class="juno-modal__tag" id="tray-tag">ACTIVE JOBS</span>
|
|
40
|
+
<button class="juno-modal__close" autofocus aria-label="Close">✕</button>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="juno-modal__body"><!-- scrolls on its own --></div>
|
|
43
|
+
<div class="juno-modal__foot">
|
|
44
|
+
<button class="juno-btn juno-btn--ghost">CLEAR DONE</button>
|
|
45
|
+
<button class="juno-btn juno--warning">PAUSE ALL</button>
|
|
46
|
+
</div>
|
|
47
|
+
</dialog>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`showModal()` provides the scrim (`::backdrop`, `opacity.scrim`) and z-order for
|
|
51
|
+
free — no scrim element, no z-index bookkeeping. Head/body/foot are the modal
|
|
52
|
+
parts; the drawer class only re-pins and re-slides the surface.
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
- Settings panels, filters, detail editors that don't warrant leaving context.
|
|
57
|
+
- Same `<dialog>` + `showModal()` contract as the modal.
|
|
58
|
+
- **Phone widths (< `bp.sm`) are automatic:** side drawers cap at `85vw` so a
|
|
59
|
+
sliver of scrim stays visible (and tappable) for dismissal. The bottom
|
|
60
|
+
drawer always pads past the home indicator (`safe-area-inset-bottom`).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Field
|
|
2
|
+
|
|
3
|
+
Wraps any control with a label, optional help text, and an error message. Pure
|
|
4
|
+
layout + the validation/required cue — it owns no state.
|
|
5
|
+
|
|
6
|
+
## Web
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<div class="juno-field">
|
|
10
|
+
<label class="juno-field__label" for="cs">
|
|
11
|
+
Order ID <span class="juno-field__req" aria-hidden="true">*</span>
|
|
12
|
+
</label>
|
|
13
|
+
<input id="cs" class="juno-input juno-mono" type="text" aria-required="true" />
|
|
14
|
+
<span class="juno-field__help">Prefix + number</span>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<!-- error -->
|
|
18
|
+
<div class="juno-field">
|
|
19
|
+
<label class="juno-field__label" for="sq">Error code</label>
|
|
20
|
+
<input id="sq" class="juno-input juno-mono" aria-invalid="true" aria-describedby="sq-e" />
|
|
21
|
+
<span class="juno-field__error" id="sq-e">Service unavailable</span>
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Class | Effect |
|
|
26
|
+
| -------------------- | ----------------------------------------------------------------------- |
|
|
27
|
+
| `.juno-field` | Vertical stack (label · control · help/error), `space.4` gap. |
|
|
28
|
+
| `.juno-field__label` | 10px uppercase, tracking `wider`, `label` color. |
|
|
29
|
+
| `.juno-field__req` | Required asterisk in `warning`. Decorative — pair with `aria-required`. |
|
|
30
|
+
| `.juno-field__help` | 11px `label` helper text. |
|
|
31
|
+
| `.juno-field__error` | 11px `warning` error text. |
|
|
32
|
+
|
|
33
|
+
## Anatomy (any platform)
|
|
34
|
+
|
|
35
|
+
- Stack label → control → message; gap `space.4`.
|
|
36
|
+
- Label: B612, `font.size.10`, uppercase, tracking `font.tracking.wider`, `label` color.
|
|
37
|
+
- Help `font.size.11` `label`; error `font.size.11` `warning`.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
- One control per field. Tie `for`/`id`, and `aria-describedby` to the help/error id.
|
|
42
|
+
- For errors, set `aria-invalid="true"` on the control (it re-colors its own border)
|
|
43
|
+
**and** show `.juno-field__error`. The asterisk is visual; required-ness is
|
|
44
|
+
`aria-required` on the control.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Gauge
|
|
2
|
+
|
|
3
|
+
A determinate metric ring — CPU / RAM / DISK readouts with the value centered.
|
|
4
|
+
The metric cousin of the [arc loader](./loader.md): the arc shows _progress of a
|
|
5
|
+
task_; the gauge shows _the current level of a quantity_. Pure CSS
|
|
6
|
+
(`conic-gradient`), no SVG in the markup.
|
|
7
|
+
|
|
8
|
+
## Web
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<div
|
|
12
|
+
class="juno-gauge juno-gauge--sm juno--nominal"
|
|
13
|
+
style="--juno-gauge-value: 67"
|
|
14
|
+
role="meter"
|
|
15
|
+
aria-valuenow="67"
|
|
16
|
+
aria-valuemin="0"
|
|
17
|
+
aria-valuemax="100"
|
|
18
|
+
aria-label="Disk"
|
|
19
|
+
>
|
|
20
|
+
<span class="juno-gauge__value">67</span>
|
|
21
|
+
</div>
|
|
22
|
+
<span class="juno-gauge__label">DISK</span>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Class / prop | Effect |
|
|
26
|
+
| -------------------- | ----------------------------------------------------------------------------- |
|
|
27
|
+
| `.juno-gauge` | 64px ring; sweep = `--juno-gauge-value` (0–100). |
|
|
28
|
+
| `.juno-gauge--sm` | 44px — dense card grids. |
|
|
29
|
+
| `.juno-gauge--lg` | 96px — hero metrics. |
|
|
30
|
+
| `.juno-gauge__value` | Centered mono readout, role-colored. |
|
|
31
|
+
| `.juno-gauge__label` | Caption (a sibling — place it under or beside the ring). |
|
|
32
|
+
| `.juno--<role>` | Ring + value color (default `active`). |
|
|
33
|
+
| `--juno-gauge-value` | The value, set inline or from JS. Registered (`@property`) so it transitions. |
|
|
34
|
+
|
|
35
|
+
## Anatomy (any platform)
|
|
36
|
+
|
|
37
|
+
- Ring: track = `border` color, fill sweep = role, round the ring `size / 16`
|
|
38
|
+
stroke (4px at 64). Value: mono, bold, same color as the sweep.
|
|
39
|
+
- Sweep starts at 12 o'clock, clockwise.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
- **Thresholds are app policy.** junoui ships no value → color rule; map it
|
|
44
|
+
yourself. The field-tested recipe: `v ≥ 90 → warning`, `≥ 75 → caution`,
|
|
45
|
+
`else nominal`.
|
|
46
|
+
- Add `role="meter"` + `aria-valuenow/min/max` + a label; the ring alone is
|
|
47
|
+
invisible to assistive tech.
|
|
48
|
+
- For task progress (this will finish), use a [loader](./loader.md) instead.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Icon loader
|
|
2
|
+
|
|
3
|
+
A nav destination's icon ringed by the spinning [arc](./loader.md#arc) while
|
|
4
|
+
that section loads — the "this section is loading" affordance for a
|
|
5
|
+
[rail](./rail.md), [dock](./dock.md), or [pillbar](./pillbar.md) item. The icon
|
|
6
|
+
stays static on top; the arc sizes in `em` around it and takes no pointer
|
|
7
|
+
events, so the item still clicks through. Zero JS in the CSS — the app toggles
|
|
8
|
+
the arc's `--indeterminate` class to start/stop the spin.
|
|
9
|
+
|
|
10
|
+
## Web
|
|
11
|
+
|
|
12
|
+
```html
|
|
13
|
+
<a class="juno-rail__item" href="/library" aria-current="page">
|
|
14
|
+
<span class="juno-icon-loader">
|
|
15
|
+
<svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
|
|
16
|
+
<span class="juno-arc juno-arc--indeterminate" role="status" aria-label="Loading"></span>
|
|
17
|
+
</span>
|
|
18
|
+
<span class="juno-rail__label">Library</span>
|
|
19
|
+
</a>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
When the section finishes, remove `.juno-arc--indeterminate` (or the whole
|
|
23
|
+
`.juno-arc`). For a progress ring instead of an endless spin, drop
|
|
24
|
+
`--indeterminate` and set `--juno-progress` (0–100) on the `.juno-arc`.
|
|
25
|
+
|
|
26
|
+
| Class / prop | Effect |
|
|
27
|
+
| ------------------------- | -------------------------------------------------------------- |
|
|
28
|
+
| `.juno-icon-loader` | Positioned wrapper; sizes to the icon, centers the ring on it. |
|
|
29
|
+
| `> .juno-icon` | The static glyph, held above the ring. |
|
|
30
|
+
| `> .juno-arc` | The ring — `1.9em`, thin (`0.14em`), pointer-transparent. |
|
|
31
|
+
| `--juno-icon-loader-ring` | Override the ring diameter (default `1.9em`). |
|
|
32
|
+
| `.juno--<role>` | Ring color (default `active`). |
|
|
33
|
+
|
|
34
|
+
## Anatomy (any platform)
|
|
35
|
+
|
|
36
|
+
- A wrapper the size of the icon; the arc is absolutely positioned and centered
|
|
37
|
+
over it, at a larger diameter so it rings the glyph.
|
|
38
|
+
- The ring color is the semantic role; a `.juno--loading`/`.juno--active`
|
|
39
|
+
ancestor tints it.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
- **Concentric via a single-cell grid, never `translate(-50%, -50%)`** — the
|
|
44
|
+
icon and ring share one grid cell (`place-items: center`), so they're centered
|
|
45
|
+
on each other without any `transform`. The arc's rotation animation writes
|
|
46
|
+
`transform`, so a translate-based centering would be clobbered; keep the grid
|
|
47
|
+
approach if you re-roll the markup.
|
|
48
|
+
- Gate the spin to first load, not every background refetch — a nav icon that
|
|
49
|
+
blinks on every poll reads as broken. Add `--indeterminate` when a section
|
|
50
|
+
has no data yet; remove it once loaded.
|
|
51
|
+
- The arc carries the loading semantics (`role="status"` +
|
|
52
|
+
`aria-label="Loading"`); the icon stays `aria-hidden`. Don't also mark the
|
|
53
|
+
nav item busy — one announcement is enough.
|
|
54
|
+
- Respects reduced motion via the arc's own stepped, low-key animation; see
|
|
55
|
+
[loader](./loader.md).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Icon
|
|
2
|
+
|
|
3
|
+
A zero-JS inline-SVG glyph. Icons ship as one **SVG sprite** of `<symbol>`s; you
|
|
4
|
+
reference a symbol with `<use>`. The glyph inherits the current text color and sizes
|
|
5
|
+
in `em`, so it tracks `font-size` and the `[data-juno-text]` scale.
|
|
6
|
+
|
|
7
|
+
Set ships [Phosphor Icons](https://phosphoricons.com) (bold weight) — MIT-licensed,
|
|
8
|
+
free to redistribute and sell. The bundle carries the license in `src/icons/LICENSE`
|
|
9
|
+
and a banner in the generated sprite; keep both when you ship.
|
|
10
|
+
|
|
11
|
+
## Web
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<!-- decorative — hide from assistive tech -->
|
|
15
|
+
<svg class="juno-icon" aria-hidden="true">
|
|
16
|
+
<use href="node_modules/junoui/dist/icons/juno-icons.svg#juno-i-gear" />
|
|
17
|
+
</svg>
|
|
18
|
+
|
|
19
|
+
<!-- meaningful — label it -->
|
|
20
|
+
<svg class="juno-icon juno-icon--lg juno-icon--role juno--warning" role="img" aria-label="Warning">
|
|
21
|
+
<use href="…/juno-icons.svg#juno-i-warning" />
|
|
22
|
+
</svg>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Import path: `@junoput01/junoui/icons` resolves to the sprite.
|
|
26
|
+
|
|
27
|
+
| Class | Effect |
|
|
28
|
+
| ------------------ | ------------------------------------------------------------- |
|
|
29
|
+
| `.juno-icon` | 1.25em square, `fill: currentColor`, baseline-aligned inline. |
|
|
30
|
+
| `.juno-icon--sm` | 1em (matches surrounding text). |
|
|
31
|
+
| `.juno-icon--lg` | 1.75em. |
|
|
32
|
+
| `.juno-icon--xl` | 2.5em. |
|
|
33
|
+
| `.juno-icon--role` | Tint with `var(--juno-role)` instead of inherited text color. |
|
|
34
|
+
| `--juno-icon-size` | Override the size directly (any length). |
|
|
35
|
+
|
|
36
|
+
## Sizing & color
|
|
37
|
+
|
|
38
|
+
- **Color** is `currentColor`: an icon inside colored text matches it. Add
|
|
39
|
+
`.juno-icon--role` + a `.juno--<role>` ancestor (or set `--juno-role`) to tint by
|
|
40
|
+
status. Always pair a status color with a text label — color is never the only signal.
|
|
41
|
+
- **Size** is `em`-relative, so icons grow with the type scale and stay proportional
|
|
42
|
+
inside buttons / inputs. For a fixed pixel size set `--juno-icon-size: 20px`.
|
|
43
|
+
|
|
44
|
+
## Adding / changing icons
|
|
45
|
+
|
|
46
|
+
Drop an SVG into `src/icons/` (must use `currentColor`, a `viewBox`), then
|
|
47
|
+
`npm run build:icons` (part of `npm run build`). The file name becomes the symbol id
|
|
48
|
+
`juno-i-<name>`. Swapping icon sets is a source change in `src/icons/` — keep the new
|
|
49
|
+
set's license file alongside.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Input / textarea
|
|
2
|
+
|
|
3
|
+
Text entry — inputs are precise. **Mono by default** (codes, IDs, tokens, values);
|
|
4
|
+
add `.juno-input--sans` for free text. One class for `<input>` and `<textarea>`.
|
|
5
|
+
|
|
6
|
+
## Web
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<input class="juno-input" type="text" value="UAL 519" />
|
|
10
|
+
<!-- mono code -->
|
|
11
|
+
<input class="juno-input juno-input--sans" placeholder="Type to edit…" />
|
|
12
|
+
<!-- free text -->
|
|
13
|
+
<input class="juno-input juno--target" value="38000" />
|
|
14
|
+
<!-- managed -->
|
|
15
|
+
<input class="juno-input" aria-invalid="true" value="7700" />
|
|
16
|
+
<!-- error -->
|
|
17
|
+
<input class="juno-input" disabled value="LOCKED" />
|
|
18
|
+
<textarea class="juno-input juno-input--sans" rows="4"></textarea>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Class / attr | Effect |
|
|
22
|
+
| ------------------- | ------------------------------------------------------------------------------------ |
|
|
23
|
+
| `.juno-input` | Box: `control-surface` bg, `control-edge` border, radius `4`, density padding. Mono. |
|
|
24
|
+
| `.juno-input--sans` | Sans font for free-text fields. |
|
|
25
|
+
| `.juno--<role>` | Re-colors the border (e.g. `target` for managed values). |
|
|
26
|
+
| `[aria-invalid]` | `warning` border + text, tied to the a11y attribute. |
|
|
27
|
+
| `:disabled` | `s1` bg, `muted` text, not-allowed. |
|
|
28
|
+
|
|
29
|
+
`--juno-role` defaults to `control-edge`, so the resting border is quiet; a role class
|
|
30
|
+
or `aria-invalid` overrides it. **Focus** = `active` border + a 1px ring (replaces the
|
|
31
|
+
base outline on inputs).
|
|
32
|
+
|
|
33
|
+
## Anatomy (any platform)
|
|
34
|
+
|
|
35
|
+
- **Control surface:** on dark panels the hairline border vanishes, so the edge lifts
|
|
36
|
+
to `muted` on an `s2` field; light mode keeps the true `border` on `s0`
|
|
37
|
+
(`--juno-control-surface` / `--juno-control-edge`).
|
|
38
|
+
- Padding `--juno-pad-control-block` × `space.12` (density-aware). Radius `4`. Min
|
|
39
|
+
height `size.tap.min`. Font `font.size.14`, `data`; placeholder `muted`.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
- Mono is the default because most technical entry is codes/values; opt into `--sans`
|
|
44
|
+
for names and remarks. Textarea is usually `--sans`.
|
|
45
|
+
- Wrap in [`.juno-field`](./field.md) for label + help/error.
|