ionbase-ui 0.22.0 → 0.25.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/dist/components/AgentActivity.d.ts +41 -0
- package/dist/components/AgentActivity.d.ts.map +1 -0
- package/dist/components/AgentActivity.js +84 -0
- package/dist/components/AgentActivity.js.map +1 -0
- package/dist/components/AgentStop.d.ts +58 -0
- package/dist/components/AgentStop.d.ts.map +1 -0
- package/dist/components/AgentStop.js +82 -0
- package/dist/components/AgentStop.js.map +1 -0
- package/dist/components/ApprovalGate.d.ts +72 -0
- package/dist/components/ApprovalGate.d.ts.map +1 -0
- package/dist/components/ApprovalGate.js +68 -0
- package/dist/components/ApprovalGate.js.map +1 -0
- package/dist/components/Citation.d.ts +51 -0
- package/dist/components/Citation.d.ts.map +1 -0
- package/dist/components/Citation.js +41 -0
- package/dist/components/Citation.js.map +1 -0
- package/dist/components/ConfidenceIndicator.d.ts +37 -0
- package/dist/components/ConfidenceIndicator.d.ts.map +1 -0
- package/dist/components/ConfidenceIndicator.js +41 -0
- package/dist/components/ConfidenceIndicator.js.map +1 -0
- package/dist/components/StreamingText.d.ts +47 -0
- package/dist/components/StreamingText.d.ts.map +1 -0
- package/dist/components/StreamingText.js +44 -0
- package/dist/components/StreamingText.js.map +1 -0
- package/dist/components/index.d.ts +12 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +6 -0
- package/dist/components/index.js.map +1 -1
- package/dist/figma-descriptions.json +147 -0
- package/dist/figma-map.json +3 -1
- package/dist/meta/AgentActivity.json +103 -0
- package/dist/meta/AgentActivityStep.json +117 -0
- package/dist/meta/AgentStop.json +164 -0
- package/dist/meta/ApprovalGate.json +255 -0
- package/dist/meta/Avatar.json +2 -2
- package/dist/meta/AvatarGroup.json +2 -2
- package/dist/meta/Citation.json +101 -0
- package/dist/meta/CitationList.json +94 -0
- package/dist/meta/CitationListItem.json +88 -0
- package/dist/meta/ConfidenceIndicator.json +115 -0
- package/dist/meta/Input.json +2 -2
- package/dist/meta/PhoneInput.json +38 -38
- package/dist/meta/StreamingText.json +99 -0
- package/dist/meta/components.json +2125 -989
- package/dist/meta/contrast.json +1086 -32
- package/dist/meta/index.json +100 -5
- package/dist/meta/patterns/index.json +1 -1
- package/dist/styles/agent-activity.css +95 -0
- package/dist/styles/agent-stop.css +109 -0
- package/dist/styles/approval-gate.css +181 -0
- package/dist/styles/citation.css +93 -0
- package/dist/styles/confidence-indicator.css +97 -0
- package/dist/styles/index.css +34 -0
- package/dist/styles/streaming-text.css +56 -0
- package/llms.txt +2 -2
- package/package.json +4 -3
package/dist/meta/index.json
CHANGED
|
@@ -1,11 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "ionbase-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"usage": "Pick a component here, then read dist/meta/<Name>.json for its full contract.",
|
|
5
5
|
"hooks": [
|
|
6
6
|
"useToast"
|
|
7
7
|
],
|
|
8
8
|
"components": {
|
|
9
|
+
"AgentActivity": {
|
|
10
|
+
"summary": "An ordered, plain-language log of what the agent is doing. Status is text and shape, never colour alone.",
|
|
11
|
+
"status": "stable",
|
|
12
|
+
"variants": {},
|
|
13
|
+
"detail": "dist/meta/AgentActivity.json",
|
|
14
|
+
"hasIntent": true
|
|
15
|
+
},
|
|
16
|
+
"AgentActivityStep": {
|
|
17
|
+
"summary": "One step in an activity log: what happened, in the user's language, with a status carried by shape and text.",
|
|
18
|
+
"status": "stable",
|
|
19
|
+
"variants": {
|
|
20
|
+
"status": [
|
|
21
|
+
"pending",
|
|
22
|
+
"active",
|
|
23
|
+
"done",
|
|
24
|
+
"failed",
|
|
25
|
+
"skipped"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"detail": "dist/meta/AgentActivityStep.json",
|
|
29
|
+
"hasIntent": true
|
|
30
|
+
},
|
|
31
|
+
"AgentStop": {
|
|
32
|
+
"summary": "The always-visible way to end a running agent. Not optional, and not behind a menu.",
|
|
33
|
+
"status": "stable",
|
|
34
|
+
"variants": {
|
|
35
|
+
"size": [
|
|
36
|
+
"sm",
|
|
37
|
+
"md",
|
|
38
|
+
"lg"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"detail": "dist/meta/AgentStop.json",
|
|
42
|
+
"hasIntent": true
|
|
43
|
+
},
|
|
9
44
|
"Alert": {
|
|
10
45
|
"summary": "A persistent, in-page status message. Intent picks the ARIA role for you.",
|
|
11
46
|
"status": "stable",
|
|
@@ -30,15 +65,34 @@
|
|
|
30
65
|
"detail": "dist/meta/Alert.json",
|
|
31
66
|
"hasIntent": true
|
|
32
67
|
},
|
|
68
|
+
"ApprovalGate": {
|
|
69
|
+
"summary": "A proposed action held until a person approves, rejects or amends it. It renders the decision; it does not enforce it.",
|
|
70
|
+
"status": "stable",
|
|
71
|
+
"variants": {
|
|
72
|
+
"risk": [
|
|
73
|
+
"low",
|
|
74
|
+
"medium",
|
|
75
|
+
"high"
|
|
76
|
+
],
|
|
77
|
+
"status": [
|
|
78
|
+
"pending",
|
|
79
|
+
"approved",
|
|
80
|
+
"rejected",
|
|
81
|
+
"expired"
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
"detail": "dist/meta/ApprovalGate.json",
|
|
85
|
+
"hasIntent": true
|
|
86
|
+
},
|
|
33
87
|
"Avatar": {
|
|
34
88
|
"summary": "A person or entity marker. Content is chosen by precedence — image, then initials, then icon — not by a type prop.",
|
|
35
89
|
"status": "stable",
|
|
36
90
|
"variants": {
|
|
37
91
|
"size": [
|
|
38
|
-
"mini",
|
|
39
92
|
"sm",
|
|
40
93
|
"md",
|
|
41
|
-
"lg"
|
|
94
|
+
"lg",
|
|
95
|
+
"mini"
|
|
42
96
|
],
|
|
43
97
|
"shape": [
|
|
44
98
|
"circle",
|
|
@@ -53,10 +107,10 @@
|
|
|
53
107
|
"status": "stable",
|
|
54
108
|
"variants": {
|
|
55
109
|
"size": [
|
|
56
|
-
"mini",
|
|
57
110
|
"sm",
|
|
58
111
|
"md",
|
|
59
|
-
"lg"
|
|
112
|
+
"lg",
|
|
113
|
+
"mini"
|
|
60
114
|
],
|
|
61
115
|
"shape": [
|
|
62
116
|
"circle",
|
|
@@ -123,6 +177,40 @@
|
|
|
123
177
|
"detail": "dist/meta/Checkbox.json",
|
|
124
178
|
"hasIntent": true
|
|
125
179
|
},
|
|
180
|
+
"Citation": {
|
|
181
|
+
"summary": "The inline source marker. The visible number is for the eye; the accessible name is the sentence.",
|
|
182
|
+
"status": "stable",
|
|
183
|
+
"variants": {},
|
|
184
|
+
"detail": "dist/meta/Citation.json",
|
|
185
|
+
"hasIntent": true
|
|
186
|
+
},
|
|
187
|
+
"CitationList": {
|
|
188
|
+
"summary": "The footer list of sources, as an ordered list so the count and order are structural.",
|
|
189
|
+
"status": "stable",
|
|
190
|
+
"variants": {},
|
|
191
|
+
"detail": "dist/meta/CitationList.json",
|
|
192
|
+
"hasIntent": true
|
|
193
|
+
},
|
|
194
|
+
"CitationListItem": {
|
|
195
|
+
"summary": "One source row: its number, what it is, and the passage it supports.",
|
|
196
|
+
"status": "stable",
|
|
197
|
+
"variants": {},
|
|
198
|
+
"detail": "dist/meta/CitationListItem.json",
|
|
199
|
+
"hasIntent": true
|
|
200
|
+
},
|
|
201
|
+
"ConfidenceIndicator": {
|
|
202
|
+
"summary": "How much to trust the thing next to it — three levels with a required basis, never a percentage.",
|
|
203
|
+
"status": "stable",
|
|
204
|
+
"variants": {
|
|
205
|
+
"level": [
|
|
206
|
+
"low",
|
|
207
|
+
"medium",
|
|
208
|
+
"high"
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
"detail": "dist/meta/ConfidenceIndicator.json",
|
|
212
|
+
"hasIntent": true
|
|
213
|
+
},
|
|
126
214
|
"Divider": {
|
|
127
215
|
"summary": "A semantic thematic break, rendered as a real <hr>.",
|
|
128
216
|
"status": "stable",
|
|
@@ -357,6 +445,13 @@
|
|
|
357
445
|
"detail": "dist/meta/Select.json",
|
|
358
446
|
"hasIntent": true
|
|
359
447
|
},
|
|
448
|
+
"StreamingText": {
|
|
449
|
+
"summary": "Model output arriving a token at a time, in a container that does not move. Deliberately not a live region.",
|
|
450
|
+
"status": "stable",
|
|
451
|
+
"variants": {},
|
|
452
|
+
"detail": "dist/meta/StreamingText.json",
|
|
453
|
+
"hasIntent": true
|
|
454
|
+
},
|
|
360
455
|
"TabItem": {
|
|
361
456
|
"summary": "One tab and its panel. Re-exported from react-stately's collection Item — `title` is the tab label, children are the panel.",
|
|
362
457
|
"status": "stable",
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* AgentActivity
|
|
3
|
+
*
|
|
4
|
+
* NOT DRAWN IN FIGMA. The rail-and-body layout is Alert's, one step down in
|
|
5
|
+
* scale; colours are the status roles used everywhere else in the system.
|
|
6
|
+
*/
|
|
7
|
+
.ion-agent-activity {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
gap: var(--spacing-8);
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
list-style: none;
|
|
14
|
+
font-family: var(--font-family-sans);
|
|
15
|
+
font-size: var(--type-body-sm);
|
|
16
|
+
line-height: var(--type-body-sm-line-height);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.ion-agent-activity__step {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: flex-start;
|
|
22
|
+
gap: var(--spacing-8);
|
|
23
|
+
color: var(--text-secondary);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.ion-agent-activity__glyph {
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
flex: none;
|
|
29
|
+
width: var(--icon-size-sm);
|
|
30
|
+
height: var(--icon-size-sm);
|
|
31
|
+
|
|
32
|
+
/* Optical alignment to the first line of the label, not to the box. */
|
|
33
|
+
margin-top: var(--spacing-2);
|
|
34
|
+
color: var(--icon-tertiary);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.ion-agent-activity__glyph svg {
|
|
38
|
+
width: 100%;
|
|
39
|
+
height: 100%;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.ion-agent-activity__body {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
gap: var(--spacing-2);
|
|
46
|
+
min-width: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ion-agent-activity__detail {
|
|
50
|
+
color: var(--text-tertiary);
|
|
51
|
+
font-size: var(--type-caption);
|
|
52
|
+
line-height: var(--type-caption-line-height);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
* Status colour is the second signal, never the only one: each status also has
|
|
57
|
+
* a differently SHAPED glyph, and its name in visually hidden text. A row of
|
|
58
|
+
* dots that differ only in hue fails WCAG 1.4.1 outright.
|
|
59
|
+
*/
|
|
60
|
+
.ion-agent-activity__step--active {
|
|
61
|
+
color: var(--text-default);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ion-agent-activity__step--active .ion-agent-activity__glyph {
|
|
65
|
+
color: var(--icon-primary);
|
|
66
|
+
animation: ion-agent-activity-spin 1.2s linear infinite;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.ion-agent-activity__step--done .ion-agent-activity__glyph {
|
|
70
|
+
color: var(--icon-success);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ion-agent-activity__step--failed {
|
|
74
|
+
color: var(--text-error);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.ion-agent-activity__step--failed .ion-agent-activity__glyph {
|
|
78
|
+
color: var(--icon-error);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.ion-agent-activity__step--skipped {
|
|
82
|
+
color: var(--text-tertiary);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes ion-agent-activity-spin {
|
|
86
|
+
to {
|
|
87
|
+
transform: rotate(360deg);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@media (prefers-reduced-motion: reduce) {
|
|
92
|
+
.ion-agent-activity__step--active .ion-agent-activity__glyph {
|
|
93
|
+
animation: none;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* AgentStop
|
|
3
|
+
*
|
|
4
|
+
* NOT DRAWN IN FIGMA. This component has no Figma counterpart yet, so the
|
|
5
|
+
* measurements are borrowed rather than invented: the size ramp, radius, focus
|
|
6
|
+
* ring and icon sizing are Button's, read from the same tokens. When Figma
|
|
7
|
+
* draws it, this file should need values changed, not structure.
|
|
8
|
+
*
|
|
9
|
+
* DELIBERATELY NOT `surface/error`. Stopping a run is normal and expected, and
|
|
10
|
+
* you can start it again. Colouring it like a delete teaches hesitation about
|
|
11
|
+
* the one control that must never be hesitated over. It reads as a firm
|
|
12
|
+
* neutral: strong border, plain surface, error colour only on hover, where it
|
|
13
|
+
* confirms rather than warns.
|
|
14
|
+
*/
|
|
15
|
+
.ion-agent-stop {
|
|
16
|
+
display: inline-flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
gap: var(--spacing-8);
|
|
20
|
+
min-height: var(--spacing-40);
|
|
21
|
+
padding: var(--spacing-8) var(--spacing-16);
|
|
22
|
+
border: var(--border-width-default) solid var(--border-strong);
|
|
23
|
+
border-radius: var(--radius-md);
|
|
24
|
+
background-color: var(--surface-default);
|
|
25
|
+
color: var(--text-default);
|
|
26
|
+
font-family: var(--font-family-sans);
|
|
27
|
+
font-size: var(--type-body);
|
|
28
|
+
line-height: var(--type-body-line-height);
|
|
29
|
+
font-weight: var(--font-weight-medium);
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
transition:
|
|
32
|
+
background-color var(--ion-duration-base) var(--ion-ease-out),
|
|
33
|
+
border-color var(--ion-duration-base) var(--ion-ease-out),
|
|
34
|
+
color var(--ion-duration-base) var(--ion-ease-out);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.ion-agent-stop:focus-visible {
|
|
38
|
+
outline: var(--border-width-thick) solid var(--border-focus);
|
|
39
|
+
outline-offset: 2px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* Disabled ONLY while the stop is in flight, never as a resting state. A
|
|
44
|
+
* greyed-out stop button on a running agent is the failure this component
|
|
45
|
+
* exists to prevent, so the styling deliberately does not read as
|
|
46
|
+
* "unavailable" — it reads as "already asked".
|
|
47
|
+
*
|
|
48
|
+
* Declared before :hover so specificity reads non-decreasing; the :not(:disabled)
|
|
49
|
+
* on the hover rules is what keeps them from fighting.
|
|
50
|
+
*/
|
|
51
|
+
.ion-agent-stop:disabled {
|
|
52
|
+
cursor: default;
|
|
53
|
+
background-color: var(--surface-muted);
|
|
54
|
+
border-color: var(--border-default);
|
|
55
|
+
color: var(--text-secondary);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.ion-agent-stop:hover:not(:disabled) {
|
|
59
|
+
background-color: var(--surface-error-subtle);
|
|
60
|
+
border-color: var(--border-error);
|
|
61
|
+
color: var(--text-error);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ion-agent-stop:active:not(:disabled) {
|
|
65
|
+
background-color: var(--surface-error-subtle-hover);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.ion-agent-stop__glyph {
|
|
69
|
+
display: inline-flex;
|
|
70
|
+
flex: none;
|
|
71
|
+
width: var(--icon-size-sm);
|
|
72
|
+
height: var(--icon-size-sm);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.ion-agent-stop__glyph svg {
|
|
76
|
+
width: 100%;
|
|
77
|
+
height: 100%;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* The square shrinks while stopping — the one motion cue that the press
|
|
81
|
+
* landed, on a control whose text also changed. */
|
|
82
|
+
.ion-agent-stop[data-stopping] .ion-agent-stop__glyph svg {
|
|
83
|
+
transform: scale(0.7);
|
|
84
|
+
transition: transform var(--ion-duration-base) var(--ion-ease-out);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.ion-agent-stop--sm {
|
|
88
|
+
min-height: var(--spacing-32);
|
|
89
|
+
padding: var(--spacing-4) var(--spacing-12);
|
|
90
|
+
font-size: var(--type-body-sm);
|
|
91
|
+
line-height: var(--type-body-sm-line-height);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.ion-agent-stop--sm .ion-agent-stop__glyph {
|
|
95
|
+
width: var(--icon-size-xs);
|
|
96
|
+
height: var(--icon-size-xs);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.ion-agent-stop--lg {
|
|
100
|
+
min-height: var(--spacing-48);
|
|
101
|
+
padding: var(--spacing-12) var(--spacing-20);
|
|
102
|
+
font-size: var(--type-body-lg);
|
|
103
|
+
line-height: var(--type-body-lg-line-height);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.ion-agent-stop--lg .ion-agent-stop__glyph {
|
|
107
|
+
width: var(--icon-size-md);
|
|
108
|
+
height: var(--icon-size-md);
|
|
109
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ApprovalGate
|
|
3
|
+
*
|
|
4
|
+
* NOT DRAWN IN FIGMA. Structure is Alert's — icon rail, body, one variable per
|
|
5
|
+
* colour slot — so that when Figma draws it, this file needs values changed
|
|
6
|
+
* rather than rewriting. The action row borrows Button's ramp.
|
|
7
|
+
*
|
|
8
|
+
* RISK CHANGES EMPHASIS, NOT MEANING
|
|
9
|
+
*
|
|
10
|
+
* Three risk tiers reassign four variables, exactly the way Alert's intents do.
|
|
11
|
+
* `low` sits on the neutral surface, `medium` on information, `high` on
|
|
12
|
+
* warning — NOT on error. Error is for something that has gone wrong; a
|
|
13
|
+
* high-risk approval is working correctly, and it is asking. Reserving red for
|
|
14
|
+
* failure is what keeps red meaningful when a failure actually happens.
|
|
15
|
+
*/
|
|
16
|
+
.ion-approval-gate {
|
|
17
|
+
--ion-approval-surface: var(--surface-information-subtle);
|
|
18
|
+
--ion-approval-border: var(--border-information);
|
|
19
|
+
--ion-approval-icon: var(--icon-information);
|
|
20
|
+
--ion-approval-accent: var(--text-information);
|
|
21
|
+
|
|
22
|
+
position: relative;
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: flex-start;
|
|
25
|
+
gap: var(--spacing-12);
|
|
26
|
+
padding: var(--spacing-16);
|
|
27
|
+
background-color: var(--ion-approval-surface);
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* A thicker leading edge, not a heavier box. A decision waiting on a person
|
|
31
|
+
* has to be findable at a glance down a long transcript, and a full heavy
|
|
32
|
+
* border would compete with every Alert on the page.
|
|
33
|
+
*/
|
|
34
|
+
border: var(--border-width-default) solid var(--ion-approval-border);
|
|
35
|
+
border-inline-start-width: var(--border-width-thicker);
|
|
36
|
+
border-radius: var(--radius-md);
|
|
37
|
+
color: var(--text-default);
|
|
38
|
+
font-family: var(--font-family-sans);
|
|
39
|
+
font-size: var(--type-body);
|
|
40
|
+
line-height: var(--type-body-line-height);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ion-approval-gate--low {
|
|
44
|
+
--ion-approval-surface: var(--surface-muted);
|
|
45
|
+
--ion-approval-border: var(--border-default);
|
|
46
|
+
--ion-approval-icon: var(--icon-secondary);
|
|
47
|
+
--ion-approval-accent: var(--text-secondary);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.ion-approval-gate--high {
|
|
51
|
+
--ion-approval-surface: var(--surface-warning-subtle);
|
|
52
|
+
--ion-approval-border: var(--border-warning-strong);
|
|
53
|
+
--ion-approval-icon: var(--icon-warning);
|
|
54
|
+
--ion-approval-accent: var(--text-warning);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Resolved: the decision is a record now, not a question. Drop the tint and
|
|
58
|
+
* keep the rule, so the row stays scannable without still looking pending. */
|
|
59
|
+
.ion-approval-gate--approved,
|
|
60
|
+
.ion-approval-gate--rejected,
|
|
61
|
+
.ion-approval-gate--expired {
|
|
62
|
+
--ion-approval-surface: var(--surface-default);
|
|
63
|
+
--ion-approval-border: var(--border-default);
|
|
64
|
+
--ion-approval-icon: var(--icon-tertiary);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ion-approval-gate--approved {
|
|
68
|
+
--ion-approval-border: var(--border-success);
|
|
69
|
+
--ion-approval-icon: var(--icon-success);
|
|
70
|
+
--ion-approval-accent: var(--text-success);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ion-approval-gate--rejected {
|
|
74
|
+
--ion-approval-accent: var(--text-secondary);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.ion-approval-gate__icon {
|
|
78
|
+
display: inline-flex;
|
|
79
|
+
flex: none;
|
|
80
|
+
width: var(--icon-size-md);
|
|
81
|
+
height: var(--icon-size-md);
|
|
82
|
+
color: var(--ion-approval-icon);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ion-approval-gate__icon svg {
|
|
86
|
+
width: 100%;
|
|
87
|
+
height: 100%;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.ion-approval-gate__body {
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-direction: column;
|
|
93
|
+
gap: var(--spacing-8);
|
|
94
|
+
min-width: 0;
|
|
95
|
+
flex: 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.ion-approval-gate__title {
|
|
99
|
+
margin: 0;
|
|
100
|
+
font-weight: var(--font-weight-semibold);
|
|
101
|
+
color: var(--text-default);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Focusable only programmatically, so it takes a ring but no tab stop. */
|
|
105
|
+
.ion-approval-gate__title:focus-visible {
|
|
106
|
+
outline: var(--border-width-thick) solid var(--border-focus);
|
|
107
|
+
outline-offset: 2px;
|
|
108
|
+
border-radius: var(--radius-xs);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.ion-approval-gate__detail {
|
|
112
|
+
margin: 0;
|
|
113
|
+
color: var(--text-secondary);
|
|
114
|
+
font-size: var(--type-body-sm);
|
|
115
|
+
line-height: var(--type-body-sm-line-height);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ion-approval-gate__actions {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-wrap: wrap;
|
|
121
|
+
gap: var(--spacing-8);
|
|
122
|
+
margin-top: var(--spacing-4);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.ion-approval-gate__action {
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
min-height: var(--spacing-32);
|
|
130
|
+
padding: var(--spacing-4) var(--spacing-12);
|
|
131
|
+
border: var(--border-width-default) solid var(--border-strong);
|
|
132
|
+
border-radius: var(--radius-sm);
|
|
133
|
+
background-color: var(--surface-default);
|
|
134
|
+
color: var(--text-default);
|
|
135
|
+
font-family: var(--font-family-sans);
|
|
136
|
+
font-size: var(--type-body-sm);
|
|
137
|
+
line-height: var(--type-body-sm-line-height);
|
|
138
|
+
font-weight: var(--font-weight-medium);
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
transition:
|
|
141
|
+
background-color var(--ion-duration-base) var(--ion-ease-out),
|
|
142
|
+
border-color var(--ion-duration-base) var(--ion-ease-out);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.ion-approval-gate__action:focus-visible {
|
|
146
|
+
outline: var(--border-width-thick) solid var(--border-focus);
|
|
147
|
+
outline-offset: 2px;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Before :hover so specificity reads non-decreasing. */
|
|
151
|
+
.ion-approval-gate__action:disabled {
|
|
152
|
+
cursor: default;
|
|
153
|
+
background-color: var(--surface-disabled);
|
|
154
|
+
border-color: var(--border-disabled);
|
|
155
|
+
color: var(--text-disabled);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.ion-approval-gate__action:hover:not(:disabled) {
|
|
159
|
+
background-color: var(--surface-hover);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/*
|
|
163
|
+
* Approve is the only filled button, and it is filled in brand rather than
|
|
164
|
+
* success. Success would state an outcome before there is one.
|
|
165
|
+
*/
|
|
166
|
+
.ion-approval-gate__action--approve {
|
|
167
|
+
background-color: var(--surface-primary);
|
|
168
|
+
border-color: var(--surface-primary);
|
|
169
|
+
color: var(--text-on-color);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.ion-approval-gate__action--approve:hover:not(:disabled) {
|
|
173
|
+
background-color: var(--surface-primary-hover);
|
|
174
|
+
border-color: var(--surface-primary-hover);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ion-approval-gate__resolution {
|
|
178
|
+
margin: 0;
|
|
179
|
+
font-weight: var(--font-weight-medium);
|
|
180
|
+
color: var(--ion-approval-accent);
|
|
181
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Citation
|
|
3
|
+
*
|
|
4
|
+
* NOT DRAWN IN FIGMA. The inline marker borrows Badge's pill geometry at the
|
|
5
|
+
* smallest size; the footer list borrows the Table's row rhythm.
|
|
6
|
+
*/
|
|
7
|
+
.ion-citation {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
min-width: var(--spacing-16);
|
|
12
|
+
height: var(--spacing-16);
|
|
13
|
+
padding: 0 var(--spacing-4);
|
|
14
|
+
|
|
15
|
+
/* Sits with the text, not on it: superscript positioning would shift the
|
|
16
|
+
* line box and make a paragraph of citations ripple. */
|
|
17
|
+
margin-inline-start: var(--spacing-2);
|
|
18
|
+
border-radius: var(--radius-xs);
|
|
19
|
+
background-color: var(--surface-primary-subtle);
|
|
20
|
+
color: var(--text-link);
|
|
21
|
+
font-size: var(--type-caption);
|
|
22
|
+
line-height: var(--type-caption-line-height);
|
|
23
|
+
font-weight: var(--font-weight-medium);
|
|
24
|
+
text-decoration: none;
|
|
25
|
+
vertical-align: baseline;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
a.ion-citation:hover {
|
|
29
|
+
background-color: var(--surface-primary-subtle-hover);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
a.ion-citation:focus-visible {
|
|
33
|
+
outline: var(--border-width-thick) solid var(--border-focus);
|
|
34
|
+
outline-offset: 1px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.ion-citation-list {
|
|
38
|
+
font-family: var(--font-family-sans);
|
|
39
|
+
font-size: var(--type-body-sm);
|
|
40
|
+
line-height: var(--type-body-sm-line-height);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ion-citation-list__label {
|
|
44
|
+
margin: 0 0 var(--spacing-8);
|
|
45
|
+
color: var(--text-tertiary);
|
|
46
|
+
font-size: var(--type-caption);
|
|
47
|
+
line-height: var(--type-caption-line-height);
|
|
48
|
+
font-weight: var(--font-weight-semibold);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ion-citation-list__items {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
gap: var(--spacing-8);
|
|
55
|
+
margin: 0;
|
|
56
|
+
padding: 0;
|
|
57
|
+
|
|
58
|
+
/* The <ol> keeps its semantics and loses its markers: the visible number is
|
|
59
|
+
* the citation's own, which must match the inline marker exactly. */
|
|
60
|
+
list-style: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ion-citation-list__item {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: flex-start;
|
|
66
|
+
gap: var(--spacing-8);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.ion-citation-list__marker {
|
|
70
|
+
flex: none;
|
|
71
|
+
min-width: var(--spacing-16);
|
|
72
|
+
color: var(--text-tertiary);
|
|
73
|
+
font-size: var(--type-caption);
|
|
74
|
+
line-height: var(--type-body-sm-line-height);
|
|
75
|
+
text-align: end;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.ion-citation-list__body {
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
gap: var(--spacing-2);
|
|
82
|
+
min-width: 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ion-citation-list__source {
|
|
86
|
+
color: var(--text-link);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ion-citation-list__passage {
|
|
90
|
+
color: var(--text-tertiary);
|
|
91
|
+
font-size: var(--type-caption);
|
|
92
|
+
line-height: var(--type-caption-line-height);
|
|
93
|
+
}
|