@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.
Files changed (61) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/css/juno.css +162 -3
  3. package/docs/accessibility.md +167 -0
  4. package/docs/components/README.md +68 -0
  5. package/docs/components/accordion.md +49 -0
  6. package/docs/components/alert.md +46 -0
  7. package/docs/components/avatar.md +45 -0
  8. package/docs/components/badge.md +35 -0
  9. package/docs/components/breadcrumb.md +31 -0
  10. package/docs/components/button.md +32 -0
  11. package/docs/components/card.md +41 -0
  12. package/docs/components/checkbox.md +41 -0
  13. package/docs/components/chip.md +44 -0
  14. package/docs/components/divider.md +32 -0
  15. package/docs/components/dock.md +56 -0
  16. package/docs/components/drawer.md +60 -0
  17. package/docs/components/field.md +44 -0
  18. package/docs/components/gauge.md +48 -0
  19. package/docs/components/icon-loader.md +55 -0
  20. package/docs/components/icon.md +49 -0
  21. package/docs/components/input.md +45 -0
  22. package/docs/components/list.md +76 -0
  23. package/docs/components/loader.md +80 -0
  24. package/docs/components/menu.md +54 -0
  25. package/docs/components/modal.md +52 -0
  26. package/docs/components/navbar.md +53 -0
  27. package/docs/components/pagination.md +42 -0
  28. package/docs/components/pillbar.md +64 -0
  29. package/docs/components/popover.md +43 -0
  30. package/docs/components/rail.md +54 -0
  31. package/docs/components/readout.md +39 -0
  32. package/docs/components/segmented.md +46 -0
  33. package/docs/components/select.md +33 -0
  34. package/docs/components/skeleton.md +38 -0
  35. package/docs/components/slider.md +48 -0
  36. package/docs/components/spark.md +51 -0
  37. package/docs/components/status.md +30 -0
  38. package/docs/components/stepper.md +46 -0
  39. package/docs/components/switch.md +38 -0
  40. package/docs/components/table.md +126 -0
  41. package/docs/components/tabs.md +61 -0
  42. package/docs/components/thumb.md +61 -0
  43. package/docs/components/toast.md +48 -0
  44. package/docs/components/toggle-button.md +40 -0
  45. package/docs/components/tooltip.md +63 -0
  46. package/docs/design-guidelines.md +147 -0
  47. package/docs/flutter.md +42 -0
  48. package/docs/getting-started.md +70 -0
  49. package/docs/integration.md +95 -0
  50. package/docs/layout.md +201 -0
  51. package/docs/native.md +52 -0
  52. package/docs/roadmap.md +106 -0
  53. package/docs/tokens-reference.md +223 -0
  54. package/docs/web.md +89 -0
  55. package/package.json +3 -2
  56. package/src/css/base.css +7 -0
  57. package/src/css/components/dock.css +13 -0
  58. package/src/css/components/icon-loader.css +53 -0
  59. package/src/css/components/pillbar.css +15 -0
  60. package/src/css/components/rail.css +8 -0
  61. 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.