@junoput01/junoui 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +251 -0
- package/README.md +23 -19
- package/dist/css/juno-custom-media.css +32 -0
- package/dist/css/juno.css +1355 -40
- package/dist/icons/inline.js +22 -0
- package/docs/accessibility.md +188 -0
- package/docs/boot-shell.md +295 -0
- package/docs/components/README.md +71 -0
- package/docs/components/accordion.md +49 -0
- package/docs/components/alert.md +46 -0
- package/docs/components/avatar.md +45 -0
- package/docs/components/badge.md +35 -0
- package/docs/components/breadcrumb.md +31 -0
- package/docs/components/button.md +32 -0
- package/docs/components/card.md +41 -0
- package/docs/components/checkbox.md +41 -0
- package/docs/components/chip.md +44 -0
- package/docs/components/divider.md +32 -0
- package/docs/components/dock.md +215 -0
- package/docs/components/drawer.md +100 -0
- package/docs/components/field.md +44 -0
- package/docs/components/fold-slot.md +31 -0
- package/docs/components/gauge.md +48 -0
- package/docs/components/icon-loader.md +122 -0
- package/docs/components/icon.md +70 -0
- package/docs/components/input.md +45 -0
- package/docs/components/list.md +76 -0
- package/docs/components/load-state.md +131 -0
- package/docs/components/loader.md +88 -0
- package/docs/components/menu.md +54 -0
- package/docs/components/modal.md +52 -0
- package/docs/components/navbar.md +53 -0
- package/docs/components/pagination.md +42 -0
- package/docs/components/pillbar.md +211 -0
- package/docs/components/popover.md +43 -0
- package/docs/components/rail.md +54 -0
- package/docs/components/readout.md +39 -0
- package/docs/components/reload.md +41 -0
- package/docs/components/segmented.md +46 -0
- package/docs/components/select.md +33 -0
- package/docs/components/skeleton.md +45 -0
- package/docs/components/slider.md +48 -0
- package/docs/components/spark.md +51 -0
- package/docs/components/status.md +30 -0
- package/docs/components/stepper.md +46 -0
- package/docs/components/switch.md +38 -0
- package/docs/components/table.md +126 -0
- package/docs/components/tabs.md +61 -0
- package/docs/components/thumb.md +81 -0
- package/docs/components/toast.md +48 -0
- package/docs/components/toggle-button.md +40 -0
- package/docs/components/tooltip.md +63 -0
- package/docs/design-guidelines.md +173 -0
- package/docs/flutter.md +42 -0
- package/docs/getting-started.md +93 -0
- package/docs/integration.md +95 -0
- package/docs/ios-conformance.md +224 -0
- package/docs/layout.md +271 -0
- package/docs/native.md +52 -0
- package/docs/roadmap.md +106 -0
- package/docs/tokens-reference.md +223 -0
- package/docs/web.md +95 -0
- package/package.json +7 -3
- package/src/css/base.css +171 -1
- package/src/css/components/dock.css +335 -0
- package/src/css/components/drawer.css +40 -3
- package/src/css/components/fold-slot.css +44 -0
- package/src/css/components/icon-loader.css +67 -0
- package/src/css/components/icon.css +6 -4
- package/src/css/components/load-state.css +136 -0
- package/src/css/components/loader.css +6 -0
- package/src/css/components/menu.css +4 -0
- package/src/css/components/modal.css +24 -3
- package/src/css/components/navbar.css +5 -1
- package/src/css/components/pillbar.css +222 -7
- package/src/css/components/rail.css +8 -0
- package/src/css/components/reload.css +48 -0
- package/src/css/components/skeleton.css +41 -13
- package/src/css/components/tabs.css +5 -0
- package/src/css/components/thumb.css +63 -1
- package/src/css/components/toast.css +5 -1
- package/src/css/density.css +22 -0
- package/src/css/layout.css +95 -5
- package/src/css/utilities.css +4 -1
package/docs/layout.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Layout & responsiveness
|
|
2
|
+
|
|
3
|
+
How blocks adapt — defined once, inherited by every UI. Two mechanisms:
|
|
4
|
+
|
|
5
|
+
1. **Intrinsic layout primitives** — reflow by available space, no media queries.
|
|
6
|
+
2. **Container queries** — a component restyles by _its own_ width, not the viewport
|
|
7
|
+
(right for a library dropped into unknown layouts).
|
|
8
|
+
|
|
9
|
+
Breakpoint tokens (`--juno-bp-sm…2xl`) follow Tailwind's scale and exist for the
|
|
10
|
+
rare viewport-level case.
|
|
11
|
+
|
|
12
|
+
## Why container queries over viewport breakpoints
|
|
13
|
+
|
|
14
|
+
junoui components live inside arbitrary app skeletons. A card doesn't know if it's
|
|
15
|
+
in a 280px sidebar or full width — so it adapts to its container:
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
.juno-card {
|
|
19
|
+
container-type: inline-size;
|
|
20
|
+
} /* already set */
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`.juno-card__row` stacks automatically when the card is < 320px wide, anywhere.
|
|
24
|
+
|
|
25
|
+
## Layout primitives
|
|
26
|
+
|
|
27
|
+
Wrap a region; it adapts on resize. Every knob is a custom property with a token
|
|
28
|
+
default — override per instance inline.
|
|
29
|
+
|
|
30
|
+
| Class | Does | Key knob (default) |
|
|
31
|
+
| ------------------------ | ---------------------------------------- | ---------------------------------------- |
|
|
32
|
+
| `.juno-center` | Max-measure wrapper, fluid gutters | `--juno-measure` (`bp-xl`) |
|
|
33
|
+
| `.juno-stack` | Vertical rhythm between children | `--juno-stack-space` (`space-16`) |
|
|
34
|
+
| `.juno-cluster` | Wrapping inline group (toolbars, tags) | `--juno-cluster-space` (`space-8`) |
|
|
35
|
+
| `.juno-grid-auto` | Cards that collapse columns themselves | `--juno-grid-min` (`240px`) |
|
|
36
|
+
| `.juno-grid-auto--tiles` | Media wall wired to the density layer | `--juno-tile-min` / `--juno-gap-content` |
|
|
37
|
+
| `.juno-sidebar` | Aside + fluid content, stacks when tight | `--juno-sidebar-width` (`280px`) |
|
|
38
|
+
| `.juno-switcher` | N-up or all-stacked at a threshold | `--juno-switcher-threshold` (`bp-sm`) |
|
|
39
|
+
| `.juno-scroller` | Bare scroll container (axis/snap/bar) | `--juno-scroller-snap` (`none`) |
|
|
40
|
+
| `.juno-reel` | Horizontal scroll-snap row | `--juno-reel-space` (`space-12`) |
|
|
41
|
+
|
|
42
|
+
### Examples
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<!-- responsive card grid — no breakpoints, columns just fit -->
|
|
46
|
+
<div class="juno-grid-auto" style="--juno-grid-min:280px;">
|
|
47
|
+
<article class="juno-card">…</article>
|
|
48
|
+
<article class="juno-card">…</article>
|
|
49
|
+
<article class="juno-card">…</article>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<!-- toolbar that wraps -->
|
|
53
|
+
<div class="juno-cluster">
|
|
54
|
+
<button class="juno-btn juno--nominal">CONFIRM</button>
|
|
55
|
+
<button class="juno-btn juno-btn--ghost">CANCEL</button>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- sidebar + content; stacks when content would get too narrow -->
|
|
59
|
+
<div class="juno-sidebar">
|
|
60
|
+
<aside class="juno-sidebar__aside">…</aside>
|
|
61
|
+
<main class="juno-sidebar__main">…</main>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<!-- two-up that flips to stacked under ~640px of space -->
|
|
65
|
+
<div class="juno-switcher">
|
|
66
|
+
<div>A</div>
|
|
67
|
+
<div>B</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!-- media wall: tile size + gap follow [data-juno-density] -->
|
|
71
|
+
<div class="juno-grid-auto juno-grid-auto--tiles"><img … /><img … /><img … /></div>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`--tiles` reads `--juno-tile-min` / `--juno-gap-content` from the density layer
|
|
75
|
+
(`150px` / `space-10` comfortable, `108px` / `space-4` compact), so one
|
|
76
|
+
`data-juno-density` attribute re-densifies controls, surfaces **and** content
|
|
77
|
+
grids together.
|
|
78
|
+
|
|
79
|
+
## Scroller
|
|
80
|
+
|
|
81
|
+
Every scrolling region in the library — `.juno-reel`, `.juno-app-shell__main`,
|
|
82
|
+
tab strips — is the same three knobs: overflow axis, overscroll containment,
|
|
83
|
+
snap type. `.juno-scroller` ships them as overridable custom props instead of
|
|
84
|
+
each consumer re-deriving (and usually forgetting `overscroll-behavior`, which
|
|
85
|
+
lets iOS pull-to-refresh/scroll-chain through an inner scroller into the
|
|
86
|
+
page). Defaults: `overflow: auto` (both axes), `overscroll-behavior: contain`,
|
|
87
|
+
no snap.
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<!-- vertical list scroller with containment, no snap -->
|
|
91
|
+
<div class="juno-scroller juno-scroller--y">…</div>
|
|
92
|
+
|
|
93
|
+
<!-- horizontal, scrollbar hidden, softer "proximity" snap, opt-in stops -->
|
|
94
|
+
<div
|
|
95
|
+
class="juno-scroller juno-scroller--x juno-scroller--bare"
|
|
96
|
+
style="--juno-scroller-snap: x proximity;"
|
|
97
|
+
>
|
|
98
|
+
<div class="juno-snap">…</div>
|
|
99
|
+
<div class="juno-snap">…</div>
|
|
100
|
+
</div>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- `.juno-scroller--x` — horizontal axis only (`overflow: auto hidden`)
|
|
104
|
+
- `.juno-scroller--y` — vertical axis only (`overflow: hidden auto`)
|
|
105
|
+
- `.juno-scroller--bare` — hides the scrollbar (Firefox + WebKit)
|
|
106
|
+
- `.juno-snap` — on a child: opts into `scroll-snap-align`
|
|
107
|
+
|
|
108
|
+
`.juno-reel` is `.juno-scroller`'s horizontal-snap preset baked into one
|
|
109
|
+
class: it now reads its `scroll-snap-type` from the same `--juno-scroller-snap`
|
|
110
|
+
prop (default unchanged: `inline mandatory`), so the mode is overridable
|
|
111
|
+
per instance instead of hardcoded — e.g. a "magnet" strip that wants
|
|
112
|
+
`proximity` instead of a stepped `mandatory` feel:
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<div class="juno-reel" style="--juno-scroller-snap: inline proximity;">…</div>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Gesture surfaces
|
|
119
|
+
|
|
120
|
+
For an element whose pointer events an app JS layer owns outright — drag-pan,
|
|
121
|
+
pinch-zoom, swipe classification, anything that is a state machine rather than
|
|
122
|
+
native scrolling — junoui ships the CSS side of that contract as one class.
|
|
123
|
+
The gesture handler itself is the app's job (or a sibling `junoui-<framework>`
|
|
124
|
+
package): junoui declares the surface, never the logic.
|
|
125
|
+
|
|
126
|
+
```html
|
|
127
|
+
<div class="juno-gesture-surface" id="viewport"><!-- JS drag/pinch handlers attach here --></div>
|
|
128
|
+
|
|
129
|
+
<!-- only needs the touch-action axis lock, not the full reset -->
|
|
130
|
+
<li class="juno-list__item juno-pan-x"><!-- swipe-to-reveal row --></li>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`.juno-gesture-surface` sets `touch-action: var(--juno-touch-action, none)`,
|
|
134
|
+
`-webkit-touch-callout: none`, `user-select: none` and
|
|
135
|
+
`-webkit-tap-highlight-color: transparent` — so the UA never fights the
|
|
136
|
+
handler with its own scroll/zoom recognition, long-press callout, text
|
|
137
|
+
selection or tap flash. Override `--juno-touch-action` per instance to hand
|
|
138
|
+
back one axis (`pan-x` / `pan-y`) instead of all of them. `.juno-pan-x` /
|
|
139
|
+
`.juno-pan-y` are standalone single-axis classes for elements that want the
|
|
140
|
+
axis lock alone.
|
|
141
|
+
|
|
142
|
+
These four properties are **community convention, not Apple-documented
|
|
143
|
+
behavior** — see [ios-conformance.md](./ios-conformance.md) before citing them
|
|
144
|
+
as a platform requirement.
|
|
145
|
+
|
|
146
|
+
## App shell
|
|
147
|
+
|
|
148
|
+
Every product app assembles the same frame; `.juno-app-shell` ships it as
|
|
149
|
+
classes — a collapsible [rail](./components/rail.md), a topbar, a scrolling
|
|
150
|
+
content outlet, and a [dock](./components/dock.md) at the foot — so you stop
|
|
151
|
+
copy-pasting the same `<style>` block into every app.
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<div class="juno-app-shell">
|
|
155
|
+
<nav class="juno-rail juno-rail--responsive" aria-label="Primary">
|
|
156
|
+
<div class="juno-rail__brand">JUNO</div>
|
|
157
|
+
<a class="juno-rail__item" href="/library" aria-current="page">
|
|
158
|
+
<svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
|
|
159
|
+
<span class="juno-rail__label">Library</span>
|
|
160
|
+
</a>
|
|
161
|
+
</nav>
|
|
162
|
+
<div class="juno-app-shell__body">
|
|
163
|
+
<header class="juno-app-shell__topbar">
|
|
164
|
+
<input class="juno-input" type="search" placeholder="SEARCH…" />
|
|
165
|
+
<span class="juno-badge juno-badge--soft juno--nominal">ONLINE</span>
|
|
166
|
+
</header>
|
|
167
|
+
<main class="juno-app-shell__main">…</main>
|
|
168
|
+
<nav class="juno-dock juno-hide-from-md" aria-label="Primary">
|
|
169
|
+
<a class="juno-dock__item" href="/library" aria-current="page">
|
|
170
|
+
<svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
|
|
171
|
+
<span class="juno-dock__label">Library</span>
|
|
172
|
+
</a>
|
|
173
|
+
</nav>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
What the primitive encodes so you don't have to:
|
|
179
|
+
|
|
180
|
+
- **`100dvh`, not `100vh`** — the shell fills the _dynamic_ viewport, so the
|
|
181
|
+
dock isn't clipped by the phone's shrinking address bar.
|
|
182
|
+
- **The `__main` region is the scroller**, not the page. The dock (or
|
|
183
|
+
[pillbar](./components/pillbar.md)) is a flex sibling at the body foot, so it
|
|
184
|
+
stays pinned with zero `sticky`/`fixed` and never overlaps content — the
|
|
185
|
+
short-page pitfall of sticky nav bars (below) can't happen here.
|
|
186
|
+
- **Safe-area insets** — the shell pads for landscape notches
|
|
187
|
+
(`inset-left`/`right`), the topbar for `inset-top`, the dock for
|
|
188
|
+
`inset-bottom`. **This requires `viewport-fit=cover` in your page's viewport
|
|
189
|
+
meta** ([getting-started](./getting-started.md#required-the-viewport-meta)) —
|
|
190
|
+
without it iOS reports every inset as `0` and none of this padding happens.
|
|
191
|
+
|
|
192
|
+
Collapse the rail by toggling `.juno-rail--collapsed` (one class; the width
|
|
193
|
+
transition and label hiding are built in). Trays/detail panels: the
|
|
194
|
+
[slide-over](./components/drawer.md#the-slide-over-pattern) pattern in the
|
|
195
|
+
drawer doc. Knobs: `--juno-app-shell-topbar-size` (topbar height).
|
|
196
|
+
|
|
197
|
+
### Narrow viewports (phone)
|
|
198
|
+
|
|
199
|
+
The rail↔dock swap is two classes, no JS: `.juno-rail--responsive` self-hides
|
|
200
|
+
below `md`, and the dock carries `.juno-hide-from-md` so it shows only there.
|
|
201
|
+
(Equivalent to hanging `.juno-hide-below-md` on the rail yourself — the
|
|
202
|
+
modifier just saves you knowing to.) Keep 3–5 dock destinations; the rest go
|
|
203
|
+
behind a "More" item (drawer or menu). Prefer a floating bar? Swap the dock
|
|
204
|
+
for a [pillbar](./components/pillbar.md) — same contract, capsule look.
|
|
205
|
+
|
|
206
|
+
**Viewport helpers.** For the cases an intrinsic primitive can't express
|
|
207
|
+
(swap a nav for a menu button), hide/show by breakpoint at `sm` (640px),
|
|
208
|
+
`md` (768px), `lg` (1024px):
|
|
209
|
+
|
|
210
|
+
| Class | Visible |
|
|
211
|
+
| -------------------------------------------- | -------------- |
|
|
212
|
+
| `.juno-hide-below-md` / `.juno-show-from-md` | at `md` and up |
|
|
213
|
+
| `.juno-hide-from-md` / `.juno-show-below-md` | below `md` |
|
|
214
|
+
|
|
215
|
+
`show-*` are readable aliases for the inverse `hide-*` (`show-from-md` ≡
|
|
216
|
+
`hide-below-md`); pick whichever reads clearer at the call site. Same three
|
|
217
|
+
cut points for `sm` and `lg`.
|
|
218
|
+
|
|
219
|
+
### Page-scroll shells (dock/pillbar `--fixed`)
|
|
220
|
+
|
|
221
|
+
`.juno-app-shell` is the recommended frame because its `__main` scroller keeps
|
|
222
|
+
the dock in flow. If instead the **whole page** scrolls, the dock/pillbar use
|
|
223
|
+
`position: sticky` — which only pins _while the column overflows_. On a short
|
|
224
|
+
page that doesn't scroll, a sticky bar lands mid-content, reading as "not
|
|
225
|
+
stuck." For that layout use `.juno-dock--fixed` (pins flush to the viewport
|
|
226
|
+
foot) or `.juno-pillbar--fixed` (fixes to the viewport, still floating its gap
|
|
227
|
+
above the foot) — then reserve the bar's footprint at the page foot (e.g.
|
|
228
|
+
`padding-block-end`) so it doesn't cover the last row.
|
|
229
|
+
|
|
230
|
+
### Tab + stack (phone navigation recipe)
|
|
231
|
+
|
|
232
|
+
The full phone pattern is three parts: the dock or pillbar switches
|
|
233
|
+
_sections_; inside a section, a [list](./components/list.md) row (or any
|
|
234
|
+
link) pushes a detail view; every pushed view opens with a
|
|
235
|
+
[navbar](./components/navbar.md) whose back control unwinds one level.
|
|
236
|
+
junoui ships all three looks — the app owns the stack (routing/history):
|
|
237
|
+
|
|
238
|
+
```html
|
|
239
|
+
<div class="juno-app-shell">
|
|
240
|
+
<div class="juno-app-shell__body">
|
|
241
|
+
<!-- one section, drilled one level in -->
|
|
242
|
+
<header class="juno-navbar">
|
|
243
|
+
<a class="juno-navbar__back" href="/settings">
|
|
244
|
+
<svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-caret-left" /></svg>
|
|
245
|
+
<span class="juno-navbar__back-label">Settings</span>
|
|
246
|
+
</a>
|
|
247
|
+
<h1 class="juno-navbar__title">Playback</h1>
|
|
248
|
+
<div class="juno-navbar__actions"></div>
|
|
249
|
+
</header>
|
|
250
|
+
<main class="juno-app-shell__main"><!-- .juno-list groups… --></main>
|
|
251
|
+
<nav class="juno-pillbar" aria-label="Primary"><!-- section tabs --></nav>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Adopting in an existing project
|
|
257
|
+
|
|
258
|
+
No restructuring required — additive and incremental:
|
|
259
|
+
|
|
260
|
+
1. Set `data-juno-palette` / `data-juno-mode`, swap hardcoded values → `var(--juno-*)`.
|
|
261
|
+
2. Add component classes where blocks match.
|
|
262
|
+
3. Wrap layout regions in a primitive (`.juno-grid-auto`, `.juno-cluster`, …) to get
|
|
263
|
+
reflow. Add `container-type: inline-size` to a wrapper for component-level queries.
|
|
264
|
+
|
|
265
|
+
You opt in per region; nothing forces a markup shape.
|
|
266
|
+
|
|
267
|
+
## The JS line
|
|
268
|
+
|
|
269
|
+
These are all CSS. Behavior that needs state (resize observers feeding app state,
|
|
270
|
+
virtualization, drag-resizable panels) belongs in your app or a sibling
|
|
271
|
+
`junoui-<framework>` package — not the design system.
|
package/docs/native.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Native mobile (Android / iOS)
|
|
2
|
+
|
|
3
|
+
Native platforms can't parse `oklch()`, so colors are pre-converted to sRGB hex
|
|
4
|
+
during the build. Values match the web rendering.
|
|
5
|
+
|
|
6
|
+
## Android
|
|
7
|
+
|
|
8
|
+
Copy or sync the generated resources into your module:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
dist/android/colors.xml → res/values/colors.xml
|
|
12
|
+
dist/android/dimens.xml → res/values/dimens.xml
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Reference them:
|
|
16
|
+
|
|
17
|
+
```xml
|
|
18
|
+
<TextView
|
|
19
|
+
android:textColor="@color/standard_dark_nominal"
|
|
20
|
+
android:padding="@dimen/space_16"
|
|
21
|
+
android:textSize="@dimen/font_size_14" />
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- Color names: `<palette>_<mode>_<role>` (e.g. `colorblind_dark_warning`).
|
|
25
|
+
- Dimensions are `dp`; font sizes are `sp`.
|
|
26
|
+
- Theme switching: pick the resource set for the active palette/mode, or split the
|
|
27
|
+
files into qualified `values-night/` for dark mode.
|
|
28
|
+
|
|
29
|
+
## iOS (Swift)
|
|
30
|
+
|
|
31
|
+
Add the generated file to your target:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
dist/ios/JunoTokens.swift
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```swift
|
|
38
|
+
label.textColor = JunoTokens.standardDarkNominal
|
|
39
|
+
let pad: CGFloat = JunoTokens.space16
|
|
40
|
+
let body: CGFloat = JunoTokens.fontSize14
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- Colors are `UIColor` constants named `<palette><Mode><Role>` (camelCase).
|
|
44
|
+
- Dimensions are `CGFloat` constants.
|
|
45
|
+
|
|
46
|
+
## Keeping in sync
|
|
47
|
+
|
|
48
|
+
Re-run `npm run build` in junoui and re-copy the files (or script the copy in your
|
|
49
|
+
CI). Because all platforms derive from the same `tokens/` source, the values can
|
|
50
|
+
never drift between web and native.
|
|
51
|
+
|
|
52
|
+
Exact values for every token: [tokens-reference.md](./tokens-reference.md).
|
package/docs/roadmap.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Roadmap — missing capabilities
|
|
2
|
+
|
|
3
|
+
Gap analysis vs mature design systems (Material, Carbon, Radix, Polaris, Tailwind).
|
|
4
|
+
What junoui does **not** yet have, prioritised. The framework line holds throughout:
|
|
5
|
+
junoui ships the **look + the accessibility/structure contract**; stateful behavior
|
|
6
|
+
(focus traps, open/close, positioning, data) lives in apps or a sibling
|
|
7
|
+
`junoui-<framework>` package.
|
|
8
|
+
|
|
9
|
+
Priority key: 🔴 must · 🟡 high · 🟢 nice.
|
|
10
|
+
|
|
11
|
+
## Have today
|
|
12
|
+
|
|
13
|
+
Tokens (color · spacing · type · radius · border · size · breakpoints · motion ·
|
|
14
|
+
z-index · elevation · opacity), density modes, themes (3 palettes × dark/light), CSS
|
|
15
|
+
components (badge, button, card, readout, status dot, loaders, **form controls** —
|
|
16
|
+
field · input · select · checkbox · radio · switch · slider; **overlays** — modal ·
|
|
17
|
+
drawer · tooltip · popover · menu), layout primitives + container queries,
|
|
18
|
+
multi-platform outputs, docs, lint + tests + CI.
|
|
19
|
+
|
|
20
|
+
## Foundations (token gaps) — ✅ shipped 2026-06
|
|
21
|
+
|
|
22
|
+
All foundation token gaps are now built. Values: [tokens-reference.md](./tokens-reference.md);
|
|
23
|
+
usage: [design-guidelines.md](./design-guidelines.md).
|
|
24
|
+
|
|
25
|
+
| Done | What shipped |
|
|
26
|
+
| --------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| **Motion** (duration + easing) | `--juno-motion-duration-{instant,quick,base,deliberate}` + `--juno-motion-ease-{decel,accel,standard,spring}`. |
|
|
28
|
+
| **Z-index scale** | `--juno-z-*` layer stack: surface · raised · anchored · overlay · alert. |
|
|
29
|
+
| **Elevation / shadow** | `--juno-shadow-{1,2,3}` (e1–e3) — border-first depth; shadow for lifted surfaces. |
|
|
30
|
+
| **Opacity scale** | `--juno-opacity-{disabled,muted,scrim}`. |
|
|
31
|
+
| **Density modes** (compact/comfy) | `data-juno-density` swaps semantic padding aliases (`--juno-pad-*`, `--juno-gap-control`). |
|
|
32
|
+
|
|
33
|
+
## Components
|
|
34
|
+
|
|
35
|
+
| Missing | Priority |
|
|
36
|
+
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
37
|
+
| ~~**Form controls** — input, textarea, select, checkbox, radio, switch, slider~~ | ✅ shipped |
|
|
38
|
+
| ~~**Field** wrapper — label + control + help + error + required~~ | ✅ shipped |
|
|
39
|
+
| ~~**Overlays** — modal/dialog, drawer, tooltip, popover, menu/dropdown~~ | ✅ shipped |
|
|
40
|
+
| ~~**Table / data grid** styling~~ | ✅ shipped |
|
|
41
|
+
| ~~**Alert / toast / inline notification**~~ | ✅ shipped |
|
|
42
|
+
| ~~**Tabs**, accordion / disclosure~~ | ✅ shipped |
|
|
43
|
+
| ~~**Skeleton** loading placeholder (pairs with loaders)~~ | ✅ shipped |
|
|
44
|
+
| ~~Avatar, chip/tag, divider, breadcrumb, pagination, stepper~~ | ✅ shipped |
|
|
45
|
+
| **Chat layer** (`junoui-chat`) — message bubble, list, day separator, system pill, attachment cards, conversation header, chat-row, rail. Requested by the buzz integration; highest-leverage gap for chat apps. | 🟡 |
|
|
46
|
+
| Calendar **visuals** (event chip, day-cell) | 🟢 |
|
|
47
|
+
|
|
48
|
+
## Field-driven — ✅ shipped 2026-07
|
|
49
|
+
|
|
50
|
+
Gaps surfaced by the first production consumer (a media-server web client, 2026-07):
|
|
51
|
+
everything a real app had to hand-roll on top of junoui, rebuilt here as generic,
|
|
52
|
+
reusable pieces. The rule stands — features land app-agnostic; only the origin is
|
|
53
|
+
logged.
|
|
54
|
+
|
|
55
|
+
| Done | What shipped |
|
|
56
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
57
|
+
| **Dense sizes** | `.juno-btn--sm` + `.juno-switch--sm` for 40–46px toolbar chrome / per-row toggles. |
|
|
58
|
+
| **Segmented control** | `.juno-seg` — radio-driven exclusive pill row, zero JS; `aria-pressed` button flavor. |
|
|
59
|
+
| **Gauge** | `.juno-gauge` — determinate metric ring (conic-gradient), value centered, threshold recipe doc. |
|
|
60
|
+
| **Spark** | `.juno-spark` — sparkline size/stroke/color contract (app supplies points; no charting shipped). |
|
|
61
|
+
| **Micro badge** | `.juno-badge--micro` — mono data-UI atom for provenance/kind tags + threshold values. |
|
|
62
|
+
| **Rail + app shell** | `.juno-rail` (collapsible, `aria-current`-styled) + `layout.md#app-shell` recipe. |
|
|
63
|
+
| **Content density** | `--juno-tile-min`/`--juno-gap-content` archetype + `.juno-grid-auto--tiles`. |
|
|
64
|
+
| **Slide-over recipe** | Drawer doc: scrim + header/body/pinned-footer composition from existing parts. |
|
|
65
|
+
| **Media/system icons** | 14 Phosphor glyphs: squares-four · images · hexagon · puzzle-piece · play · film-strip · cloud · cloud-arrow-down · arrows-clockwise · cpu · hard-drives · sliders · arrows-out · upload-simple. |
|
|
66
|
+
|
|
67
|
+
## Mobile — ✅ shipped 2026-07
|
|
68
|
+
|
|
69
|
+
Mobile-first structures for narrow viewports and touch, automatic where safe,
|
|
70
|
+
opt-in where markup is needed:
|
|
71
|
+
|
|
72
|
+
| Done | What shipped |
|
|
73
|
+
| -------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
74
|
+
| **Dock** | `.juno-dock` — bottom nav, phone counterpart of the rail; sticky, safe-area padded; shell swap recipe in `layout.md`. |
|
|
75
|
+
| **Bottom sheet** | Modal auto-converts below `bp.sm`: full-width, top-rounded, slides up, stretched footer actions. |
|
|
76
|
+
| **Drawer phone fit** | Side drawers cap at `85vw` (scrim stays tappable); bottom drawer pads for the home indicator. |
|
|
77
|
+
| **Toast snackbar** | Full-width bottom stack on phones; slides up instead of sideways. |
|
|
78
|
+
| **Scrollable tabs** | Tab strip scrolls sideways instead of overflowing. |
|
|
79
|
+
| **Stacked table** | `.juno-table--stack` + `data-label` — card rows below a 480px container; real `<table>` semantics kept. |
|
|
80
|
+
| **Touch ergonomics** | `pointer: coarse` raises `--juno-size-tap-min` → 44px; `hover: none` keeps table row actions visible. |
|
|
81
|
+
| **Pillbar** | `.juno-pillbar` — floating pill bar (iOS-style): 2–5 icon destinations/actions, translucent + blurred, safe-area. |
|
|
82
|
+
| **Navbar** | `.juno-navbar` — stack top bar: back control always on the start edge, centered truncating title, trailing actions. |
|
|
83
|
+
| **List** | `.juno-list` — grouped rows (settings pattern): icon + label/support + trailing value/control/chevron. |
|
|
84
|
+
| **Tab + stack** | Shell recipe in `layout.md`: dock/pillbar switches sections, navbar backs out of pushed views. |
|
|
85
|
+
|
|
86
|
+
## Quality / infra
|
|
87
|
+
|
|
88
|
+
| Missing | Why | Priority |
|
|
89
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------ | -------- |
|
|
90
|
+
| ~~**Visual regression** snapshots (Playwright)~~ | ✅ shipped — `npm run test:visual` diffs every showcase page (dark + light). | ✅ |
|
|
91
|
+
| ~~**Changesets**~~ | ✅ shipped — `npm run changeset`; manual Version PR (`npm run version`) → CI publishes on merge. | ✅ |
|
|
92
|
+
| ~~**Icon convention / set**~~ | ✅ shipped — `.juno-icon` + SVG sprite (Phosphor bold, MIT). | ✅ |
|
|
93
|
+
| **eslint** (flat config) | JS surface is small; prettier + tests cover most. | 🟢 |
|
|
94
|
+
|
|
95
|
+
Done already: stylelint + prettier, `node:test` integrity suite, a11y doc + ARIA
|
|
96
|
+
contract, forced-colors, RTL via logical properties, CI gate.
|
|
97
|
+
|
|
98
|
+
## Recommended order
|
|
99
|
+
|
|
100
|
+
1. ~~**Foundation tokens** — motion, z-index, elevation, opacity, density.~~ ✅ done.
|
|
101
|
+
2. ~~**Form controls + field** — the single biggest capability gap.~~ ✅ done.
|
|
102
|
+
3. ~~**Overlays** — modal, tooltip, menu.~~ ✅ done.
|
|
103
|
+
4. ~~**Table / data grid** — sortable header, cell types, row states, overflow, skeleton/empty.~~ ✅ done.
|
|
104
|
+
5. ~~**Quality** — visual-regression snapshots + changesets.~~ ✅ done.
|
|
105
|
+
|
|
106
|
+
Biggest leverage: **#1 + #2.**
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
<!-- GENERATED by scripts/gen-docs.mjs — do not edit by hand. Run `npm run gen-docs`. -->
|
|
2
|
+
|
|
3
|
+
# Token reference
|
|
4
|
+
|
|
5
|
+
Every junoui token with its value and the identifier to use on each platform.
|
|
6
|
+
Colors show the authored value and the resolved sRGB hex (use the hex in any
|
|
7
|
+
tool that does not understand `oklch()`).
|
|
8
|
+
|
|
9
|
+
## How names map across platforms
|
|
10
|
+
|
|
11
|
+
| Platform | Pattern | Example (`color.standard.dark.nominal`) |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| CSS — semantic | `var(--juno-<role>)` (switches with theme attrs) | `var(--juno-nominal)` |
|
|
14
|
+
| SCSS | `$juno-color-<palette>-<mode>-<role>` | `$juno-color-standard-dark-nominal` |
|
|
15
|
+
| JS / TS | `TOKENS.<palette>.<mode>.<role>` | `TOKENS.standard.dark.nominal` |
|
|
16
|
+
| JSON (DTCG) | `color.<palette>.<mode>.<role>` | `color.standard.dark.nominal` |
|
|
17
|
+
| Android | `@color/<palette>_<mode>_<role>` | `@color/standard_dark_nominal` |
|
|
18
|
+
| iOS (Swift) | `JunoTokens.<camelCase>` | `JunoTokens.standardDarkNominal` |
|
|
19
|
+
| Flutter (Dart) | `JunoTokens.<camelCase>` | `JunoTokens.standardDarkNominal` |
|
|
20
|
+
|
|
21
|
+
Core tokens (spacing, radius, typography, …) use `--juno-<path-joined-by->`,
|
|
22
|
+
e.g. `space.16` → `var(--juno-space-16)`, `@dimen/space_16`, `JunoTokens.space16`.
|
|
23
|
+
|
|
24
|
+
## Color roles
|
|
25
|
+
|
|
26
|
+
Color encodes status, never decoration. Each role has exactly one meaning.
|
|
27
|
+
|
|
28
|
+
### Palette: colorblind
|
|
29
|
+
|
|
30
|
+
| Role | Dark value | Dark hex | Light value | Light hex |
|
|
31
|
+
|---|---|---|---|---|
|
|
32
|
+
| `nominal` | `#78A9FF` | `#78A9FF` | `#0043CE` | `#0043CE` |
|
|
33
|
+
| `active` | `#BE95FF` | `#BE95FF` | `#6929C4` | `#6929C4` |
|
|
34
|
+
| `target` | `#FF7EB6` | `#FF7EB6` | `#9F1853` | `#9F1853` |
|
|
35
|
+
| `caution` | `#F1C21B` | `#F1C21B` | `#7D4F00` | `#7D4F00` |
|
|
36
|
+
| `warning` | `#FF832B` | `#FF832B` | `#BA4300` | `#BA4300` |
|
|
37
|
+
| `data` | `oklch(93% 0.008 85)` | `#EAE7E2` | `oklch(14% 0.008 85)` | `#0B0906` |
|
|
38
|
+
| `data-dim` | `oklch(38% 0.010 85)` | `#45423C` | `oklch(70% 0.008 85)` | `#A19E99` |
|
|
39
|
+
| `label` | `oklch(63% 0.012 85)` | `#8C8981` | `oklch(42% 0.010 85)` | `#504D47` |
|
|
40
|
+
| `muted` | `oklch(48.5% 0.010 85)` | `#625F59` | `oklch(63% 0.008 85)` | `#8B8984` |
|
|
41
|
+
| `border` | `oklch(30% 0.012 85)` | `#312D27` | `oklch(82% 0.010 85)` | `#C7C4BD` |
|
|
42
|
+
| `border-strong` | `oklch(40% 0.012 85)` | `#4B4740` | `oklch(74% 0.010 85)` | `#AEAAA4` |
|
|
43
|
+
| `s0` | `oklch(11% 0.010 85)` | `#060402` | `oklch(97% 0.008 85)` | `#F8F5EF` |
|
|
44
|
+
| `s1` | `oklch(15% 0.012 85)` | `#0D0B06` | `oklch(93% 0.010 85)` | `#EBE7E0` |
|
|
45
|
+
| `s2` | `oklch(19% 0.012 85)` | `#16130E` | `oklch(89% 0.010 85)` | `#DEDAD3` |
|
|
46
|
+
| `s3` | `oklch(24% 0.012 85)` | `#221F19` | `oklch(85% 0.010 85)` | `#D1CDC7` |
|
|
47
|
+
|
|
48
|
+
### Palette: soft
|
|
49
|
+
|
|
50
|
+
| Role | Dark value | Dark hex | Light value | Light hex |
|
|
51
|
+
|---|---|---|---|---|
|
|
52
|
+
| `nominal` | `oklch(63% 0.13 155)` | `#38A065` | `oklch(40% 0.11 155)` | `#00582C` |
|
|
53
|
+
| `active` | `oklch(67% 0.12 210)` | `#00A8BE` | `oklch(44% 0.11 210)` | `#006174` |
|
|
54
|
+
| `target` | `oklch(58% 0.14 318)` | `#9C5CAF` | `oklch(42% 0.12 318)` | `#673477` |
|
|
55
|
+
| `caution` | `oklch(72% 0.12 75)` | `#D09945` | `oklch(50% 0.12 75)` | `#8A5700` |
|
|
56
|
+
| `warning` | `oklch(62% 0.15 30)` | `#D15D4D` | `oklch(42% 0.13 30)` | `#86281D` |
|
|
57
|
+
| `data` | `oklch(90% 0.008 88)` | `#E0DED8` | `oklch(14% 0.008 88)` | `#0A0906` |
|
|
58
|
+
| `data-dim` | `oklch(39% 0.010 88)` | `#47453F` | `oklch(69% 0.008 88)` | `#9D9B96` |
|
|
59
|
+
| `label` | `oklch(63% 0.010 88)` | `#8C8982` | `oklch(44% 0.010 88)` | `#55524C` |
|
|
60
|
+
| `muted` | `oklch(48.5% 0.010 88)` | `#615F59` | `oklch(62.5% 0.008 88)` | `#8A8782` |
|
|
61
|
+
| `border` | `oklch(31% 0.010 88)` | `#32302B` | `oklch(84% 0.010 88)` | `#CDCAC3` |
|
|
62
|
+
| `border-strong` | `oklch(41% 0.010 88)` | `#4D4A44` | `oklch(76% 0.010 88)` | `#B4B1AA` |
|
|
63
|
+
| `s0` | `oklch(12% 0.012 88)` | `#070602` | `oklch(96% 0.010 88)` | `#F4F2EA` |
|
|
64
|
+
| `s1` | `oklch(16% 0.012 88)` | `#0F0D08` | `oklch(92% 0.010 88)` | `#E7E4DD` |
|
|
65
|
+
| `s2` | `oklch(20% 0.012 88)` | `#181610` | `oklch(88% 0.010 88)` | `#DAD7D0` |
|
|
66
|
+
| `s3` | `oklch(25% 0.012 88)` | `#24211B` | `oklch(84% 0.010 88)` | `#CDCAC3` |
|
|
67
|
+
|
|
68
|
+
### Palette: standard
|
|
69
|
+
|
|
70
|
+
| Role | Dark value | Dark hex | Light value | Light hex |
|
|
71
|
+
|---|---|---|---|---|
|
|
72
|
+
| `nominal` | `oklch(73% 0.22 148)` | `#00CB4C` | `oklch(42% 0.18 148)` | `#006400` |
|
|
73
|
+
| `active` | `oklch(76% 0.16 204)` | `#00CDDF` | `oklch(47% 0.16 220)` | `#006B98` |
|
|
74
|
+
| `target` | `oklch(65% 0.26 324)` | `#D63DE6` | `oklch(45% 0.22 324)` | `#8B0097` |
|
|
75
|
+
| `caution` | `oklch(77% 0.17 73)` | `#F4A000` | `oklch(50% 0.17 73)` | `#9B4C00` |
|
|
76
|
+
| `warning` | `oklch(63% 0.22 28)` | `#F13A32` | `oklch(42% 0.21 26)` | `#A10000` |
|
|
77
|
+
| `data` | `oklch(93% 0.008 85)` | `#EAE7E2` | `oklch(14% 0.008 85)` | `#0B0906` |
|
|
78
|
+
| `data-dim` | `oklch(38% 0.010 85)` | `#45423C` | `oklch(70% 0.008 85)` | `#A19E99` |
|
|
79
|
+
| `label` | `oklch(63% 0.012 85)` | `#8C8981` | `oklch(42% 0.010 85)` | `#504D47` |
|
|
80
|
+
| `muted` | `oklch(48.5% 0.010 85)` | `#625F59` | `oklch(63% 0.008 85)` | `#8B8984` |
|
|
81
|
+
| `border` | `oklch(30% 0.012 85)` | `#312D27` | `oklch(82% 0.010 85)` | `#C7C4BD` |
|
|
82
|
+
| `border-strong` | `oklch(40% 0.012 85)` | `#4B4740` | `oklch(74% 0.010 85)` | `#AEAAA4` |
|
|
83
|
+
| `s0` | `oklch(11% 0.010 85)` | `#060402` | `oklch(97% 0.008 85)` | `#F8F5EF` |
|
|
84
|
+
| `s1` | `oklch(15% 0.012 85)` | `#0D0B06` | `oklch(93% 0.010 85)` | `#EBE7E0` |
|
|
85
|
+
| `s2` | `oklch(19% 0.012 85)` | `#16130E` | `oklch(89% 0.010 85)` | `#DEDAD3` |
|
|
86
|
+
| `s3` | `oklch(24% 0.012 85)` | `#221F19` | `oklch(85% 0.010 85)` | `#D1CDC7` |
|
|
87
|
+
|
|
88
|
+
## Core tokens
|
|
89
|
+
|
|
90
|
+
### Borders
|
|
91
|
+
|
|
92
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
93
|
+
|---|---|---|---|
|
|
94
|
+
| `border.width.1` | `1px` | `var(--juno-border-width-1)` | `JunoTokens.borderWidth1` |
|
|
95
|
+
| `border.width.2` | `2px` | `var(--juno-border-width-2)` | `JunoTokens.borderWidth2` |
|
|
96
|
+
| `border.width.3` | `3px` | `var(--juno-border-width-3)` | `JunoTokens.borderWidth3` |
|
|
97
|
+
|
|
98
|
+
### Breakpoints
|
|
99
|
+
|
|
100
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| `bp.sm` | `640px` | `var(--juno-bp-sm)` | `JunoTokens.bpSm` |
|
|
103
|
+
| `bp.md` | `768px` | `var(--juno-bp-md)` | `JunoTokens.bpMd` |
|
|
104
|
+
| `bp.lg` | `1024px` | `var(--juno-bp-lg)` | `JunoTokens.bpLg` |
|
|
105
|
+
| `bp.xl` | `1280px` | `var(--juno-bp-xl)` | `JunoTokens.bpXl` |
|
|
106
|
+
| `bp.2xl` | `1536px` | `var(--juno-bp-2xl)` | `JunoTokens.bp2xl` |
|
|
107
|
+
|
|
108
|
+
### Elevation
|
|
109
|
+
|
|
110
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
111
|
+
|---|---|---|---|
|
|
112
|
+
| `shadow.1` | `0 1px 2px rgb(0 0 0 / 0.30)` | `var(--juno-shadow-1)` | `JunoTokens.shadow1` |
|
|
113
|
+
| `shadow.2` | `0 4px 14px rgb(0 0 0 / 0.35)` | `var(--juno-shadow-2)` | `JunoTokens.shadow2` |
|
|
114
|
+
| `shadow.3` | `0 12px 32px rgb(0 0 0 / 0.50)` | `var(--juno-shadow-3)` | `JunoTokens.shadow3` |
|
|
115
|
+
|
|
116
|
+
### Motion
|
|
117
|
+
|
|
118
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| `motion.duration.instant` | `80ms` | `var(--juno-motion-duration-instant)` | `JunoTokens.motionDurationInstant` |
|
|
121
|
+
| `motion.duration.quick` | `140ms` | `var(--juno-motion-duration-quick)` | `JunoTokens.motionDurationQuick` |
|
|
122
|
+
| `motion.duration.base` | `200ms` | `var(--juno-motion-duration-base)` | `JunoTokens.motionDurationBase` |
|
|
123
|
+
| `motion.duration.deliberate` | `300ms` | `var(--juno-motion-duration-deliberate)` | `JunoTokens.motionDurationDeliberate` |
|
|
124
|
+
| `motion.ease.decel` | `cubic-bezier(0.2, 0.8, 0.2, 1)` | `var(--juno-motion-ease-decel)` | `JunoTokens.motionEaseDecel` |
|
|
125
|
+
| `motion.ease.accel` | `cubic-bezier(0.4, 0, 1, 1)` | `var(--juno-motion-ease-accel)` | `JunoTokens.motionEaseAccel` |
|
|
126
|
+
| `motion.ease.standard` | `cubic-bezier(0.2, 0.7, 0.3, 1)` | `var(--juno-motion-ease-standard)` | `JunoTokens.motionEaseStandard` |
|
|
127
|
+
| `motion.ease.spring` | `cubic-bezier(0.2, 0.9, 0.3, 1.2)` | `var(--juno-motion-ease-spring)` | `JunoTokens.motionEaseSpring` |
|
|
128
|
+
|
|
129
|
+
### Opacity
|
|
130
|
+
|
|
131
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
132
|
+
|---|---|---|---|
|
|
133
|
+
| `opacity.disabled` | `0.45` | `var(--juno-opacity-disabled)` | `JunoTokens.opacityDisabled` |
|
|
134
|
+
| `opacity.muted` | `0.65` | `var(--juno-opacity-muted)` | `JunoTokens.opacityMuted` |
|
|
135
|
+
| `opacity.scrim` | `0.62` | `var(--juno-opacity-scrim)` | `JunoTokens.opacityScrim` |
|
|
136
|
+
|
|
137
|
+
### Radius
|
|
138
|
+
|
|
139
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
140
|
+
|---|---|---|---|
|
|
141
|
+
| `radius.2` | `2px` | `var(--juno-radius-2)` | `JunoTokens.radius2` |
|
|
142
|
+
| `radius.3` | `3px` | `var(--juno-radius-3)` | `JunoTokens.radius3` |
|
|
143
|
+
| `radius.4` | `4px` | `var(--juno-radius-4)` | `JunoTokens.radius4` |
|
|
144
|
+
| `radius.5` | `5px` | `var(--juno-radius-5)` | `JunoTokens.radius5` |
|
|
145
|
+
| `radius.8` | `8px` | `var(--juno-radius-8)` | `JunoTokens.radius8` |
|
|
146
|
+
|
|
147
|
+
### Sizing
|
|
148
|
+
|
|
149
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
150
|
+
|---|---|---|---|
|
|
151
|
+
| `size.tap.min` | `24px` | `var(--juno-size-tap-min)` | `JunoTokens.sizeTapMin` |
|
|
152
|
+
| `size.tap.comfortable` | `44px` | `var(--juno-size-tap-comfortable)` | `JunoTokens.sizeTapComfortable` |
|
|
153
|
+
| `size.dot.sm` | `8px` | `var(--juno-size-dot-sm)` | `JunoTokens.sizeDotSm` |
|
|
154
|
+
| `size.dot.md` | `10px` | `var(--juno-size-dot-md)` | `JunoTokens.sizeDotMd` |
|
|
155
|
+
|
|
156
|
+
### Spacing
|
|
157
|
+
|
|
158
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
159
|
+
|---|---|---|---|
|
|
160
|
+
| `space.2` | `2px` | `var(--juno-space-2)` | `JunoTokens.space2` |
|
|
161
|
+
| `space.4` | `4px` | `var(--juno-space-4)` | `JunoTokens.space4` |
|
|
162
|
+
| `space.8` | `8px` | `var(--juno-space-8)` | `JunoTokens.space8` |
|
|
163
|
+
| `space.10` | `10px` | `var(--juno-space-10)` | `JunoTokens.space10` |
|
|
164
|
+
| `space.12` | `12px` | `var(--juno-space-12)` | `JunoTokens.space12` |
|
|
165
|
+
| `space.16` | `16px` | `var(--juno-space-16)` | `JunoTokens.space16` |
|
|
166
|
+
| `space.20` | `20px` | `var(--juno-space-20)` | `JunoTokens.space20` |
|
|
167
|
+
| `space.24` | `24px` | `var(--juno-space-24)` | `JunoTokens.space24` |
|
|
168
|
+
| `space.28` | `28px` | `var(--juno-space-28)` | `JunoTokens.space28` |
|
|
169
|
+
| `space.32` | `32px` | `var(--juno-space-32)` | `JunoTokens.space32` |
|
|
170
|
+
| `space.40` | `40px` | `var(--juno-space-40)` | `JunoTokens.space40` |
|
|
171
|
+
| `space.56` | `56px` | `var(--juno-space-56)` | `JunoTokens.space56` |
|
|
172
|
+
| `space.72` | `72px` | `var(--juno-space-72)` | `JunoTokens.space72` |
|
|
173
|
+
| `space.96` | `96px` | `var(--juno-space-96)` | `JunoTokens.space96` |
|
|
174
|
+
|
|
175
|
+
### Typography
|
|
176
|
+
|
|
177
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
178
|
+
|---|---|---|---|
|
|
179
|
+
| `font.family.sans` | `'B612', sans-serif` | `var(--juno-font-family-sans)` | `JunoTokens.fontFamilySans` |
|
|
180
|
+
| `font.family.mono` | `'B612 Mono', monospace` | `var(--juno-font-family-mono)` | `JunoTokens.fontFamilyMono` |
|
|
181
|
+
| `font.weight.light` | `300` | `var(--juno-font-weight-light)` | `JunoTokens.fontWeightLight` |
|
|
182
|
+
| `font.weight.regular` | `400` | `var(--juno-font-weight-regular)` | `JunoTokens.fontWeightRegular` |
|
|
183
|
+
| `font.weight.medium` | `500` | `var(--juno-font-weight-medium)` | `JunoTokens.fontWeightMedium` |
|
|
184
|
+
| `font.weight.semibold` | `600` | `var(--juno-font-weight-semibold)` | `JunoTokens.fontWeightSemibold` |
|
|
185
|
+
| `font.weight.bold` | `700` | `var(--juno-font-weight-bold)` | `JunoTokens.fontWeightBold` |
|
|
186
|
+
| `font.size.10` | `10px` | `var(--juno-font-size-10)` | `JunoTokens.fontSize10` |
|
|
187
|
+
| `font.size.11` | `11px` | `var(--juno-font-size-11)` | `JunoTokens.fontSize11` |
|
|
188
|
+
| `font.size.12` | `12px` | `var(--juno-font-size-12)` | `JunoTokens.fontSize12` |
|
|
189
|
+
| `font.size.13` | `13px` | `var(--juno-font-size-13)` | `JunoTokens.fontSize13` |
|
|
190
|
+
| `font.size.14` | `14px` | `var(--juno-font-size-14)` | `JunoTokens.fontSize14` |
|
|
191
|
+
| `font.size.16` | `16px` | `var(--juno-font-size-16)` | `JunoTokens.fontSize16` |
|
|
192
|
+
| `font.size.18` | `18px` | `var(--juno-font-size-18)` | `JunoTokens.fontSize18` |
|
|
193
|
+
| `font.size.20` | `20px` | `var(--juno-font-size-20)` | `JunoTokens.fontSize20` |
|
|
194
|
+
| `font.size.28` | `28px` | `var(--juno-font-size-28)` | `JunoTokens.fontSize28` |
|
|
195
|
+
| `font.size.32` | `32px` | `var(--juno-font-size-32)` | `JunoTokens.fontSize32` |
|
|
196
|
+
| `font.size.36` | `36px` | `var(--juno-font-size-36)` | `JunoTokens.fontSize36` |
|
|
197
|
+
| `font.size.38` | `38px` | `var(--juno-font-size-38)` | `JunoTokens.fontSize38` |
|
|
198
|
+
| `font.size.48` | `48px` | `var(--juno-font-size-48)` | `JunoTokens.fontSize48` |
|
|
199
|
+
| `font.size.52` | `52px` | `var(--juno-font-size-52)` | `JunoTokens.fontSize52` |
|
|
200
|
+
| `font.lineHeight.none` | `1` | `var(--juno-font-lineHeight-none)` | `JunoTokens.fontLineHeightNone` |
|
|
201
|
+
| `font.lineHeight.tight` | `1.1` | `var(--juno-font-lineHeight-tight)` | `JunoTokens.fontLineHeightTight` |
|
|
202
|
+
| `font.lineHeight.snug` | `1.2` | `var(--juno-font-lineHeight-snug)` | `JunoTokens.fontLineHeightSnug` |
|
|
203
|
+
| `font.lineHeight.normal` | `1.4` | `var(--juno-font-lineHeight-normal)` | `JunoTokens.fontLineHeightNormal` |
|
|
204
|
+
| `font.lineHeight.relaxed` | `1.5` | `var(--juno-font-lineHeight-relaxed)` | `JunoTokens.fontLineHeightRelaxed` |
|
|
205
|
+
| `font.lineHeight.loose` | `1.7` | `var(--juno-font-lineHeight-loose)` | `JunoTokens.fontLineHeightLoose` |
|
|
206
|
+
| `font.tracking.tight` | `0.02em` | `var(--juno-font-tracking-tight)` | `JunoTokens.fontTrackingTight` |
|
|
207
|
+
| `font.tracking.normal` | `0.06em` | `var(--juno-font-tracking-normal)` | `JunoTokens.fontTrackingNormal` |
|
|
208
|
+
| `font.tracking.label` | `0.08em` | `var(--juno-font-tracking-label)` | `JunoTokens.fontTrackingLabel` |
|
|
209
|
+
| `font.tracking.wide` | `0.12em` | `var(--juno-font-tracking-wide)` | `JunoTokens.fontTrackingWide` |
|
|
210
|
+
| `font.tracking.caps` | `0.15em` | `var(--juno-font-tracking-caps)` | `JunoTokens.fontTrackingCaps` |
|
|
211
|
+
| `font.tracking.wider` | `0.2em` | `var(--juno-font-tracking-wider)` | `JunoTokens.fontTrackingWider` |
|
|
212
|
+
| `font.tracking.widest` | `0.3em` | `var(--juno-font-tracking-widest)` | `JunoTokens.fontTrackingWidest` |
|
|
213
|
+
|
|
214
|
+
### Z-index
|
|
215
|
+
|
|
216
|
+
| Token | Value | CSS variable | Flutter / iOS |
|
|
217
|
+
|---|---|---|---|
|
|
218
|
+
| `z.surface` | `0` | `var(--juno-z-surface)` | `JunoTokens.zSurface` |
|
|
219
|
+
| `z.raised` | `100` | `var(--juno-z-raised)` | `JunoTokens.zRaised` |
|
|
220
|
+
| `z.anchored` | `2000` | `var(--juno-z-anchored)` | `JunoTokens.zAnchored` |
|
|
221
|
+
| `z.overlay` | `4000` | `var(--juno-z-overlay)` | `JunoTokens.zOverlay` |
|
|
222
|
+
| `z.alert` | `5000` | `var(--juno-z-alert)` | `JunoTokens.zAlert` |
|
|
223
|
+
|