@ethlete/components 1.0.0-next.79 → 1.0.0-next.81
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 +41 -0
- package/design/anchored-dialog.ts +98 -0
- package/design/button.ts +13 -1
- package/design/config.json +6 -1
- package/design/dialog.ts +5 -3
- package/design/form-field.ts +3 -0
- package/design/menu.ts +8 -4
- package/design/notification.ts +8 -4
- package/design/sdk/components/accordion/accordion.ts +5 -1
- package/design/sdk/components/anchored-dialog/anchored-dialog.css +63 -0
- package/design/sdk/components/anchored-dialog/anchored-dialog.ts +75 -0
- package/design/sdk/components/avatar/avatar.ts +3 -2
- package/design/sdk/components/badge/badge.ts +2 -1
- package/design/sdk/components/banner/banner.ts +2 -1
- package/design/sdk/components/bracket/bracket.ts +2 -1
- package/design/sdk/components/breadcrumb/breadcrumb.ts +2 -1
- package/design/sdk/components/button/button.css +11 -3
- package/design/sdk/components/button/button.ts +17 -4
- package/design/sdk/components/calendar/calendar.ts +2 -1
- package/design/sdk/components/card/card.ts +2 -1
- package/design/sdk/components/carousel/carousel.ts +2 -1
- package/design/sdk/components/chart/chart.ts +2 -1
- package/design/sdk/components/checkbox/checkbox.css +65 -0
- package/design/sdk/components/checkbox/checkbox.ts +180 -0
- package/design/sdk/components/chip/chip.ts +2 -1
- package/design/sdk/components/copy-button/copy-button.ts +2 -1
- package/design/sdk/components/description-list/description-list.ts +2 -1
- package/design/sdk/components/dialog/dialog.ts +2 -1
- package/design/sdk/components/divider/divider.ts +2 -1
- package/design/sdk/components/empty-state/empty-state.ts +2 -1
- package/design/sdk/components/grid/grid.ts +3 -2
- package/design/sdk/components/input/input.ts +2 -1
- package/design/sdk/components/kbd/kbd.ts +2 -1
- package/design/sdk/components/loader/loader.ts +2 -1
- package/design/sdk/components/masonry/masonry.ts +3 -2
- package/design/sdk/components/match/match.ts +2 -1
- package/design/sdk/components/menu/menu.ts +19 -7
- package/design/sdk/components/notification/notification.ts +2 -1
- package/design/sdk/components/otp-input/otp-input.ts +2 -1
- package/design/sdk/components/pagination/pagination.ts +2 -1
- package/design/sdk/components/picture/picture.ts +2 -1
- package/design/sdk/components/progress-steps/progress-steps.ts +2 -1
- package/design/sdk/components/query-error/query-error.ts +2 -1
- package/design/sdk/components/radio-group/radio-group.css +46 -0
- package/design/sdk/components/radio-group/radio-group.ts +167 -0
- package/design/sdk/components/scheduler/scheduler.ts +2 -1
- package/design/sdk/components/scrollable/scrollable.ts +2 -2
- package/design/sdk/components/scrollbar/scrollbar.ts +2 -1
- package/design/sdk/components/select/shared/select-part.ts +11 -2
- package/design/sdk/components/select-panel/select-panel.ts +2 -1
- package/design/sdk/components/skeleton/skeleton.ts +2 -1
- package/design/sdk/components/slider/slider.ts +2 -1
- package/design/sdk/components/standings/standings.ts +2 -1
- package/design/sdk/components/stat-tile/stat-tile.ts +2 -1
- package/design/sdk/components/stream/stream.ts +6 -1
- package/design/sdk/components/switch/switch.css +4 -2
- package/design/sdk/components/switch/switch.ts +2 -2
- package/design/sdk/components/table/table.ts +2 -1
- package/design/sdk/components/textarea/textarea.ts +4 -3
- package/design/sdk/components/timeline/timeline.ts +2 -2
- package/design/sdk/components/toolbar/toolbar.ts +2 -1
- package/design/sdk/foundations/colors/colors.css +16 -0
- package/design/sdk/foundations/colors/colors.ts +1 -1
- package/design/sdk/foundations/colors/shared/contrast.ts +1 -1
- package/design/sdk/lint-baseline.json +6 -0
- package/design/sdk/pictures.json +1195 -0
- package/design/sdk/ready.json +64 -0
- package/design/sdk/rule-baseline.json +104 -0
- package/design/select.ts +9 -5
- package/design/textarea.ts +2 -0
- package/design/tooltip.ts +5 -5
- package/fesm2022/ethlete-components.mjs +1190 -973
- package/fesm2022/ethlete-components.mjs.map +1 -1
- package/generators/generators.json +2 -0
- package/package.json +1 -1
- package/src/lib/button/button-properties-styles.component.css +6 -6
- package/src/lib/button/button.component.css +11 -7
- package/src/lib/button/button.types.ts +33 -0
- package/src/lib/button/icon-button.component.css +3 -3
- package/src/lib/button/window-control-button.component.css +70 -3
- package/src/lib/calendar/calendar.component.css +2 -2
- package/src/lib/chip/chip.component.css +4 -4
- package/src/lib/focus-ring/focus-ring-styles.component.css +20 -5
- package/src/lib/forms/switch/switch.component.css +1 -14
- package/src/lib/kbd/kbd.component.css +1 -1
- package/src/lib/menu/menu.component.css +2 -2
- package/src/lib/notification/notification.component.css +3 -3
- package/types/ethlete-components.d.ts +171 -139
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
radioGroup,
|
|
3
|
+
type RadioGroupMockOption,
|
|
4
|
+
type RadioGroupMockOptions,
|
|
5
|
+
type RadioMockForce,
|
|
6
|
+
radioGroupStyles,
|
|
7
|
+
} from '@ethlete/components/design/radio-group';
|
|
8
|
+
import { control } from '@ethlete/components/design/control';
|
|
9
|
+
import { definePart, drawing } from '@design-system';
|
|
10
|
+
import frame from './radio-group.css?inline';
|
|
11
|
+
|
|
12
|
+
type Props = { group: RadioGroupMockOptions } & Partial<RadioGroupMockOptions>;
|
|
13
|
+
|
|
14
|
+
const LABEL = 'Remind me one hour before';
|
|
15
|
+
|
|
16
|
+
const ROWS = {
|
|
17
|
+
unchecked: {},
|
|
18
|
+
checked: { checked: true },
|
|
19
|
+
} satisfies Record<string, Partial<RadioGroupMockOption>>;
|
|
20
|
+
|
|
21
|
+
const COLUMNS = ['rest', 'hover', 'focus-visible', 'active', 'disabled', 'readonly'] as const;
|
|
22
|
+
|
|
23
|
+
type Row = keyof typeof ROWS;
|
|
24
|
+
type Column = (typeof COLUMNS)[number];
|
|
25
|
+
|
|
26
|
+
const cellOf = (row: Row, column: Column): RadioGroupMockOptions => ({
|
|
27
|
+
id: `${row}-${column}`,
|
|
28
|
+
readonly: column === 'readonly',
|
|
29
|
+
options: [
|
|
30
|
+
{
|
|
31
|
+
...ROWS[row],
|
|
32
|
+
label: LABEL,
|
|
33
|
+
disabled: column === 'disabled',
|
|
34
|
+
force:
|
|
35
|
+
column === 'rest' || column === 'disabled' || column === 'readonly'
|
|
36
|
+
? undefined
|
|
37
|
+
: (column satisfies RadioMockForce),
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const stateOf = (row: Row, column: Column) => (column === 'rest' ? row : `${row}-${column}`);
|
|
43
|
+
|
|
44
|
+
const gridStates = Object.fromEntries(
|
|
45
|
+
(Object.keys(ROWS) as Row[]).flatMap((row) =>
|
|
46
|
+
COLUMNS.map((column) => [stateOf(row, column), { group: cellOf(row, column) }]),
|
|
47
|
+
),
|
|
48
|
+
) as Record<string, Props>;
|
|
49
|
+
|
|
50
|
+
const marked = (markup: string) =>
|
|
51
|
+
markup.replace(/<et-radio(?=[\s>])/gu, (tag) => control(`${tag}>`, 'radio').slice(0, -1));
|
|
52
|
+
|
|
53
|
+
const REMINDERS = ['One hour before', 'Fifteen minutes before', 'At kick-off'];
|
|
54
|
+
|
|
55
|
+
const reminderGroup = (
|
|
56
|
+
checked: number | null,
|
|
57
|
+
extra: Partial<RadioGroupMockOptions> & { force?: RadioMockForce[] } = {},
|
|
58
|
+
): RadioGroupMockOptions => {
|
|
59
|
+
const { force, ...rest } = extra;
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
id: 'reminder',
|
|
63
|
+
label: 'Kick-off reminder',
|
|
64
|
+
...rest,
|
|
65
|
+
options: REMINDERS.map((label, index) => ({
|
|
66
|
+
label,
|
|
67
|
+
checked: index === checked,
|
|
68
|
+
force: index === 1 ? force : undefined,
|
|
69
|
+
})),
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const formatGroup = (checked: number | null, force?: RadioMockForce[]): RadioGroupMockOptions => ({
|
|
74
|
+
id: 'format',
|
|
75
|
+
label: 'Match report format',
|
|
76
|
+
variant: 'card',
|
|
77
|
+
options: [
|
|
78
|
+
{ label: 'Short', description: 'The score and the scorers.', checked: checked === 0, force },
|
|
79
|
+
{ label: 'Full', description: 'Every event, with the line-ups.', checked: checked === 1 },
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const INVALID = {
|
|
84
|
+
required: true,
|
|
85
|
+
error: 'Pick a reminder to continue.',
|
|
86
|
+
errorColor: 'danger',
|
|
87
|
+
} satisfies Partial<RadioGroupMockOptions>;
|
|
88
|
+
|
|
89
|
+
export default definePart({
|
|
90
|
+
note: 'The SDK radio group (et-radio-group with et-radio) in flow, first drawing, drawn by the mock from @ethlete/components/design/radio-group with the real markup and CSS: et-label, et-radio in the plain and the card variant (et-selection-card), et-description, et-form-support with hint and error, the required marker, plus the color-interactive sheet; the brand theme, danger as the error theme. Fixtures are fictional: a match reminder form (Kick-off reminder: One hour before, Fifteen minutes before, At kick-off; hint We send it as a push notification.; required with error Pick a reminder to continue.; mixed hint The selected matches disagree.; card group Match report format: Short, The score and the scorers. / Full, Every event, with the line-ups.; horizontal group Show matches at: Home, Away, Neutral ground; grid label Remind me one hour before). Framed as a page with 16px padding at 360 and 640. States: a grid of unchecked and checked by rest, hover, focus-visible, active, disabled and readonly (one-option groups); group-none, group-checked, group-support (descriptions and hint), group-option-hover, group-option-pressed, group-option-focus-visible, group-mixed (bulk edit, dashed circles), group-disabled, group-readonly, invalid, invalid-focus-visible, invalid-checked, group-horizontal, card-rest, card-checked, card-hover, card-focus-visible and card-checked-focus-visible. Numbers (light / dark), from shot pixels at scale 2 at 360, brand mint, a: circle 20px with a 2px border and a 10px dot (border-box, fixed in 00072d935); unchecked circle border (surface border) vs page 1.26 / 1.73; checked ring and dot (primary) 1.33 / 13.50; checked hover dot and ring (-hover via color-interactive; the lib hover rule skips a checked radio) 1.37 / 13.06, 1.03 from rest; active 2.24 / 8.01; focus ring and focused border (primary -focus), checked or unchecked, 1.37 / 13.06; card checked edge and ring (primary) 1.33 / 13.50; mixed dashed border (primary) 1.33 / 13.50; invalid circle border (danger) 4.83 / 3.71; disabled checked ring 2.12 / 1.65, disabled label 1.41 / 1.65 (exempt under 1.4.11). Decided rules that arise: Q88 (every radio focus ring in ink, the unchecked one too, since unlike the checkbox it is primary, not the surface text colour; the invalid ring takes the danger ink; the card ring in ink), Q99a (the checked circle border, the focused circle border, the mixed dashed border and the card checked and focus edge take light-dark(ink, primary); the checked dot is a mint fill, so it takes a 1px inset ink edge, an outline at -1px) and Q101 (a checked radio hovers to -active). The ink edge on a mint fill arises, so Q102 arises: b draws the dot edge in both schemes, c keeps dark as today (light-dark(ink, transparent)). The error border is the danger theme, not mint, and passes 3:1, so it is kept. Findings for later: no new lib CSS bug; the radio circle box-sizing bug is fixed (00072d935, measured 40 sheet px = 20px). (1) WCAG 1.4.11: the unchecked circle border is 1.26 / 1.73 vs page, under 3:1, the only edge of an unchecked radio (the same open question as the checkbox box and the switch off track). Not drawn. (2) The required marker takes the error theme primary: 3.71:1 in dark, under 4.5:1; exempted here as in checkbox r1. (3) A checked radio has no hover rule of its own; only color-interactive shifts it to -hover, 1.03 from rest, so hover on a checked radio is invisible in a; Q101 fixes it in b and c. (4) Readonly draws exactly like rest, as with the checkbox. (5) A disabled group dims its options (opacity 0.5 and the disabled label colour, both at once) but not the group label, which keeps 7.81 in light; the same holds for the checkbox group. Later rounds, left out here: the sizes sm and lg, the card with the control at start and the card slots, a coloured (non-brand) radio, the warning state, a disabled option inside an enabled group, a pending (aria-busy) group, long labels that wrap, RTL and the check animation.',
|
|
91
|
+
madeBy: ['claude-opus-5-5'],
|
|
92
|
+
states: {
|
|
93
|
+
...gridStates,
|
|
94
|
+
'group-none': { group: reminderGroup(null) },
|
|
95
|
+
'group-checked': { group: reminderGroup(0) },
|
|
96
|
+
'group-support': {
|
|
97
|
+
group: {
|
|
98
|
+
id: 'support',
|
|
99
|
+
label: 'Kick-off reminder',
|
|
100
|
+
hint: 'We send it as a push notification.',
|
|
101
|
+
options: [
|
|
102
|
+
{ label: 'One hour before', description: 'Time to get to the ground.', checked: true },
|
|
103
|
+
{ label: 'At kick-off', description: 'Only when the whistle goes.' },
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
'group-option-hover': { group: reminderGroup(0, { force: ['hover'] }) },
|
|
108
|
+
'group-option-pressed': { group: reminderGroup(0, { force: ['hover', 'active'] }) },
|
|
109
|
+
'group-option-focus-visible': { group: reminderGroup(1, { force: ['focus-visible'] }) },
|
|
110
|
+
'group-mixed': { group: reminderGroup(0, { mixed: true, hint: 'The selected matches disagree.' }) },
|
|
111
|
+
'group-disabled': { group: reminderGroup(0, { disabled: true }) },
|
|
112
|
+
'group-readonly': { group: reminderGroup(0, { readonly: true }) },
|
|
113
|
+
invalid: { group: reminderGroup(null, INVALID) },
|
|
114
|
+
'invalid-focus-visible': { group: reminderGroup(null, { ...INVALID, force: ['focus-visible'] }) },
|
|
115
|
+
'invalid-checked': { group: reminderGroup(1, INVALID) },
|
|
116
|
+
'group-horizontal': {
|
|
117
|
+
group: {
|
|
118
|
+
id: 'venue',
|
|
119
|
+
label: 'Show matches at',
|
|
120
|
+
orientation: 'horizontal',
|
|
121
|
+
options: [{ label: 'Home', checked: true }, { label: 'Away' }, { label: 'Neutral ground' }],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
'card-rest': { group: formatGroup(null) },
|
|
125
|
+
'card-checked': { group: formatGroup(0) },
|
|
126
|
+
'card-hover': { group: formatGroup(1, ['hover']) },
|
|
127
|
+
'card-focus-visible': { group: formatGroup(1, ['focus-visible']) },
|
|
128
|
+
'card-checked-focus-visible': { group: formatGroup(0, ['focus-visible']) },
|
|
129
|
+
},
|
|
130
|
+
grid: {
|
|
131
|
+
columns: COLUMNS,
|
|
132
|
+
rows: Object.fromEntries(
|
|
133
|
+
(Object.keys(ROWS) as Row[]).map((row) => [
|
|
134
|
+
row,
|
|
135
|
+
Object.fromEntries(COLUMNS.map((column) => [column, stateOf(row, column)])),
|
|
136
|
+
]),
|
|
137
|
+
),
|
|
138
|
+
},
|
|
139
|
+
omits: [
|
|
140
|
+
{ option: 'size', value: 'sm', reason: 'Not drawn in this round: sizes are a later round.' },
|
|
141
|
+
{ option: 'size', value: 'md', reason: 'The default size, which every state draws without setting it.' },
|
|
142
|
+
{ option: 'size', value: 'lg', reason: 'Not drawn in this round: sizes are a later round.' },
|
|
143
|
+
{
|
|
144
|
+
option: 'orientation',
|
|
145
|
+
value: 'vertical',
|
|
146
|
+
reason: 'The default orientation, drawn by the group-* states, outside the grid.',
|
|
147
|
+
},
|
|
148
|
+
{ option: 'orientation', value: 'horizontal', reason: 'Drawn as the group-horizontal state, outside the grid.' },
|
|
149
|
+
{ option: 'variant', value: 'plain', reason: 'The default variant, which the grid draws without setting it.' },
|
|
150
|
+
{ option: 'variant', value: 'card', reason: 'Drawn as the card-* states, outside the grid.' },
|
|
151
|
+
{
|
|
152
|
+
option: 'controlPosition',
|
|
153
|
+
value: 'start',
|
|
154
|
+
reason: 'Not drawn in this round: the card with the control at start is a later round.',
|
|
155
|
+
},
|
|
156
|
+
{ option: 'controlPosition', value: 'end', reason: 'Drawn as the card-* states, outside the grid.' },
|
|
157
|
+
],
|
|
158
|
+
controls: {
|
|
159
|
+
radio: { kind: 'button', input: ['pointer', 'keyboard'], disabled: true },
|
|
160
|
+
},
|
|
161
|
+
widths: [360, 640],
|
|
162
|
+
render: (props: Props) =>
|
|
163
|
+
drawing({
|
|
164
|
+
body: `<div class="t-frame">${marked(radioGroup(props.group))}</div>`,
|
|
165
|
+
styles: [radioGroupStyles, frame].join('\n'),
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
@@ -231,9 +231,10 @@ export default definePart({
|
|
|
231
231
|
agenda: { view: 'agenda' },
|
|
232
232
|
},
|
|
233
233
|
widths: [560, 800, 1200],
|
|
234
|
+
frame: (body) => `<div class="t-frame">${body}</div>`,
|
|
234
235
|
render: (props: Props) =>
|
|
235
236
|
drawing({
|
|
236
|
-
body:
|
|
237
|
+
body: skipClipped(render(props)),
|
|
237
238
|
styles: [schedulerStyles, frame].join('\n'),
|
|
238
239
|
}),
|
|
239
240
|
});
|
|
@@ -94,7 +94,7 @@ const render = (props: Props) => {
|
|
|
94
94
|
|
|
95
95
|
export default definePart({
|
|
96
96
|
note: 'scale of the decided shape, Q182, lead merge',
|
|
97
|
-
madeBy: ['claude-opus-5-5'],
|
|
97
|
+
madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5'],
|
|
98
98
|
states: {
|
|
99
99
|
'horizontal-start': {},
|
|
100
100
|
'horizontal-middle': { position: 'middle' },
|
|
@@ -127,7 +127,7 @@ export default definePart({
|
|
|
127
127
|
widths: [480],
|
|
128
128
|
render: (props: Props) =>
|
|
129
129
|
drawing({
|
|
130
|
-
body: `<div class="scrollable-frame${props.itemSize ? '
|
|
130
|
+
body: `<div class="scrollable-frame ${props.itemSize ? 'scrollable-frame--sized' : ''}">${render(props)}</div>`,
|
|
131
131
|
styles: [scrollableStyles, frame].join('\n'),
|
|
132
132
|
}),
|
|
133
133
|
});
|
|
@@ -115,9 +115,10 @@ export default definePart({
|
|
|
115
115
|
'auto-hidden': { layout: 'vertical', visible: false },
|
|
116
116
|
},
|
|
117
117
|
widths: [480],
|
|
118
|
+
frame: (body, props) => `<div class="scrollbar-frame"${props.layout === 'rtl' ? ' dir="rtl"' : ''}>${body}</div>`,
|
|
118
119
|
render: (props: Props) =>
|
|
119
120
|
drawing({
|
|
120
|
-
body: `<div class="scrollbar-
|
|
121
|
+
body: `<div class="scrollbar-wrapper">${render(props)}</div>`,
|
|
121
122
|
styles: [scrollbarStyles, frame].join('\n'),
|
|
122
123
|
}),
|
|
123
124
|
});
|
|
@@ -5,6 +5,9 @@ import { interactionRows } from '@design-system';
|
|
|
5
5
|
type FieldInteraction = 'hover' | 'active' | 'focus-visible';
|
|
6
6
|
|
|
7
7
|
export type SelectProps = {
|
|
8
|
+
label?: string;
|
|
9
|
+
ariaLabel?: string;
|
|
10
|
+
options?: { value: string; label: string }[];
|
|
8
11
|
value?: string;
|
|
9
12
|
open?: boolean;
|
|
10
13
|
active?: string;
|
|
@@ -64,12 +67,18 @@ export const selectBody = (props: SelectProps) =>
|
|
|
64
67
|
markControl(
|
|
65
68
|
formField({
|
|
66
69
|
id: 'status',
|
|
67
|
-
label: 'Status',
|
|
70
|
+
label: props.label ?? 'Status',
|
|
68
71
|
errorColor: 'danger',
|
|
69
72
|
open: props.open,
|
|
70
73
|
disabled: props.disabled,
|
|
71
74
|
size: props.size,
|
|
72
|
-
control: select({
|
|
75
|
+
control: select({
|
|
76
|
+
options: props.options ?? OPTIONS,
|
|
77
|
+
value: props.value,
|
|
78
|
+
active: props.active,
|
|
79
|
+
placeholder: 'Pick a status',
|
|
80
|
+
ariaLabel: props.ariaLabel,
|
|
81
|
+
}),
|
|
73
82
|
}),
|
|
74
83
|
props,
|
|
75
84
|
);
|
|
@@ -116,9 +116,10 @@ export default definePart({
|
|
|
116
116
|
controls: {
|
|
117
117
|
option: { kind: 'row', input: ['pointer', 'keyboard'], disabled: true },
|
|
118
118
|
},
|
|
119
|
+
frame: (body) => `<div class="select-panel-frame">${body}</div>`,
|
|
119
120
|
render: (props: Props) =>
|
|
120
121
|
drawing({
|
|
121
|
-
body:
|
|
122
|
+
body: props.panel ? groupedPanel(props) : singleOption(props),
|
|
122
123
|
styles: [selectStyles, styles].join('\n'),
|
|
123
124
|
}),
|
|
124
125
|
});
|
|
@@ -42,9 +42,10 @@ export default definePart({
|
|
|
42
42
|
static: { form: 'card', animated: false },
|
|
43
43
|
},
|
|
44
44
|
widths: [480],
|
|
45
|
+
frame: (body) => `<div class="skeleton-frame">${body}</div>`,
|
|
45
46
|
render: (props: Props) =>
|
|
46
47
|
drawing({
|
|
47
|
-
body:
|
|
48
|
+
body: render(props),
|
|
48
49
|
styles: [skeletonStyles, frame].join('\n'),
|
|
49
50
|
}),
|
|
50
51
|
});
|
|
@@ -78,9 +78,10 @@ export default definePart({
|
|
|
78
78
|
],
|
|
79
79
|
},
|
|
80
80
|
widths: [320, 360, 640],
|
|
81
|
+
frame: (body) => `<div class="t-frame">${body}</div>`,
|
|
81
82
|
render: (props: Props) =>
|
|
82
83
|
drawing({
|
|
83
|
-
body:
|
|
84
|
+
body: slider(props.field),
|
|
84
85
|
styles: [sliderStyles, frame].join('\n'),
|
|
85
86
|
}),
|
|
86
87
|
});
|
|
@@ -122,9 +122,10 @@ export default definePart({
|
|
|
122
122
|
'pick-locked': { view: 'pick', locked: true },
|
|
123
123
|
},
|
|
124
124
|
widths: [480, 800],
|
|
125
|
+
frame: (body) => `<div class="t-frame">${body}</div>`,
|
|
125
126
|
render: (props: Props) =>
|
|
126
127
|
drawing({
|
|
127
|
-
body:
|
|
128
|
+
body: props.view === 'table' ? table(props) : pick(props),
|
|
128
129
|
styles: [standingsStyles, frame].join('\n'),
|
|
129
130
|
}),
|
|
130
131
|
});
|
|
@@ -76,9 +76,10 @@ export default definePart({
|
|
|
76
76
|
loading: { form: 'loading' },
|
|
77
77
|
},
|
|
78
78
|
widths: [480],
|
|
79
|
+
frame: (body) => `<div class="stat-tile-frame">${body}</div>`,
|
|
79
80
|
render: ({ form }: Props) =>
|
|
80
81
|
drawing({
|
|
81
|
-
body:
|
|
82
|
+
body: card({ content: statTile(FORMS[form]) }),
|
|
82
83
|
styles: [cardStyles, statTileStyles, frame].join('\n'),
|
|
83
84
|
}),
|
|
84
85
|
});
|
|
@@ -30,9 +30,14 @@ export default definePart({
|
|
|
30
30
|
controls: {
|
|
31
31
|
action: { kind: 'button', input: ['pointer', 'keyboard'] },
|
|
32
32
|
},
|
|
33
|
+
frame: (body) => `<div class="t-frame">${body}</div>`,
|
|
33
34
|
render: (props: Props) =>
|
|
34
35
|
drawing({
|
|
35
|
-
body:
|
|
36
|
+
body: streamPlayerSlot({
|
|
37
|
+
state: props.state,
|
|
38
|
+
player: VIDEO,
|
|
39
|
+
buttonAttributes: buttonAttributes(props.button),
|
|
40
|
+
}).replace('<et-spinner ', '<et-spinner data-et-skip="CLIPPED" '),
|
|
36
41
|
styles: [streamStyles, frame].join('\n'),
|
|
37
42
|
}),
|
|
38
43
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
et-switch:not([aria-checked='true']):not([data-indeterminate]) .et-switch-track {
|
|
3
|
-
box-shadow:
|
|
3
|
+
box-shadow: none;
|
|
4
|
+
background-color: color-mix(in srgb, var(--et-surface-interaction-solid, currentColor) 38%, transparent);
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
@media (hover: hover) {
|
|
@@ -10,7 +11,8 @@
|
|
|
10
11
|
:where(et-choice-field:has(.et-choice-field-label-area:hover))
|
|
11
12
|
et-switch:not([aria-disabled='true']):not([data-readonly]):not([aria-checked='true']):not([data-indeterminate]) {
|
|
12
13
|
.et-switch-track {
|
|
13
|
-
box-shadow:
|
|
14
|
+
box-shadow: none;
|
|
15
|
+
background-color: color-mix(in srgb, var(--et-surface-interaction-solid, currentColor) 38%, transparent);
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
}
|
|
@@ -28,7 +28,7 @@ const columns = ['rest', ...INTERACTIONS, 'disabled'] as const;
|
|
|
28
28
|
|
|
29
29
|
export default definePart({
|
|
30
30
|
note: 'The SDK switch, drawn by its mock from @ethlete/components/design: alone off, on and indeterminate in every interaction, and inside an et-choice-field with a label in each size and as a card. The label area skips CLIPPED: its 1.2 line height rounds the 12 and 16 px line box down by under a pixel, with no glyph cut.',
|
|
31
|
-
madeBy: ['claude-opus-5-5'],
|
|
31
|
+
madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5'],
|
|
32
32
|
states: {
|
|
33
33
|
...rowStates,
|
|
34
34
|
'label-sm': { label: 'Email me updates', size: 'sm', checked: true },
|
|
@@ -54,7 +54,7 @@ export default definePart({
|
|
|
54
54
|
body: switchControl({
|
|
55
55
|
...options,
|
|
56
56
|
color: 'brand',
|
|
57
|
-
attributes: ['data-et-control="switch"', interaction && `data-et-force="${interaction}"`]
|
|
57
|
+
attributes: [options.attributes, 'data-et-control="switch"', interaction && `data-et-force="${interaction}"`]
|
|
58
58
|
.filter(Boolean)
|
|
59
59
|
.join(' '),
|
|
60
60
|
}).replace('class="et-choice-field-label-area', 'data-et-skip="CLIPPED" class="et-choice-field-label-area'),
|
|
@@ -152,9 +152,10 @@ export default definePart({
|
|
|
152
152
|
'align-center': { center: true },
|
|
153
153
|
},
|
|
154
154
|
widths: [480],
|
|
155
|
+
frame: (body) => `<div class="t-frame">${body}</div>`,
|
|
155
156
|
render: (props: Props) =>
|
|
156
157
|
drawing({
|
|
157
|
-
body:
|
|
158
|
+
body: render(props),
|
|
158
159
|
styles: [tableStyles, frame].join('\n'),
|
|
159
160
|
}),
|
|
160
161
|
});
|
|
@@ -22,7 +22,7 @@ const INVALID = {
|
|
|
22
22
|
|
|
23
23
|
export default definePart({
|
|
24
24
|
note: 'scale of the decided shape, Q182, lead merge',
|
|
25
|
-
madeBy: ['claude-opus-5-5'],
|
|
25
|
+
madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5'],
|
|
26
26
|
states: {
|
|
27
27
|
empty: message({ placeholder: undefined }),
|
|
28
28
|
placeholder: message(),
|
|
@@ -54,11 +54,12 @@ export default definePart({
|
|
|
54
54
|
'size-lg': message({ value: VALUE, size: 'lg' }),
|
|
55
55
|
},
|
|
56
56
|
widths: [320, 360, 640],
|
|
57
|
+
frame: (body, props) => `<div class="t-frame ${props.scrolled ? 't-scrolled' : ''}">${body}</div>`,
|
|
57
58
|
render: (props: Props) =>
|
|
58
59
|
drawing({
|
|
59
60
|
body: props.scrolled
|
|
60
|
-
?
|
|
61
|
-
:
|
|
61
|
+
? textareaField(props.field).replace('<div class="et-form-field-control-frame"', '$& data-et-skip="CLIPPED"')
|
|
62
|
+
: textareaField(props.field),
|
|
62
63
|
styles: [textareaFieldStyles, frame].join('\n'),
|
|
63
64
|
}),
|
|
64
65
|
});
|
|
@@ -67,7 +67,7 @@ const items = ({ markers, themedDots, time = true, compact, long, count = EVENTS
|
|
|
67
67
|
|
|
68
68
|
export default definePart({
|
|
69
69
|
note: 'Decided rules only',
|
|
70
|
-
madeBy: ['claude-opus-5-5'],
|
|
70
|
+
madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5'],
|
|
71
71
|
states: {
|
|
72
72
|
default: {},
|
|
73
73
|
'with-markers': { markers: true },
|
|
@@ -81,7 +81,7 @@ export default definePart({
|
|
|
81
81
|
widths: [480],
|
|
82
82
|
render: (props: Props) =>
|
|
83
83
|
drawing({
|
|
84
|
-
body: `<div class="timeline-frame${props.compact ? '
|
|
84
|
+
body: `<div class="timeline-frame ${props.compact ? 'timeline-frame--compact' : ''}">${timeline({ items: items(props) })}</div>`,
|
|
85
85
|
styles: [timelineStyles, frame].join('\n'),
|
|
86
86
|
}),
|
|
87
87
|
});
|
|
@@ -79,9 +79,10 @@ export default definePart({
|
|
|
79
79
|
controls: Object.fromEntries(
|
|
80
80
|
BUTTONS.map(({ control }) => [control, { kind: 'button', input: ['pointer', 'keyboard'] }]),
|
|
81
81
|
),
|
|
82
|
+
frame: (body) => `<div class="toolbar-frame">${body}</div>`,
|
|
82
83
|
render: (props: Props) =>
|
|
83
84
|
drawing({
|
|
84
|
-
body:
|
|
85
|
+
body: render(props),
|
|
85
86
|
styles: [toolbarStyles, frame].join('\n'),
|
|
86
87
|
}),
|
|
87
88
|
});
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
--et-surface-type: light;
|
|
12
12
|
--et-surface-elevation: 0;
|
|
13
13
|
--et-shadow-color-rgb: 23 23 23;
|
|
14
|
+
--et-surface-color-theme-variants:
|
|
15
|
+
brand brand-on-light, danger danger-on-light, success success-on-light, warning warning-on-light;
|
|
14
16
|
--et-surface-interaction: 115 115 115;
|
|
15
17
|
--et-surface-interaction-hover: 64 64 64;
|
|
16
18
|
--et-surface-interaction-focus: 64 64 64;
|
|
@@ -44,6 +46,8 @@
|
|
|
44
46
|
--et-surface-type: light;
|
|
45
47
|
--et-surface-elevation: 1;
|
|
46
48
|
--et-shadow-color-rgb: 23 23 23;
|
|
49
|
+
--et-surface-color-theme-variants:
|
|
50
|
+
brand brand-on-light, danger danger-on-light, success success-on-light, warning warning-on-light;
|
|
47
51
|
--et-surface-interaction: 115 115 115;
|
|
48
52
|
--et-surface-interaction-hover: 64 64 64;
|
|
49
53
|
--et-surface-interaction-focus: 64 64 64;
|
|
@@ -77,6 +81,8 @@
|
|
|
77
81
|
--et-surface-type: light;
|
|
78
82
|
--et-surface-elevation: 0;
|
|
79
83
|
--et-shadow-color-rgb: 23 23 23;
|
|
84
|
+
--et-surface-color-theme-variants:
|
|
85
|
+
brand brand-on-light, danger danger-on-light, success success-on-light, warning warning-on-light;
|
|
80
86
|
--et-surface-interaction: 115 115 115;
|
|
81
87
|
--et-surface-interaction-hover: 64 64 64;
|
|
82
88
|
--et-surface-interaction-focus: 64 64 64;
|
|
@@ -114,6 +120,8 @@
|
|
|
114
120
|
--et-surface-type: light;
|
|
115
121
|
--et-surface-elevation: 0;
|
|
116
122
|
--et-shadow-color-rgb: 23 23 23;
|
|
123
|
+
--et-surface-color-theme-variants:
|
|
124
|
+
brand brand-on-light, danger danger-on-light, success success-on-light, warning warning-on-light;
|
|
117
125
|
--et-surface-interaction: 115 115 115;
|
|
118
126
|
--et-surface-interaction-hover: 64 64 64;
|
|
119
127
|
--et-surface-interaction-focus: 64 64 64;
|
|
@@ -259,6 +267,7 @@
|
|
|
259
267
|
}
|
|
260
268
|
|
|
261
269
|
.et-color--danger {
|
|
270
|
+
--et-color-theme-type: error;
|
|
262
271
|
--et-color-primary: 220 38 38;
|
|
263
272
|
--et-color-primary-hover: 185 28 28;
|
|
264
273
|
--et-color-primary-focus: 185 28 28;
|
|
@@ -279,6 +288,7 @@
|
|
|
279
288
|
}
|
|
280
289
|
|
|
281
290
|
.et-color--warning {
|
|
291
|
+
--et-color-theme-type: warning;
|
|
282
292
|
--et-color-primary: 217 119 6;
|
|
283
293
|
--et-color-primary-hover: 245 158 11;
|
|
284
294
|
--et-color-primary-focus: 245 158 11;
|
|
@@ -525,6 +535,8 @@
|
|
|
525
535
|
--et-surface-type: light;
|
|
526
536
|
--et-surface-elevation: 1;
|
|
527
537
|
--et-shadow-color-rgb: 23 23 23;
|
|
538
|
+
--et-surface-color-theme-variants:
|
|
539
|
+
brand brand-on-light, danger danger-on-light, success success-on-light, warning warning-on-light;
|
|
528
540
|
--et-surface-interaction: 115 115 115;
|
|
529
541
|
--et-surface-interaction-hover: 64 64 64;
|
|
530
542
|
--et-surface-interaction-focus: 64 64 64;
|
|
@@ -558,6 +570,8 @@
|
|
|
558
570
|
--et-surface-type: light;
|
|
559
571
|
--et-surface-elevation: 1;
|
|
560
572
|
--et-shadow-color-rgb: 23 23 23;
|
|
573
|
+
--et-surface-color-theme-variants:
|
|
574
|
+
brand brand-on-light, danger danger-on-light, success success-on-light, warning warning-on-light;
|
|
561
575
|
--et-surface-interaction: 115 115 115;
|
|
562
576
|
--et-surface-interaction-hover: 64 64 64;
|
|
563
577
|
--et-surface-interaction-focus: 64 64 64;
|
|
@@ -593,6 +607,8 @@
|
|
|
593
607
|
--et-surface-type: light;
|
|
594
608
|
--et-surface-elevation: 1;
|
|
595
609
|
--et-shadow-color-rgb: 23 23 23;
|
|
610
|
+
--et-surface-color-theme-variants:
|
|
611
|
+
brand brand-on-light, danger danger-on-light, success success-on-light, warning warning-on-light;
|
|
596
612
|
--et-surface-interaction: 115 115 115;
|
|
597
613
|
--et-surface-interaction-hover: 64 64 64;
|
|
598
614
|
--et-surface-interaction-focus: 64 64 64;
|
|
@@ -171,7 +171,7 @@ const render = (props: Props): Drawing => {
|
|
|
171
171
|
|
|
172
172
|
export default definePart<Props>({
|
|
173
173
|
note: 'The SDK colour tokens: a light and a dark surface, the demo colour themes brand, danger and warning with their on-light variants, and the AA contrast of text and fills. Every frame loads it before the part styles. Generated by tools/scripts/generate-sdk-tokens.mjs from the Storybook themes; never edit the CSS by hand.',
|
|
174
|
-
madeBy: ['claude-opus-5-5'],
|
|
174
|
+
madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5'],
|
|
175
175
|
states: {
|
|
176
176
|
'surface-light': { group: 'surface', surface: 'light' },
|
|
177
177
|
'surface-dark': { group: 'surface', surface: 'dark' },
|
|
@@ -38,7 +38,7 @@ const pair = (label: string, fill: string, ink: string, fixed: boolean) => {
|
|
|
38
38
|
const ratio = contrastRatio(fill, ink);
|
|
39
39
|
|
|
40
40
|
return html`<span class="sdk-pair" style="background: rgb(${fill}); color: rgb(${ink})">Aa</span>
|
|
41
|
-
<span class="sdk-pair-label${fixed ? '
|
|
41
|
+
<span class="sdk-pair-label ${fixed ? 'sdk-fixed' : ''}">${label}</span>
|
|
42
42
|
<code class="sdk-value">${fill} / ${ink}</code>
|
|
43
43
|
<strong class="sdk-ratio" data-pass="${ratio >= AA}"
|
|
44
44
|
>${ratio.toFixed(2)}:1 ${ratio >= AA ? 'AA' : 'below AA'}</strong
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"components/breadcrumb/breadcrumb.ts": { "@typescript-eslint/no-non-null-assertion": 1 },
|
|
3
|
+
"components/tabs/tabs.ts": { "@typescript-eslint/no-non-null-assertion": 1 },
|
|
4
|
+
"components/timeline/timeline.ts": { "@typescript-eslint/no-non-null-assertion": 1 },
|
|
5
|
+
"components/toolbar/toolbar.ts": { "@typescript-eslint/no-non-null-assertion": 1 }
|
|
6
|
+
}
|