@oneli8/react 1.0.0-beta.5 → 1.0.0-beta.6
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/README.md +7 -3
- package/ai-context.json +116 -1
- package/package.json +2 -2
- package/src/atoms/NavigationBadge.js +19 -0
- package/src/foundations/geometry.js +71 -0
- package/src/index.d.ts +214 -0
- package/src/index.js +14 -0
- package/src/molecules/ChoiceChip.js +101 -0
- package/src/molecules/FormMessage.js +33 -0
- package/src/molecules/Link.js +31 -0
- package/src/molecules/NavigationItem.js +55 -0
- package/src/molecules/Select.js +109 -0
- package/src/molecules/SelectionOption.js +4 -1
- package/src/molecules/TextField.js +174 -0
- package/src/molecules/Token.js +49 -0
- package/src/organisms/ChoicePicker.js +114 -0
- package/src/organisms/Combobox.js +122 -0
- package/src/organisms/MultiSelectField.js +138 -0
- package/src/organisms/SegmentedControl.js +114 -0
- package/src/organisms/SelectionPopup.js +73 -0
- package/src/organisms/TabBar.js +68 -0
- package/src/organisms/Tabs.js +123 -0
- package/src/styles/choice-chip.css +216 -0
- package/src/styles/choice-picker.css +100 -0
- package/src/styles/combobox.css +42 -0
- package/src/styles/form-message.css +48 -0
- package/src/styles/gem.css +52 -5
- package/src/styles/link.css +116 -0
- package/src/styles/multi-select-field.css +78 -0
- package/src/styles/navigation-badge.css +37 -0
- package/src/styles/navigation-item.css +155 -0
- package/src/styles/segmented-control.css +115 -0
- package/src/styles/select.css +33 -0
- package/src/styles/selection-indicator.css +13 -4
- package/src/styles/selection-popup.css +92 -0
- package/src/styles/tab-bar.css +47 -0
- package/src/styles/tabs.css +55 -0
- package/src/styles/text-field.css +268 -0
- package/src/styles/token.css +65 -0
- package/styles.css +18 -2
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/organisms/multi-select-field/multi-select-field.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Multi-select Field (ORGANISM)
|
|
5
|
+
* Figma: Organism / Multi-select Field / Outline 904:2507 (16 variants)
|
|
6
|
+
* Organism / Multi-select Field / Filled 978:4472 (16 variants)
|
|
7
|
+
*
|
|
8
|
+
* Almost everything here is inherited rather than declared. The field shell,
|
|
9
|
+
* its four sizes, both appearances, the Gem material and the focus treatment
|
|
10
|
+
* all come from the Text Field stylesheet, because Figma builds this organism
|
|
11
|
+
* from the canonical Text Field owner and only swaps that owner between the
|
|
12
|
+
* Outline and Filled sets. What is left is the one thing a Text Field has never
|
|
13
|
+
* had to do: let committed values and the editable input share a run that
|
|
14
|
+
* wraps.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/* Figma's root is a vertical stack: the field composition, then the popup,
|
|
18
|
+
twelve apart. That gap is now bound in Figma to Spacing / Stack / Related. */
|
|
19
|
+
.ol8-multiselect {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: var(--ol8-spacing-stack-related);
|
|
23
|
+
inline-size: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* A Text Field pins this stack to one row's height, because a single line
|
|
27
|
+
input never needs more. A multi value field does: releasing the stack is what
|
|
28
|
+
lets the control below it grow, and without it the tokens simply spill out of
|
|
29
|
+
the boundary they are supposed to sit inside. */
|
|
30
|
+
.ol8-multiselect__field > .ol8-field__control-stack {
|
|
31
|
+
block-size: auto;
|
|
32
|
+
min-block-size: var(--_height);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* The control grows instead of scrolling or shrinking its contents. The
|
|
36
|
+
contract is explicit: the field "starts at its approved Text Field minimum
|
|
37
|
+
height and grows in 6px or 12px-aligned increments as tokens wrap" and "never
|
|
38
|
+
compresses tokens to preserve one nominal row". Every token keeps its own
|
|
39
|
+
protected 48 unit interaction line, so a populated row is taller than an
|
|
40
|
+
empty field by design. */
|
|
41
|
+
.ol8-multiselect__control {
|
|
42
|
+
flex-wrap: wrap;
|
|
43
|
+
align-content: center;
|
|
44
|
+
block-size: auto;
|
|
45
|
+
min-block-size: var(--_height);
|
|
46
|
+
gap: var(--ol8-component-token-field-gap);
|
|
47
|
+
padding-block: var(--ol8-component-token-field-padding-block);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* The editable input keeps a usable measure before it gives up its row. */
|
|
51
|
+
.ol8-multiselect__input {
|
|
52
|
+
min-inline-size: var(--ol8-component-token-field-minimum-input);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* A token awaiting a second Backspace. The first press only activates, so this
|
|
56
|
+
has to be visible: a silent activation would make the second press feel like
|
|
57
|
+
a single key deleting a value. */
|
|
58
|
+
.ol8-multiselect__token[data-ol8-active] {
|
|
59
|
+
--_surface: var(--ol8-color-selection-surface);
|
|
60
|
+
--_edge: var(--ol8-color-focus-outer);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* A read only field's values are labelled content, so nothing inside invites a
|
|
64
|
+
click that would do nothing. */
|
|
65
|
+
.ol8-multiselect[data-ol8-readonly="true"] .ol8-multiselect__token,
|
|
66
|
+
.ol8-multiselect[data-ol8-availability="disabled"] .ol8-multiselect__token {
|
|
67
|
+
cursor: default;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Announcements only. Removing a value says so, with the remaining count. */
|
|
71
|
+
.ol8-multiselect__status {
|
|
72
|
+
position: absolute;
|
|
73
|
+
inline-size: 1px;
|
|
74
|
+
block-size: 1px;
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
clip-path: inset(50%);
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/atoms/navigation-badge/navigation-badge.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Navigation Badge (ATOM)
|
|
5
|
+
* Figma: Atom / Navigation Badge 989:484 — a full radius pill at the standard
|
|
6
|
+
* indicator height, padded by the related inline step, whose surface and
|
|
7
|
+
* content are the only things that change when the item is selected or gem.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.ol8-nav-badge {
|
|
11
|
+
display: inline-flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
block-size: var(--ol8-size-indicator-standard);
|
|
15
|
+
padding-inline: var(--ol8-spacing-inline-related);
|
|
16
|
+
border-radius: var(--ol8-shape-radius-full);
|
|
17
|
+
background: var(--ol8-color-navigation-badge-surface-default);
|
|
18
|
+
color: var(--ol8-color-navigation-badge-content-default);
|
|
19
|
+
font-family: var(--ol8-font-family-functional);
|
|
20
|
+
font-size: var(--ol8-font-size-012);
|
|
21
|
+
font-weight: var(--ol8-font-weight-semibold);
|
|
22
|
+
line-height: var(--ol8-font-line-018);
|
|
23
|
+
font-variant-numeric: tabular-nums;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Selection and material reach the badge through the item that owns it. */
|
|
27
|
+
[data-ol8-selected="true"] > * > .ol8-nav-badge,
|
|
28
|
+
[aria-selected="true"] > * > .ol8-nav-badge,
|
|
29
|
+
[aria-current] > * > .ol8-nav-badge {
|
|
30
|
+
background: var(--ol8-color-navigation-badge-surface-selected);
|
|
31
|
+
color: var(--ol8-color-navigation-badge-content-selected);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
[data-ol8-material="gem"] .ol8-nav-badge {
|
|
35
|
+
background: var(--ol8-color-navigation-badge-surface-gem);
|
|
36
|
+
color: var(--ol8-color-navigation-badge-content-gem);
|
|
37
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/molecules/navigation-item/navigation-item.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Navigation Item (MOLECULE, internal)
|
|
5
|
+
* Figma: Tab Item 688:51, Segment Item 695:167, Destination Item 700:292.
|
|
6
|
+
*
|
|
7
|
+
* All three are one molecule. Read from Figma: a box at the size's control
|
|
8
|
+
* height with centred content, a horizontal content row at the canonical
|
|
9
|
+
* navigation gap, an eighteen unit icon, a Semibold label at the size's reading
|
|
10
|
+
* step, and an optional badge. States are identical across the three:
|
|
11
|
+
*
|
|
12
|
+
* Hover Action Quiet Surface Hover + Action Quiet Content Hover
|
|
13
|
+
* Pressed Action Quiet Surface Pressed + Action Quiet Content Pressed
|
|
14
|
+
* Focus an inward Focus Inner edge, so a parent cannot crop it
|
|
15
|
+
* Disabled Text Disabled, no surface
|
|
16
|
+
*
|
|
17
|
+
* Only the selection language differs. Tab Item raises an indicator bar in the
|
|
18
|
+
* primary colour, inset by the governed amount. Segment Item and Destination
|
|
19
|
+
* Item take the selection surface and content instead.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
.ol8-nav-item {
|
|
23
|
+
position: relative;
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
block-size: var(--_height);
|
|
29
|
+
border: 0;
|
|
30
|
+
border-radius: var(--_radius);
|
|
31
|
+
padding-inline: var(--_inset);
|
|
32
|
+
background: transparent;
|
|
33
|
+
color: var(--ol8-color-text-secondary);
|
|
34
|
+
font-family: var(--ol8-font-family-functional);
|
|
35
|
+
font-weight: var(--ol8-font-weight-semibold);
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
transition-property: background-color, color;
|
|
39
|
+
transition-duration: var(--ol8-motion-interaction-hover-duration);
|
|
40
|
+
transition-timing-function: var(--ol8-motion-interaction-hover-timing-function);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ol8-nav-item__content {
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(--ol8-component-navigation-item-gap);
|
|
47
|
+
min-inline-size: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* "Labels do not wrap." A narrow list scrolls; it never grows a second line. */
|
|
51
|
+
.ol8-nav-item__label {
|
|
52
|
+
white-space: nowrap;
|
|
53
|
+
font-size: var(--_label-size);
|
|
54
|
+
line-height: var(--_label-line);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.ol8-nav-item__icon { flex: none; }
|
|
58
|
+
|
|
59
|
+
.ol8-nav-item[data-ol8-layout="stacked"] .ol8-nav-item__content {
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
gap: 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ---- Size ------------------------------------------------------------- */
|
|
65
|
+
.ol8-nav-item[data-ol8-size="compact"] {
|
|
66
|
+
--_height: var(--ol8-component-tab-item-height-compact);
|
|
67
|
+
--_inset: var(--ol8-component-tab-item-inset-compact);
|
|
68
|
+
--_label-size: var(--ol8-font-size-012);
|
|
69
|
+
--_label-line: var(--ol8-font-line-018);
|
|
70
|
+
}
|
|
71
|
+
.ol8-nav-item[data-ol8-size="standard"] {
|
|
72
|
+
--_height: var(--ol8-component-tab-item-height-standard);
|
|
73
|
+
--_inset: var(--ol8-component-tab-item-inset-standard);
|
|
74
|
+
--_label-size: var(--ol8-font-size-016);
|
|
75
|
+
--_label-line: var(--ol8-font-line-024);
|
|
76
|
+
}
|
|
77
|
+
.ol8-nav-item[data-ol8-size="comfortable"] {
|
|
78
|
+
--_height: var(--ol8-component-tab-item-height-comfortable);
|
|
79
|
+
--_inset: var(--ol8-component-tab-item-inset-comfortable);
|
|
80
|
+
--_label-size: var(--ol8-font-size-016);
|
|
81
|
+
--_label-line: var(--ol8-font-line-024);
|
|
82
|
+
}
|
|
83
|
+
.ol8-nav-item[data-ol8-size="large"] {
|
|
84
|
+
--_height: var(--ol8-component-tab-item-height-large);
|
|
85
|
+
--_inset: var(--ol8-component-tab-item-inset-large);
|
|
86
|
+
--_label-size: var(--ol8-font-size-021);
|
|
87
|
+
--_label-line: var(--ol8-font-line-030);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.ol8-nav-item--tab,
|
|
91
|
+
.ol8-nav-item--segment { --_radius: var(--ol8-component-tab-item-radius); }
|
|
92
|
+
.ol8-nav-item--destination { --_radius: var(--ol8-component-tab-bar-item-radius); }
|
|
93
|
+
|
|
94
|
+
/* ---- State ------------------------------------------------------------ */
|
|
95
|
+
@media (hover: hover) and (pointer: fine) {
|
|
96
|
+
.ol8-nav-item:hover:not(:disabled) {
|
|
97
|
+
background: var(--ol8-color-actionquiet-surfacehover);
|
|
98
|
+
color: var(--ol8-color-actionquiet-contenthover);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
.ol8-nav-item:active:not(:disabled) {
|
|
102
|
+
background: var(--ol8-color-actionquiet-surfacepressed);
|
|
103
|
+
color: var(--ol8-color-actionquiet-contentpressed);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* "Focus uses the approved inward treatment so parent clipping cannot crop it."
|
|
107
|
+
An outward ring would be cut by a scrolling tab list. */
|
|
108
|
+
.ol8-nav-item:focus-visible {
|
|
109
|
+
outline: none;
|
|
110
|
+
box-shadow: inset 0 0 0 var(--ol8-component-navigation-focus-inset) var(--ol8-color-focus-inner);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.ol8-nav-item:disabled {
|
|
114
|
+
color: var(--ol8-color-text-disabled);
|
|
115
|
+
background: transparent;
|
|
116
|
+
cursor: not-allowed;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* ---- Selection · Tab Item raises an indicator ------------------------- */
|
|
120
|
+
.ol8-nav-item__indicator {
|
|
121
|
+
position: absolute;
|
|
122
|
+
inset-block-end: 0;
|
|
123
|
+
inset-inline: var(--ol8-component-tab-item-indicator-inset);
|
|
124
|
+
block-size: var(--ol8-component-tab-item-indicator-thickness);
|
|
125
|
+
border-radius: var(--ol8-shape-radius-full);
|
|
126
|
+
background: transparent;
|
|
127
|
+
}
|
|
128
|
+
.ol8-nav-item--tab[aria-selected="true"] {
|
|
129
|
+
color: var(--ol8-color-actionprimary-default);
|
|
130
|
+
}
|
|
131
|
+
.ol8-nav-item--tab[aria-selected="true"] > .ol8-nav-item__indicator {
|
|
132
|
+
background: var(--ol8-color-actionprimary-default);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* ---- Selection · Segment and Destination take the surface ------------- */
|
|
136
|
+
.ol8-nav-item--segment[aria-pressed="true"],
|
|
137
|
+
.ol8-nav-item--destination[aria-current] {
|
|
138
|
+
background: var(--ol8-color-selection-surface);
|
|
139
|
+
color: var(--ol8-color-selection-content);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@media (prefers-reduced-motion: reduce) {
|
|
143
|
+
.ol8-nav-item { transition-duration: var(--ol8-motion-duration-instant); }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@media (forced-colors: active) {
|
|
147
|
+
.ol8-nav-item:focus-visible {
|
|
148
|
+
outline: var(--ol8-component-navigation-focus-inset) solid Highlight;
|
|
149
|
+
outline-offset: calc(var(--ol8-component-navigation-focus-inset) * -1);
|
|
150
|
+
box-shadow: none;
|
|
151
|
+
}
|
|
152
|
+
.ol8-nav-item--tab[aria-selected="true"] > .ol8-nav-item__indicator { background: Highlight; }
|
|
153
|
+
.ol8-nav-item--segment[aria-pressed="true"],
|
|
154
|
+
.ol8-nav-item--destination[aria-current] { background: Highlight; color: HighlightText; }
|
|
155
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/organisms/segmented-control/segmented-control.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Segmented Control (ORGANISM)
|
|
5
|
+
* Figma: Navigation / Segmented Control 698:4792 — six presentations.
|
|
6
|
+
*
|
|
7
|
+
* "Presentation never changes behavior." Every presentation below is a
|
|
8
|
+
* treatment of the same Segment molecule, and none of them touches which
|
|
9
|
+
* behaviour the consumer declared.
|
|
10
|
+
*
|
|
11
|
+
* Read from Figma at Standard, Regular:
|
|
12
|
+
* Inset Fill sunken track, Border Default at the standard boundary,
|
|
13
|
+
* segments inset by the track inset, selected takes the
|
|
14
|
+
* selection surface
|
|
15
|
+
* Line Indicator no track; an adaptive secondary rail with a separate
|
|
16
|
+
* indicator in the primary colour, inset like a tab
|
|
17
|
+
* Outlined Selection no track; each segment carries its own boundary, the
|
|
18
|
+
* selected one in the primary colour at the strong width,
|
|
19
|
+
* with a deliberate gap between segments
|
|
20
|
+
* Soft Pill raised track at full radius; segments at full radius
|
|
21
|
+
* Icon-only the Inset Fill track, with icon only segments
|
|
22
|
+
* Stacked Label no track; segments stack their icon over their label
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
.ol8-segmented {
|
|
26
|
+
display: inline-flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
box-sizing: border-box;
|
|
29
|
+
gap: var(--ol8-component-tab-bar-gap);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.ol8-segmented > .ol8-nav-item { flex: 1 1 0; }
|
|
33
|
+
|
|
34
|
+
/* ---- Inset Fill and Icon-only share one track ------------------------- */
|
|
35
|
+
.ol8-segmented[data-ol8-presentation="inset-fill"],
|
|
36
|
+
.ol8-segmented[data-ol8-presentation="icon-only"] {
|
|
37
|
+
padding: var(--ol8-component-segmented-control-track-inset);
|
|
38
|
+
border: var(--ol8-border-width-standard) solid var(--ol8-color-border-default);
|
|
39
|
+
border-radius: var(--ol8-component-segmented-control-track-radius);
|
|
40
|
+
background: var(--ol8-color-surface-sunken);
|
|
41
|
+
}
|
|
42
|
+
.ol8-segmented[data-ol8-presentation="inset-fill"] > .ol8-nav-item,
|
|
43
|
+
.ol8-segmented[data-ol8-presentation="icon-only"] > .ol8-nav-item {
|
|
44
|
+
--_radius: var(--ol8-component-segmented-control-item-radius);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* ---- Soft Pill -------------------------------------------------------- */
|
|
48
|
+
.ol8-segmented[data-ol8-presentation="soft-pill"] {
|
|
49
|
+
padding: var(--ol8-component-segmented-control-track-inset);
|
|
50
|
+
border-radius: var(--ol8-shape-radius-full);
|
|
51
|
+
background: var(--ol8-color-surface-raised);
|
|
52
|
+
}
|
|
53
|
+
.ol8-segmented[data-ol8-presentation="soft-pill"] > .ol8-nav-item {
|
|
54
|
+
--_radius: var(--ol8-shape-radius-full);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* ---- Line Indicator --------------------------------------------------- */
|
|
58
|
+
.ol8-segmented[data-ol8-presentation="line-indicator"] {
|
|
59
|
+
position: relative;
|
|
60
|
+
gap: 0;
|
|
61
|
+
}
|
|
62
|
+
.ol8-segmented[data-ol8-presentation="line-indicator"]::after {
|
|
63
|
+
content: "";
|
|
64
|
+
position: absolute;
|
|
65
|
+
inset-block-end: 0;
|
|
66
|
+
inset-inline: 0;
|
|
67
|
+
block-size: var(--ol8-component-tab-item-rail);
|
|
68
|
+
background: var(--ol8-color-text-secondary);
|
|
69
|
+
}
|
|
70
|
+
/* The active segment raises the line itself, so the indicator travels with the
|
|
71
|
+
selection rather than being positioned by script. */
|
|
72
|
+
.ol8-segmented[data-ol8-presentation="line-indicator"] > .ol8-nav-item { --_radius: 0; }
|
|
73
|
+
.ol8-segmented[data-ol8-presentation="line-indicator"] > .ol8-nav-item::after {
|
|
74
|
+
content: "";
|
|
75
|
+
position: absolute;
|
|
76
|
+
z-index: 1;
|
|
77
|
+
inset-block-end: 0;
|
|
78
|
+
inset-inline: var(--ol8-component-tab-item-indicator-inset);
|
|
79
|
+
block-size: var(--ol8-component-segmented-control-line);
|
|
80
|
+
border-radius: var(--ol8-shape-radius-full);
|
|
81
|
+
background: transparent;
|
|
82
|
+
}
|
|
83
|
+
.ol8-segmented[data-ol8-presentation="line-indicator"] > .ol8-nav-item[aria-pressed="true"] {
|
|
84
|
+
background: transparent;
|
|
85
|
+
color: var(--ol8-color-actionprimary-default);
|
|
86
|
+
}
|
|
87
|
+
.ol8-segmented[data-ol8-presentation="line-indicator"] > .ol8-nav-item[aria-pressed="true"]::after {
|
|
88
|
+
background: var(--ol8-color-actionprimary-default);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ---- Outlined Selection ----------------------------------------------- */
|
|
92
|
+
.ol8-segmented[data-ol8-presentation="outlined-selection"] {
|
|
93
|
+
gap: var(--ol8-component-segmented-control-outlined-gap);
|
|
94
|
+
}
|
|
95
|
+
.ol8-segmented[data-ol8-presentation="outlined-selection"] > .ol8-nav-item {
|
|
96
|
+
--_radius: var(--ol8-component-segmented-control-item-radius);
|
|
97
|
+
border: var(--ol8-component-segmented-control-boundary) solid var(--ol8-color-border-default);
|
|
98
|
+
}
|
|
99
|
+
.ol8-segmented[data-ol8-presentation="outlined-selection"] > .ol8-nav-item[aria-pressed="true"] {
|
|
100
|
+
border-width: var(--ol8-border-width-standard);
|
|
101
|
+
border-color: var(--ol8-color-actionprimary-default);
|
|
102
|
+
background: transparent;
|
|
103
|
+
color: var(--ol8-color-actionprimary-default);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* ---- Stacked Label ---------------------------------------------------- */
|
|
107
|
+
.ol8-segmented[data-ol8-presentation="stacked-label"] > .ol8-nav-item {
|
|
108
|
+
--_radius: var(--ol8-component-segmented-control-item-radius);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@media (forced-colors: active) {
|
|
112
|
+
.ol8-segmented[data-ol8-presentation="line-indicator"] > .ol8-nav-item[aria-pressed="true"]::after {
|
|
113
|
+
background: Highlight;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/molecules/select/select.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Select (MOLECULE)
|
|
5
|
+
* Figma: Select / Trigger 583:338, Molecule / Select 875:1778.
|
|
6
|
+
*
|
|
7
|
+
* "Geometry and appearance reuse approved Text Field tokens", and Figma proves
|
|
8
|
+
* it: every bound variable on the trigger control is a Text Field one. So
|
|
9
|
+
* Select carries the field classes and adds only what a native select needs,
|
|
10
|
+
* which is the disclosure mark and the removal of the platform's own arrow.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
.ol8-select__input {
|
|
14
|
+
appearance: none;
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
}
|
|
17
|
+
.ol8-select__input:disabled { cursor: not-allowed; }
|
|
18
|
+
|
|
19
|
+
/* The native control keeps its own text colour rules, so the value takes the
|
|
20
|
+
primary ink while an unselected placeholder option stays secondary. */
|
|
21
|
+
.ol8-select__input:has(option[value=""]:checked) { color: var(--ol8-color-text-secondary); }
|
|
22
|
+
|
|
23
|
+
.ol8-select__disclosure {
|
|
24
|
+
flex: none;
|
|
25
|
+
color: var(--ol8-color-icon-secondary);
|
|
26
|
+
pointer-events: none;
|
|
27
|
+
}
|
|
28
|
+
.ol8-select[data-ol8-disabled] .ol8-select__disclosure { color: var(--ol8-color-icon-disabled); }
|
|
29
|
+
|
|
30
|
+
/* The disclosure sits over the control, so a click anywhere still reaches the
|
|
31
|
+
native select underneath and opens the platform picker. */
|
|
32
|
+
.ol8-select .ol8-field__control { position: relative; }
|
|
33
|
+
.ol8-select__input { flex: 1 1 auto; min-inline-size: 0; }
|
|
@@ -73,12 +73,21 @@
|
|
|
73
73
|
--_ink: var(--ol8-color-icon-disabled);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
/* The check glyph
|
|
77
|
-
|
|
76
|
+
/* The check glyph does NOT scale with the box, for the same reason the Mixed
|
|
77
|
+
bar below does not. Figma's `Icon / Selection / Check` is a governed two size
|
|
78
|
+
master rather than an Icon Frame instance: Size=Small (18) and Size=Standard
|
|
79
|
+
(24) both carry the same 10.2 x 6.9 artwork at the same 1.8 stroke, centred
|
|
80
|
+
in their box. So the source keeps its 24 unit box at both sizes and the
|
|
81
|
+
smaller box simply lets the empty margin overflow. The artwork is well
|
|
82
|
+
inside 18, so nothing is clipped.
|
|
83
|
+
|
|
84
|
+
This previously scaled with the box, which drew the compact check a quarter
|
|
85
|
+
smaller than Figma at a 1.35 stroke, off the 1.8 system. */
|
|
78
86
|
.ol8-selection--checkbox > .ol8-selection__mark > svg {
|
|
79
87
|
display: block;
|
|
80
|
-
inline-size: var(--
|
|
81
|
-
block-size: var(--
|
|
88
|
+
inline-size: var(--ol8-size-icon-standard);
|
|
89
|
+
block-size: var(--ol8-size-icon-standard);
|
|
90
|
+
overflow: visible;
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
/* The Mixed bar does NOT scale. Both the 18px and 24px masters carry the same
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/organisms/selection-popup/selection-popup.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Selection Popup (ORGANISM)
|
|
5
|
+
* Figma: Building Blocks / Selection Popup 574:534 — Width, Size.
|
|
6
|
+
*
|
|
7
|
+
* The rail is a div with role="listbox" rather than a list element, because a
|
|
8
|
+
* list carries a user agent margin that a component may not zero here, and the
|
|
9
|
+
* role already carries every semantic the list element would have added.
|
|
10
|
+
*
|
|
11
|
+
* Read from Figma: a raised floating surface at the standard radius with a
|
|
12
|
+
* default border, padded by the minimal step inline and the related step
|
|
13
|
+
* block, holding one Option Rail. "Width and Size govern layout only; content
|
|
14
|
+
* must be canonical Selection Option instances."
|
|
15
|
+
*
|
|
16
|
+
* The maximum block is a suggestion, not a cage: the region scrolls rather than
|
|
17
|
+
* clipping, because an option a person cannot reach is an option that does not
|
|
18
|
+
* exist.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
.ol8-popup {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
padding-block: var(--ol8-component-selectionpopup-paddingblock);
|
|
24
|
+
padding-inline: var(--ol8-component-selectionpopup-paddinginline);
|
|
25
|
+
border: var(--ol8-border-width-hairline) solid var(--ol8-color-border-default);
|
|
26
|
+
border-radius: var(--ol8-shape-radius-standard);
|
|
27
|
+
background: var(--ol8-color-surface-raised);
|
|
28
|
+
box-shadow: var(--ol8-elevation-surface-floating);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.ol8-popup__rail {
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
gap: var(--ol8-component-selectionpopup-gap);
|
|
35
|
+
padding-inline: var(--ol8-component-selectionpopup-railinsetinline);
|
|
36
|
+
overflow-y: auto;
|
|
37
|
+
overscroll-behavior: contain;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* ---- Size ------------------------------------------------------------- */
|
|
41
|
+
.ol8-popup[data-ol8-size="standard"] .ol8-popup__rail {
|
|
42
|
+
max-block-size: var(--ol8-component-selectionpopup-maximumblock-standard);
|
|
43
|
+
}
|
|
44
|
+
.ol8-popup[data-ol8-size="large"] .ol8-popup__rail {
|
|
45
|
+
max-block-size: var(--ol8-component-selectionpopup-maximumblock-large);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* ---- Width · layout only, never meaning -------------------------------
|
|
49
|
+
Content hugs, Anchor matches the control it belongs to, and Wide may exceed
|
|
50
|
+
it when the options are longer than the field. */
|
|
51
|
+
.ol8-popup[data-ol8-width="content"] { inline-size: max-content; }
|
|
52
|
+
.ol8-popup[data-ol8-width="anchor"] { inline-size: 100%; }
|
|
53
|
+
.ol8-popup[data-ol8-width="wide"] { inline-size: max-content; min-inline-size: 100%; }
|
|
54
|
+
|
|
55
|
+
/* ---- Group labels ------------------------------------------------------ */
|
|
56
|
+
.ol8-popup__group-label {
|
|
57
|
+
padding-block: var(--ol8-component-selectionpopup-gap);
|
|
58
|
+
padding-inline: var(--ol8-component-selectionoption-inset-standard);
|
|
59
|
+
color: var(--ol8-color-text-secondary);
|
|
60
|
+
font-family: var(--ol8-font-family-functional);
|
|
61
|
+
font-size: var(--ol8-font-size-012);
|
|
62
|
+
font-weight: var(--ol8-font-weight-semibold);
|
|
63
|
+
line-height: var(--ol8-font-line-018);
|
|
64
|
+
letter-spacing: var(--ol8-font-tracking-open);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ---- Status ------------------------------------------------------------
|
|
68
|
+
"No results is never represented by a selectable option", so a status is a
|
|
69
|
+
plain region, never an option, and it can never be chosen by mistake. */
|
|
70
|
+
.ol8-popup__status {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
gap: var(--ol8-component-textfield-gap-status);
|
|
74
|
+
padding-block: var(--ol8-component-selectionpopup-paddingblock);
|
|
75
|
+
padding-inline: var(--ol8-component-selectionoption-inset-standard);
|
|
76
|
+
color: var(--ol8-color-text-secondary);
|
|
77
|
+
font-family: var(--ol8-font-family-functional);
|
|
78
|
+
font-size: var(--ol8-font-size-012);
|
|
79
|
+
font-weight: var(--ol8-font-weight-regular);
|
|
80
|
+
line-height: var(--ol8-font-line-018);
|
|
81
|
+
}
|
|
82
|
+
.ol8-popup__status[data-ol8-status="error"] { color: var(--ol8-color-feedbackcritical-inlinecontent); }
|
|
83
|
+
|
|
84
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
85
|
+
.ol8-popup__status[data-ol8-status="loading"] .ol8-icon > svg {
|
|
86
|
+
animation: ol8-spin 900ms linear infinite;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@media (forced-colors: active) {
|
|
91
|
+
.ol8-popup { border-color: CanvasText; box-shadow: none; }
|
|
92
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/organisms/tab-bar/tab-bar.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Tab Bar (ORGANISM)
|
|
5
|
+
* Figma: Navigation / Tab Bar 701:460 — Bottom, Inline, Sidebar, Spatial Rail.
|
|
6
|
+
*
|
|
7
|
+
* "Tab Bar contains destinations, never a central action disguised as a
|
|
8
|
+
* destination." Every presentation below keeps the same route identity and the
|
|
9
|
+
* same current destination; only the container changes.
|
|
10
|
+
*
|
|
11
|
+
* Read from Figma at Standard, Regular: Bottom, Sidebar and Spatial Rail all
|
|
12
|
+
* sit on a raised surface with a subtle border at the tab bar radius, protected
|
|
13
|
+
* by the tab bar inset. Inline has no surface and no border, and uses the
|
|
14
|
+
* tighter inline inset on its horizontal edges. Destinations meet with no gap.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
.ol8-tab-bar {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: stretch;
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
gap: var(--ol8-component-tab-bar-gap);
|
|
22
|
+
padding: var(--ol8-component-tab-bar-inset);
|
|
23
|
+
border: var(--ol8-border-width-hairline) solid var(--ol8-color-border-subtle);
|
|
24
|
+
border-radius: var(--ol8-component-tab-bar-radius);
|
|
25
|
+
background: var(--ol8-color-surface-raised);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ol8-tab-bar > .ol8-nav-item { flex: 1 1 0; }
|
|
29
|
+
|
|
30
|
+
/* Inline sits in the page rather than on it, so it drops the surface, the
|
|
31
|
+
border and the radius, and protects only its horizontal edges. */
|
|
32
|
+
.ol8-tab-bar[data-ol8-presentation="inline"] {
|
|
33
|
+
padding-block: var(--ol8-component-tab-bar-inset);
|
|
34
|
+
padding-inline: var(--ol8-component-tab-bar-inline-inset);
|
|
35
|
+
border: 0;
|
|
36
|
+
border-radius: var(--ol8-shape-radius-none);
|
|
37
|
+
background: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ol8-tab-bar[data-ol8-presentation="sidebar"],
|
|
41
|
+
.ol8-tab-bar[data-ol8-presentation="spatial-rail"] {
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
align-items: stretch;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* The spatial rail carries no labels, so its destinations are square targets. */
|
|
47
|
+
.ol8-tab-bar[data-ol8-presentation="spatial-rail"] > .ol8-nav-item { flex: none; }
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* GENERATED from packages/core/src/organisms/tabs/tabs.css by packages/sync/src/build-styles.mjs — do not edit.
|
|
2
|
+
Edit the source in packages/core/src and re-run `npm run sync:styles`. */
|
|
3
|
+
/**
|
|
4
|
+
* Oneli8 · Tabs (ORGANISM)
|
|
5
|
+
* Figma: Navigation / Tabs 693:171 — Hierarchy, Material, Size.
|
|
6
|
+
*
|
|
7
|
+
* The organism owns sibling separation and the rail; the item owns its own
|
|
8
|
+
* inset. Read from Figma: tabs meet with no gap, and a Primary tab list carries
|
|
9
|
+
* an adaptive secondary rail behind them at the hairline thickness in the
|
|
10
|
+
* secondary text colour. Secondary and Tertiary carry no rail.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
.ol8-tabs {
|
|
14
|
+
position: relative;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: stretch;
|
|
17
|
+
/* "Narrow Tab lists scroll or use an explicitly governed overflow policy;
|
|
18
|
+
labels never wrap into competing heights." */
|
|
19
|
+
overflow-x: auto;
|
|
20
|
+
scrollbar-width: none;
|
|
21
|
+
}
|
|
22
|
+
.ol8-tabs::-webkit-scrollbar { display: none; }
|
|
23
|
+
|
|
24
|
+
.ol8-tabs[data-ol8-hierarchy="primary"]::after {
|
|
25
|
+
content: "";
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset-block-end: 0;
|
|
28
|
+
inset-inline: 0;
|
|
29
|
+
block-size: var(--ol8-component-tab-item-rail);
|
|
30
|
+
background: var(--ol8-color-text-secondary);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Vertical tabs turn the rail onto the logical inline edge and let each tab
|
|
34
|
+
fill the width, so the indicator reads as a column marker. */
|
|
35
|
+
.ol8-tabs[data-ol8-orientation="vertical"] {
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
overflow-x: visible;
|
|
38
|
+
}
|
|
39
|
+
.ol8-tabs[data-ol8-orientation="vertical"][data-ol8-hierarchy="primary"]::after {
|
|
40
|
+
inset-block: 0;
|
|
41
|
+
inset-inline: auto 0;
|
|
42
|
+
inline-size: var(--ol8-component-tab-item-rail);
|
|
43
|
+
block-size: auto;
|
|
44
|
+
}
|
|
45
|
+
.ol8-tabs[data-ol8-orientation="vertical"] .ol8-nav-item__indicator {
|
|
46
|
+
inset-block: var(--ol8-component-tab-item-indicator-inset);
|
|
47
|
+
inset-inline: auto 0;
|
|
48
|
+
inline-size: var(--ol8-component-tab-item-indicator-thickness);
|
|
49
|
+
block-size: auto;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.ol8-tabs__panel:focus-visible {
|
|
53
|
+
outline: none;
|
|
54
|
+
box-shadow: inset 0 0 0 var(--ol8-component-navigation-focus-inset) var(--ol8-color-focus-inner);
|
|
55
|
+
}
|