@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,76 @@
1
+ # List
2
+
3
+ Grouped rows for vertical data organization — the settings-screen pattern.
4
+ Labeled groups of full-width rows; each row carries a leading icon, a label
5
+ (with optional support line), and a trailing value, control, or drill-in
6
+ chevron. The phone-first sibling of the [table](./table.md): use a list when
7
+ each record is a _destination or setting_, a table when you compare columns.
8
+
9
+ ## Web
10
+
11
+ ```html
12
+ <section class="juno-list">
13
+ <h3 class="juno-list__header">Playback</h3>
14
+ <ul class="juno-list__group">
15
+ <li>
16
+ <a class="juno-list__row" href="/settings/quality">
17
+ <svg class="juno-icon juno-list__icon" aria-hidden="true">
18
+ <use href="…#juno-i-sliders" />
19
+ </svg>
20
+ <span class="juno-list__main">
21
+ <span class="juno-list__label">Quality</span>
22
+ <span class="juno-list__support">Streaming resolution</span>
23
+ </span>
24
+ <span class="juno-list__value">1080p</span>
25
+ <svg class="juno-icon juno-list__chevron" aria-hidden="true">
26
+ <use href="…#juno-i-caret-right" />
27
+ </svg>
28
+ </a>
29
+ </li>
30
+ <li>
31
+ <div class="juno-list__row">
32
+ <span class="juno-list__main"><span class="juno-list__label">Autoplay</span></span>
33
+ <label class="juno-switch juno-switch--sm"
34
+ ><input class="juno-switch__input" type="checkbox" role="switch" checked /><span
35
+ class="juno-switch__track"
36
+ ></span
37
+ ></label>
38
+ </div>
39
+ </li>
40
+ </ul>
41
+ </section>
42
+ ```
43
+
44
+ | Class | Effect |
45
+ | --------------------- | ------------------------------------------------------------------- |
46
+ | `.juno-list` | Stack of header + group(s). |
47
+ | `.juno-list__header` | Uppercase group label above the group. |
48
+ | `.juno-list__group` | `s1` card frame; rows divided by hairlines, corners rounded. |
49
+ | `.juno-list__row` | Row ≥ `size.tap.comfortable`; `<a>`/`<button>` rows get hover. |
50
+ | `.juno-list__icon` | Leading glyph, label-toned. |
51
+ | `.juno-list__main` | Label + optional support line; truncates, takes the flexible space. |
52
+ | `.juno-list__label` | Primary text. |
53
+ | `.juno-list__support` | Secondary line under the label. |
54
+ | `.juno-list__value` | Trailing mono value. |
55
+ | `.juno-list__chevron` | Drill-in caret (`caret-right`), muted. |
56
+
57
+ ## Anatomy (any platform)
58
+
59
+ - Group = `s1` surface, hairline `border`, `radius.8`; rows split by hairlines
60
+ drawn between rows only (no doubled edges).
61
+ - Row ≥ `size.tap.comfortable` tall, `space.16` inline padding, `space.12`
62
+ gap between slots. Label `font.size.13` data-toned; support `font.size.11`
63
+ label-toned; value mono `font.size.12`.
64
+ - Only interactive rows respond: hover/press fills `s2`.
65
+
66
+ ## Usage
67
+
68
+ - Trailing slot takes whatever fits the row's job: a mono value, a
69
+ [badge](./badge.md), a [switch](./switch.md), or the chevron when the row
70
+ drills into a detail view (pair the pushed view with a
71
+ [navbar](./navbar.md) back control).
72
+ - A chevron row must be an `<a>` (or `<button>`) — the whole row is the tap
73
+ target, never just the caret.
74
+ - Static key→value screens can skip `<ul>`/`<li>` and stack `div.juno-list__row`
75
+ directly inside `.juno-list__group`; keep list semantics when rows navigate.
76
+ - Don't put two controls in one row — a row is one target. Split it.
@@ -0,0 +1,80 @@
1
+ # Loaders (arc · beacon · linear)
2
+
3
+ Three progress indicators, each in an **indeterminate** form (loops on its own,
4
+ CSS only) and a **determinate** form (tracks real progress).
5
+
6
+ ## Progress API
7
+
8
+ Determinate variants read `--juno-progress` (0–100). Set it inline or from JS:
9
+
10
+ ```js
11
+ el.style.setProperty('--juno-progress', 63);
12
+ ```
13
+
14
+ Color comes from `--juno-role` (default `active`); add a `.juno--<role>` class to recolor.
15
+
16
+ ## Arc — circular ring
17
+
18
+ ```html
19
+ <!-- indeterminate -->
20
+ <div class="juno-arc juno-arc--indeterminate"></div>
21
+
22
+ <!-- determinate (label as a sibling so the ring mask doesn't clip it) -->
23
+ <div style="position:relative;width:76px;height:76px;">
24
+ <div class="juno-arc" style="--juno-progress:63;"></div>
25
+ <span class="juno-arc__label">63%</span>
26
+ </div>
27
+ ```
28
+
29
+ | Class / var | Effect |
30
+ | --------------------------------------------------- | ---------------------------------------------------------------- |
31
+ | `.juno-arc` | Ring; determinate sweep = progress (conic gradient + ring mask). |
32
+ | `.juno-arc--indeterminate` | 12-step mechanical rotation. |
33
+ | `--juno-arc-size` (76px) · `--juno-arc-width` (4px) | Diameter / stroke. |
34
+
35
+ > The ring uses a CSS mask, which clips children. Put `.juno-arc__label` as a
36
+ > **sibling** over a positioned wrapper, not inside `.juno-arc`.
37
+
38
+ ## Beacon — radiating pulse
39
+
40
+ ```html
41
+ <!-- indeterminate -->
42
+ <div class="juno-beacon"><span class="juno-beacon__core"></span></div>
43
+
44
+ <!-- determinate: fill grows centre → rim -->
45
+ <div class="juno-beacon juno-beacon--determinate" style="--juno-progress:63;">
46
+ <span class="juno-beacon__track"></span>
47
+ <span class="juno-beacon__fill"></span>
48
+ <span class="juno-beacon__hub"></span>
49
+ <span class="juno-beacon__label">63%</span>
50
+ </div>
51
+ ```
52
+
53
+ | Part | Role |
54
+ | ------------------------------------------ | ----------------------------------------------- |
55
+ | `.juno-beacon` | Container; emits two staggered pulse rings. |
56
+ | `.juno-beacon__core` | Centre dot (indeterminate). |
57
+ | `.juno-beacon--determinate` | Switches to a centre→rim fill mask by progress. |
58
+ | `__track` / `__fill` / `__hub` / `__label` | Ring track, growing fill, centre hub, readout. |
59
+
60
+ ## Linear — bar
61
+
62
+ ```html
63
+ <!-- indeterminate -->
64
+ <div class="juno-bar juno-bar--indeterminate"><span class="juno-bar__fill"></span></div>
65
+
66
+ <!-- determinate -->
67
+ <div class="juno-bar" style="--juno-progress:63;"><span class="juno-bar__fill"></span></div>
68
+ ```
69
+
70
+ | Class | Effect |
71
+ | -------------------------- | ------------------------------------- |
72
+ | `.juno-bar` | Track (`s2`, 6px, radius `radius.3`). |
73
+ | `.juno-bar__fill` | Fill; width = progress, color = role. |
74
+ | `.juno-bar--indeterminate` | A 40% segment slides across. |
75
+
76
+ ## Notes
77
+
78
+ - Indeterminate forms need no JS. All animations respect `prefers-reduced-motion`
79
+ (slowed to near-static by the base layer).
80
+ - Use determinate whenever real progress is known — it reads as more trustworthy.
@@ -0,0 +1,54 @@
1
+ # Menu / Dropdown
2
+
3
+ A list of immediate actions anchored to its trigger — with section dividers, keyboard
4
+ shortcuts, and a destructive item set apart by `warning`. Built on the **native Popover
5
+ API** (top layer — never clipped, never z-index-trapped): open/close, light-dismiss, and
6
+ ESC are free. junoui ships the look; **the app owns** roving focus (arrow keys).
7
+
8
+ ## Web
9
+
10
+ ```html
11
+ <button popovertarget="acts" aria-haspopup="menu">ACTIONS ▾</button>
12
+ <ul class="juno-menu" id="acts" popover role="menu">
13
+ <li>
14
+ <button class="juno-menu__item" role="menuitem" popovertarget="acts" popovertargetaction="hide">
15
+ <span class="juno-menu__icon">⤓</span>Import data
16
+ <span class="juno-menu__kbd">⌘O</span>
17
+ </button>
18
+ </li>
19
+ <li class="juno-menu__sep" role="separator"></li>
20
+ <li>
21
+ <button
22
+ class="juno-menu__item juno--warning"
23
+ role="menuitem"
24
+ popovertarget="acts"
25
+ popovertargetaction="hide"
26
+ >
27
+ <span class="juno-menu__icon">⨯</span>Delete project
28
+ </button>
29
+ </li>
30
+ </ul>
31
+ ```
32
+
33
+ | Class | Effect |
34
+ | -------------------------------- | ------------------------------------------------------------ |
35
+ | `.juno-menu` | 256px `s2` panel, radius `5`, shadow `2`. Top-layer, pinned. |
36
+ | `.juno-menu__item` | Action row; hover/focus → `s3`. Icon + label + shortcut. |
37
+ | `.juno-menu__item.juno--warning` | Destructive item; text + icon `warning`, hover tinted. |
38
+ | `.juno-menu__icon` / `__kbd` | Leading glyph (`label`) / trailing shortcut (`muted`). |
39
+ | `.juno-menu__sep` | Section divider. |
40
+
41
+ ## Anatomy (any platform)
42
+
43
+ - Top-layer surface `s2` + `shadow.2`, pinned below the invoker with a `space.8` gap;
44
+ flips to stay on-screen. Rise + fade, `motion.duration.quick` (140ms) / `ease.decel`,
45
+ animated with `@starting-style` + `allow-discrete`.
46
+
47
+ ## Usage
48
+
49
+ - Real `<button>` items inside `role="menu"` / `role="menuitem"`. Each item carries
50
+ `popovertarget="<id>" popovertargetaction="hide"` so activating it closes the menu with
51
+ no JS; the app still wires arrow-key roving focus + Enter.
52
+ - `popovertarget` on the trigger handles open / ESC / outside-click and exposes
53
+ `aria-expanded` implicitly. Keep `aria-haspopup="menu"` for intent.
54
+ - One destructive item max, separated by a divider and marked `.juno--warning`.
@@ -0,0 +1,52 @@
1
+ # Modal / Dialog
2
+
3
+ A centered, scrim-backed `<dialog>` for decisions that must block the deck. junoui
4
+ ships the look + entry motion; **the app owns** `showModal()`/`close()`, focus-trapping,
5
+ and ESC/scrim-click dismiss (native `<dialog>` gives you most of this free).
6
+
7
+ ## Web
8
+
9
+ ```html
10
+ <dialog class="juno-modal">
11
+ <div class="juno-modal__stripe"></div>
12
+ <div class="juno-modal__head">
13
+ <span class="juno-modal__tag">DEPLOYMENT</span>
14
+ <button class="juno-modal__close" aria-label="Close">✕</button>
15
+ </div>
16
+ <div class="juno-modal__body">
17
+ <h2 class="juno-modal__title">Promote build to production?</h2>
18
+ <p class="juno-modal__text">This routes production traffic to the new version…</p>
19
+ <div class="juno-modal__foot">
20
+ <button class="juno-btn juno-btn--ghost">CANCEL</button>
21
+ <button class="juno-btn">PROMOTE BUILD</button>
22
+ </div>
23
+ </div>
24
+ </dialog>
25
+
26
+ <!-- destructive -->
27
+ <dialog class="juno-modal juno--warning">…</dialog>
28
+ ```
29
+
30
+ | Class | Effect |
31
+ | ------------------------------------------ | ------------------------------------------------------------------- |
32
+ | `.juno-modal` | 440px panel, `s1`, radius `8`, shadow `3` (e3), `z.overlay` (4000). |
33
+ | `.juno-modal__stripe` | Top accent bar in `--juno-role`. |
34
+ | `.juno-modal__head` / `__tag` / `__close` | Tag row + close button (`size.tap.min`). |
35
+ | `.juno-modal__title` / `__text` / `__foot` | Title (20px light), body, right-aligned actions. |
36
+ | `.juno--warning` | Destructive: stripe + tag turn `warning`. |
37
+ | `::backdrop` | Dark scrim at `opacity.scrim` + 1.5px blur. |
38
+
39
+ ## Anatomy (any platform)
40
+
41
+ - Enter: scrim fades, panel scales 0.97→1 + rises, `motion.duration.deliberate`
42
+ (300ms) / `ease.decel`. Exit accelerates. `prefers-reduced-motion` collapses it.
43
+ - Elevation = `z.overlay` + `shadow.3`, paired. One scrim at a time — never stack modals.
44
+
45
+ ## Usage
46
+
47
+ - Use a real `<dialog>` + `showModal()` so focus-trap, ESC, and inert background come free.
48
+ - Destructive actions: `.juno--warning` + a deliberate confirm (`.juno-btn juno--warning`).
49
+ - For edge-anchored panels that don't block, use the [drawer](./drawer.md).
50
+ - **Phone widths (< `bp.sm`) are automatic:** the centered dialog becomes a
51
+ bottom sheet — full-width, top corners rounded, sliding up, footer buttons
52
+ stretched, content padded past the home indicator. No extra class.
@@ -0,0 +1,53 @@
1
+ # Navbar
2
+
3
+ The top bar of a pushed view on phones: a back control on the start edge —
4
+ **always present**, so any screen can unwind — a centered truncating title,
5
+ and trailing actions. junoui ships the look; the app owns the navigation
6
+ stack (what "back" does and where it goes).
7
+
8
+ ## Web
9
+
10
+ ```html
11
+ <header class="juno-navbar">
12
+ <a class="juno-navbar__back" href="/library">
13
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-caret-left" /></svg>
14
+ <span class="juno-navbar__back-label">Library</span>
15
+ </a>
16
+ <h1 class="juno-navbar__title">Album</h1>
17
+ <div class="juno-navbar__actions">
18
+ <button class="juno-btn juno-btn--sm juno-btn--ghost">EDIT</button>
19
+ </div>
20
+ </header>
21
+ ```
22
+
23
+ | Class | Effect |
24
+ | -------------------------- | ------------------------------------------------------------------ |
25
+ | `.juno-navbar` | Sticky top `s1` bar, hairline seam below, safe-area padded on top. |
26
+ | `.juno-navbar__back` | Start-edge back control, active-toned; ≥ `size.tap.comfortable`. |
27
+ | `.juno-navbar__back-label` | Parent-view name next to the caret — truncates at 14ch. |
28
+ | `.juno-navbar__title` | Centered `font.size.14` title; truncates, never wraps. |
29
+ | `.juno-navbar__actions` | Trailing cluster for small buttons / icons. |
30
+
31
+ ## Anatomy (any platform)
32
+
33
+ - Three-column grid: equal flexible sides keep the title optically centered;
34
+ when space runs out the title truncates first, never sliding under the back
35
+ control (back/actions keep their own truncated width).
36
+ - Back = `caret.left` + the **parent view's name** in the active color; the
37
+ caret flips under RTL. Title `font.size.14` semibold, data-toned.
38
+ - Bar ≥ `size.tap.comfortable` tall; top padding extends into
39
+ `env(safe-area-inset-top)` so the notch never covers it.
40
+
41
+ ## Usage
42
+
43
+ - **Tab + stack recipe:** the [dock](./dock.md)/[pillbar](./pillbar.md)
44
+ switches sections; inside a section, drilling into a
45
+ [list](./list.md) row pushes a view whose navbar backs out one level.
46
+ Full shell recipe: [layout.md](../layout.md#app-shell).
47
+ - The back control is a real `<a>` to the parent route (deep-linkable), or a
48
+ `<button>` when the app drives history. Label it with the parent view's
49
+ name; keep `aria-label="Back"` when only the caret fits.
50
+ - Root views (tab landing screens) have no parent — there, swap the back slot
51
+ for a brand/title block or leave it empty; every _pushed_ view keeps it.
52
+ - One `<h1>` per document — pushed views' navbar titles are usually the
53
+ screen's `<h1>`.
@@ -0,0 +1,42 @@
1
+ # Pagination
2
+
3
+ A row of page controls — prev / next plus numbered pages, with the current page marked
4
+ `aria-current="page"`. Built on a real `<nav>`; the app owns which page is active and
5
+ renders the list. Zero JS.
6
+
7
+ ## Web
8
+
9
+ ```html
10
+ <nav class="juno-pagination" aria-label="Pagination">
11
+ <button class="juno-pagination__item" aria-label="Previous page" disabled>
12
+ <svg class="juno-icon juno-icon--sm" aria-hidden="true"><use href="…#juno-i-caret-left" /></svg>
13
+ </button>
14
+ <button class="juno-pagination__item" aria-current="page">1</button>
15
+ <button class="juno-pagination__item">2</button>
16
+ <button class="juno-pagination__item">3</button>
17
+ <span class="juno-pagination__gap">…</span>
18
+ <button class="juno-pagination__item">9</button>
19
+ <button class="juno-pagination__item" aria-label="Next page">
20
+ <svg class="juno-icon juno-icon--sm" aria-hidden="true">
21
+ <use href="…#juno-i-caret-right" />
22
+ </svg>
23
+ </button>
24
+ </nav>
25
+ ```
26
+
27
+ | Part / attr | Effect |
28
+ | ------------------------ | ------------------------------------------------------ |
29
+ | `.juno-pagination` | `<nav>` flex row; wraps on narrow widths. |
30
+ | `.juno-pagination__item` | Page / prev / next button (44px tap target, mono). |
31
+ | `[aria-current="page"]` | Current page — filled `active` accent, non-actionable. |
32
+ | `:disabled` | Dim prev / next at the ends. |
33
+ | `.juno-pagination__gap` | The `…` between page ranges (not a button). |
34
+
35
+ ## Usage
36
+
37
+ - `aria-label="Pagination"` on the `<nav>`; `aria-current="page"` on the active page;
38
+ `aria-label` on the icon-only prev / next ("Previous page").
39
+ - The app computes the window of page numbers + where `…` falls, and disables prev / next
40
+ at the ends.
41
+ - For a simple "‹ Prev / Next ›" pair (as in the [table](./table.md) footer), use two
42
+ `__item` buttons without the numbered list.
@@ -0,0 +1,64 @@
1
+ # Pillbar
2
+
3
+ A floating pill-shaped bar hovering above the content's bottom edge — the
4
+ iOS-style alternative to the full-width [dock](./dock.md). Holds 2–5 icon
5
+ actions or destinations; mix nav links and toggle buttons, separated by an
6
+ optional divider. Zero JS.
7
+
8
+ ## Web
9
+
10
+ ```html
11
+ <nav class="juno-pillbar" aria-label="Primary">
12
+ <a class="juno-pillbar__item" href="/library" aria-current="page" aria-label="Library">
13
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
14
+ <span class="juno-pillbar__label">Library</span>
15
+ </a>
16
+ <a class="juno-pillbar__item" href="/albums" aria-label="Albums">
17
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-images" /></svg>
18
+ </a>
19
+ <span class="juno-pillbar__sep"></span>
20
+ <button class="juno-pillbar__item" aria-label="Sync">
21
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-arrows-clockwise" /></svg>
22
+ </button>
23
+ </nav>
24
+ ```
25
+
26
+ | Class / prop | Effect |
27
+ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
28
+ | `.juno-pillbar` | Sticky floating pill: blurred translucent `s1`, hairline, `shadow.2`. |
29
+ | `.juno-pillbar__item` | Round tap target ≥ `size.tap.comfortable`; icon with optional label. |
30
+ | `.juno-pillbar__label` | Inline text next to the icon — truncates at 12ch. |
31
+ | `.juno-pillbar__sep` | Vertical hairline between item groups (e.g. destinations vs. actions). |
32
+ | `[aria-current]` | Active destination: `s3` pill fill + role color. Attribute, not class. |
33
+ | `[aria-pressed]` | Same active look for toggle buttons. |
34
+ | `.juno-pillbar--fixed` | Fix to the viewport (`position: fixed`), floating its usual `space.16` + safe-area above the foot — for page-scroll shells where sticky won't pin. |
35
+ | `.juno--<role>` | Active color (default `active`). |
36
+
37
+ ## Anatomy (any platform)
38
+
39
+ - Fully-rounded capsule floating `space.16` off the bottom edge (plus the safe
40
+ area), centered inline; translucent `s1` with a background blur, hairline
41
+ `border`, `shadow.2` lift.
42
+ - Items are capsule targets at least `size.tap.comfortable` square; the active
43
+ one fills `s3` and takes the role color.
44
+ - A separator is a `border`-colored vertical hairline, `space.20` tall.
45
+
46
+ ## Usage
47
+
48
+ - Same rules as the dock: 3–5 destinations, overflow goes behind a "More" item.
49
+ Pick **one** bottom pattern per screen — dock _or_ pillbar, never both.
50
+ - Sticky, not fixed: place it last inside the scrolling column; it floats over
51
+ content while staying in flow. Best inside the
52
+ [`.juno-app-shell`](../layout.md#app-shell) frame, whose `__main` is the
53
+ scroller.
54
+ - **Short-page caveat:** sticky only pins while the column overflows, so on a
55
+ short page that doesn't scroll the pillbar lands mid-content. If the _whole
56
+ page_ scrolls, use `.juno-pillbar--fixed` to fix it to the viewport (it keeps
57
+ floating its usual gap above the foot) and reserve its footprint at the page
58
+ foot.
59
+ - Icon-only items need `aria-label`. Show the label on the active item (or all
60
+ items) when space allows.
61
+ - Nav destinations are `<a>` with `aria-current="page"`; momentary or toggle
62
+ actions are `<button>` (toggles flip `aria-pressed`).
63
+ - Works inside a [navbar](./navbar.md) + tab-stack shell — the recipe is in
64
+ [layout.md](../layout.md#app-shell).
@@ -0,0 +1,43 @@
1
+ # Popover
2
+
3
+ An anchored, click-triggered surface for rich, interactive content — filters,
4
+ quick-edits, detail cards. Unlike a [tooltip](./tooltip.md) it holds focusable controls
5
+ and persists until dismissed.
6
+
7
+ Built on the **native Popover API**: the panel lives in the browser **top layer**, so
8
+ it is _never_ clipped by an ancestor's `overflow`/`transform` and never fights
9
+ `z-index`. A `popovertarget` button is its **implicit anchor**; CSS anchor positioning
10
+ pins the panel below, inline-end aligned. Open/close, light-dismiss (outside click),
11
+ and ESC are all the platform's job — **zero JS**.
12
+
13
+ ## Web
14
+
15
+ ```html
16
+ <button popovertarget="pf" aria-haspopup="dialog">RANGE FILTER ▾</button>
17
+ <div class="juno-popover" id="pf" popover role="dialog" aria-label="Range filter">
18
+ <!-- any controls -->
19
+ <span class="juno-popover__arrow"></span>
20
+ </div>
21
+ ```
22
+
23
+ | Class | Effect |
24
+ | ---------------------- | ------------------------------------------------------------------- |
25
+ | `.juno-popover` | 280px `s2` panel, radius `5`, shadow `2`. Top-layer, anchor-pinned. |
26
+ | `.juno-popover__arrow` | Pointer back to the anchor (top-end corner). |
27
+ | `.juno-popover-anchor` | Optional inline wrapper to group trigger + panel (layout only). |
28
+
29
+ ## Anatomy (any platform)
30
+
31
+ - Top-layer surface `s2` + `shadow.2`, surface-padding. Pinned below the invoker
32
+ (`position-area: block-end span-inline-start`) with a `space.12` gap; flips to stay
33
+ on-screen via `position-try-fallbacks`.
34
+ - Enter: rise + fade, `motion.duration.quick` / `ease.decel`, animated open↔closed with
35
+ `@starting-style` + `transition-behavior: allow-discrete`.
36
+
37
+ ## Usage
38
+
39
+ - Reach for a popover when the content is interactive; a tooltip when it's just text.
40
+ - `popovertarget` makes the `<button>` toggle the panel and exposes `aria-expanded` /
41
+ `aria-details` implicitly — no script needed. Keep `aria-haspopup` for intent.
42
+ - Default anchoring is block-end / inline-end. Override with `position-area` (or set
43
+ `inset` on the panel's `toggle` event) for other placements or older engines.
@@ -0,0 +1,54 @@
1
+ # Rail
2
+
3
+ The side navigation column of the standard app shell — brand block on top, then
4
+ icon + label items. Collapsible to icons-only. The full shell composition
5
+ (rail + topbar + content + slide-over) is in [layout.md](../layout.md#app-shell).
6
+ On phone widths the shell swaps the rail for a [dock](./dock.md) (bottom nav).
7
+
8
+ ## Web
9
+
10
+ ```html
11
+ <nav class="juno-rail" aria-label="Primary">
12
+ <div class="juno-rail__brand">JUNO</div>
13
+ <a class="juno-rail__item" href="/library" aria-current="page">
14
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
15
+ <span class="juno-rail__label">Library</span>
16
+ </a>
17
+ <a class="juno-rail__item" href="/nodes">
18
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-hexagon" /></svg>
19
+ <span class="juno-rail__label">Nodes</span>
20
+ </a>
21
+ </nav>
22
+ ```
23
+
24
+ | Class / prop | Effect |
25
+ | ------------------------ | ------------------------------------------------------------------------------------------------ |
26
+ | `.juno-rail` | `s1` column, 180px, 1px `border` seam on the inline-end edge. |
27
+ | `.juno-rail__brand` | Mono uppercase brand block. |
28
+ | `.juno-rail__item` | Icon + label row; hover `s2`. |
29
+ | `.juno-rail__label` | The text — hidden when collapsed. |
30
+ | `[aria-current]` | Active item: `s3` fill + 2px role edge. Attribute, not a class. |
31
+ | `.juno-rail--collapsed` | Icons-only, `space.56` wide; width transition. |
32
+ | `.juno-rail--responsive` | Self-hides below `md`; pair with a `.juno-dock` / `.juno-pillbar` carrying `.juno-hide-from-md`. |
33
+ | `--juno-rail-width` | Override the expanded width. |
34
+ | `.juno--<role>` | Active-edge color (default `active`). |
35
+
36
+ ## Anatomy (any platform)
37
+
38
+ - Column on `s1`, hairline seam, items `space.8` × `space.16`, `font.size.12`
39
+ uppercase `label` → `data` on hover/active.
40
+ - Active = `s3` fill + `border.width.2` inline-start edge in the role color.
41
+ - Edges are logical: the rail mirrors under RTL.
42
+
43
+ ## Usage
44
+
45
+ - The app owns the collapse state (a class toggle) and sets `aria-current="page"`
46
+ on the active item — junoui styles the attribute so nav semantics stay honest.
47
+ - When collapsed, labels leave the accessibility tree: give each item an
48
+ `aria-label` (or `title`) so icons-only mode stays navigable.
49
+ - Pair with [tooltip](./tooltip.md) for collapsed-item labels.
50
+ - Adaptive shell: add `.juno-rail--responsive` so the rail self-hides below
51
+ `md` and a paired [dock](./dock.md)/[pillbar](./pillbar.md) takes over — no
52
+ need to hang `.juno-hide-below-md` on the rail yourself.
53
+ - Show a section is loading by wrapping an item's icon in an
54
+ [icon-loader](./icon-loader.md) ring.
@@ -0,0 +1,39 @@
1
+ # Data readout
2
+
3
+ A tile showing one live value: small label, large mono value, unit.
4
+
5
+ ## Web
6
+
7
+ ```html
8
+ <div class="juno-readout juno--nominal">
9
+ <span class="juno-readout__label">N1</span>
10
+ <span class="juno-readout__value">89.3</span>
11
+ <span class="juno-readout__unit">%</span>
12
+ </div>
13
+
14
+ <div class="juno-readout juno-readout--alert juno--warning">
15
+ <span class="juno-readout__label">OIL PSI</span>
16
+ <span class="juno-readout__value">12</span>
17
+ <span class="juno-readout__unit juno-text-warning">↓ LOW</span>
18
+ </div>
19
+ ```
20
+
21
+ | Class | Effect |
22
+ | -------------------------------- | ---------------------------------------------------------- |
23
+ | `.juno-readout` | `s2` tile, radius `radius.5`. Value default role = `data`. |
24
+ | `.juno--<role>` | Colors the value (status). |
25
+ | `.juno-readout--alert` | Adds a 1px role border for critical tiles. |
26
+ | `__label` / `__value` / `__unit` | Parts. |
27
+
28
+ ## Anatomy (any platform)
29
+
30
+ - Tile `s2`, padding `space.20`/`space.16`, radius `radius.5`.
31
+ - Label: `font.size.10`, uppercase, tracking `wider`, color `label`.
32
+ - Value: **B612 Mono 700**, `font.size.38`, `tabular-nums`, color = role (default `data`).
33
+ - Unit: `font.size.11`, color `label`.
34
+
35
+ ## Usage
36
+
37
+ - Value stays `data` (neutral) when nominal; switch to a status role only when the
38
+ reading itself is non-normal.
39
+ - Always B612 Mono with tabular figures so digits don't shift as values update.
@@ -0,0 +1,46 @@
1
+ # Segmented control
2
+
3
+ An exclusive-choice pill row — filters (`ALL / PHOTOS / VIDEO`), mode switchers,
4
+ sort pickers. Native radios carry the state; zero JS.
5
+
6
+ ## Web
7
+
8
+ ```html
9
+ <fieldset class="juno-seg juno--active">
10
+ <label class="juno-seg__opt"><input type="radio" name="kind" checked /><span>ALL</span></label>
11
+ <label class="juno-seg__opt"><input type="radio" name="kind" /><span>PHOTOS</span></label>
12
+ <label class="juno-seg__opt"><input type="radio" name="kind" /><span>VIDEO</span></label>
13
+ </fieldset>
14
+ ```
15
+
16
+ JS-driven apps may use buttons instead — the app flips `aria-pressed`:
17
+
18
+ ```html
19
+ <div class="juno-seg" role="group" aria-label="Kind">
20
+ <button class="juno-seg__opt" aria-pressed="true">ALL</button>
21
+ <button class="juno-seg__opt" aria-pressed="false">PHOTOS</button>
22
+ </div>
23
+ ```
24
+
25
+ | Class | Effect |
26
+ | ---------------- | ----------------------------------------------------------------------- |
27
+ | `.juno-seg` | The row (a `<fieldset>` or `role="group"`); wraps, `space.4` gap. |
28
+ | `.juno-seg__opt` | One pill: label + hidden radio + `<span>`, or an `aria-pressed` button. |
29
+ | `.juno-seg--sm` | Dense-toolbar size (`font.size.10`), matches `.juno-btn--sm`. |
30
+ | `.juno--<role>` | Color of the checked pill (default `data`-neutral). |
31
+
32
+ ## Anatomy (any platform)
33
+
34
+ - Pill: B612, 700 weight, `font.size.11`, uppercase, tracking `font.tracking.label`,
35
+ `space.4` × `space.10` padding, `radius.3`, 1px `border` outline.
36
+ - Checked: background `s3`, border + text take the role color.
37
+ - Hover (unchecked): background `s2`. Focus ring on the pill via `:focus-visible`.
38
+
39
+ ## Usage
40
+
41
+ - Exclusive choice among 2–5 short options that should all stay visible; more than
42
+ that, use a [select](./select.md).
43
+ - The radio flavor is a working form control with arrow-key group navigation for
44
+ free — prefer it; reach for `aria-pressed` buttons only when state lives in JS.
45
+ - Wrap the radio flavor in a `<fieldset>` with a `<legend>` (may be visually hidden)
46
+ so the group is announced.
@@ -0,0 +1,33 @@
1
+ # Select
2
+
3
+ A native `<select>` styled as an input, with a token-colored chevron.
4
+
5
+ ## Web
6
+
7
+ ```html
8
+ <div class="juno-select">
9
+ <select class="juno-input">
10
+ <option>NOMINAL</option>
11
+ <option>CAUTION</option>
12
+ <option>WARNING</option>
13
+ </select>
14
+ </div>
15
+ ```
16
+
17
+ | Class | Effect |
18
+ | ---------------------------- | --------------------------------------------------------------------------------------------- |
19
+ | `.juno-select` | Wrapper; draws the chevron and positions it (inline-end). |
20
+ | `.juno-select > .juno-input` | The native `<select>` reuses the input box; `appearance:none`, room reserved for the chevron. |
21
+
22
+ ## Anatomy (any platform)
23
+
24
+ - Box is identical to [input](./input.md): `s0` bg, neutral border, radius `4`,
25
+ density-aware padding.
26
+ - Chevron: a CSS triangle in `label` color at `space.12` from the inline-end edge —
27
+ inherits a token, no SVG, mirrors under RTL.
28
+
29
+ ## Usage
30
+
31
+ - Always a real `<select>` — keyboard and screen-reader behavior come for free.
32
+ - Role classes (`.juno--<role>`) and `aria-invalid` tint the border exactly as on input.
33
+ - Wrap in [`.juno-field`](./field.md) for a label.