@ethlete/components 1.0.0-next.78 → 1.0.0-next.80
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 +139 -0
- package/design/accordion.ts +73 -0
- package/design/anchored-dialog.ts +92 -0
- package/design/avatar.ts +90 -0
- package/design/badge.ts +48 -0
- package/design/banner.ts +77 -0
- package/design/bracket.ts +457 -0
- package/design/breadcrumb.ts +145 -0
- package/design/button.ts +62 -1
- package/design/calendar.ts +306 -0
- package/design/card.ts +92 -0
- package/design/carousel.ts +240 -0
- package/design/chart.ts +512 -0
- package/design/checkbox.ts +275 -0
- package/design/chip.ts +64 -0
- package/design/config.json +8 -0
- package/design/control.ts +19 -0
- package/design/copy-button.ts +59 -0
- package/design/description-list.ts +41 -0
- package/design/dialog.ts +216 -0
- package/design/divider.ts +27 -0
- package/design/empty-state.ts +45 -0
- package/design/floating-action.ts +55 -0
- package/design/form-field.ts +3 -0
- package/design/grid.ts +148 -0
- package/design/input.ts +86 -0
- package/design/kbd.ts +19 -0
- package/design/loader.ts +152 -0
- package/design/masonry.ts +115 -0
- package/design/match.ts +131 -0
- package/design/menu.ts +147 -0
- package/design/notification.ts +133 -0
- package/design/otp-input.ts +107 -0
- package/design/pagination.ts +120 -0
- package/design/picture.ts +80 -0
- package/design/progress-steps.ts +79 -0
- package/design/query-error.ts +60 -0
- package/design/radio-group.ts +132 -0
- package/design/scheduler.ts +369 -0
- package/design/scrollable.ts +218 -0
- package/design/scrollbar.ts +47 -0
- package/design/sdk/assets/fallback.svg +1 -0
- package/design/sdk/assets/tall.svg +1 -0
- package/design/sdk/assets/wide.svg +1 -0
- package/design/sdk/components/accent-on-light/accent-on-light.css +35 -0
- package/design/sdk/components/accent-on-light/accent-on-light.ts +10 -0
- package/design/sdk/components/accent-on-light/shared/controls.ts +46 -0
- package/design/sdk/components/accordion/accordion.css +17 -0
- package/design/sdk/components/accordion/accordion.ts +68 -0
- package/design/sdk/components/anchored-dialog/anchored-dialog.css +63 -0
- package/design/sdk/components/anchored-dialog/anchored-dialog.ts +65 -0
- package/design/sdk/components/avatar/avatar.css +14 -0
- package/design/sdk/components/avatar/avatar.ts +79 -0
- package/design/sdk/components/badge/badge.css +13 -0
- package/design/sdk/components/badge/badge.ts +53 -0
- package/design/sdk/components/banner/banner.css +18 -0
- package/design/sdk/components/banner/banner.ts +88 -0
- package/design/sdk/components/bracket/bracket.css +59 -0
- package/design/sdk/components/bracket/bracket.ts +144 -0
- package/design/sdk/components/breadcrumb/breadcrumb.css +25 -0
- package/design/sdk/components/breadcrumb/breadcrumb.ts +82 -0
- package/design/sdk/components/button/button.css +41 -0
- package/design/sdk/components/button/button.ts +59 -7
- package/design/sdk/components/calendar/calendar.css +33 -0
- package/design/sdk/components/calendar/calendar.ts +97 -0
- package/design/sdk/components/card/card.css +19 -0
- package/design/sdk/components/card/card.ts +62 -0
- package/design/sdk/components/carousel/carousel.css +44 -0
- package/design/sdk/components/carousel/carousel.ts +75 -0
- package/design/sdk/components/chart/chart.css +56 -0
- package/design/sdk/components/chart/chart.ts +99 -0
- package/design/sdk/components/checkbox/checkbox.css +65 -0
- package/design/sdk/components/checkbox/checkbox.ts +180 -0
- package/design/sdk/components/chip/chip.css +18 -0
- package/design/sdk/components/chip/chip.ts +77 -0
- package/design/sdk/components/copy-button/copy-button.css +14 -0
- package/design/sdk/components/copy-button/copy-button.ts +60 -0
- package/design/sdk/components/description-list/description-list.css +7 -0
- package/design/sdk/components/description-list/description-list.ts +54 -0
- package/design/sdk/components/dialog/dialog.css +29 -0
- package/design/sdk/components/dialog/dialog.ts +79 -0
- package/design/sdk/components/divider/divider.css +26 -0
- package/design/sdk/components/divider/divider.ts +44 -0
- package/design/sdk/components/empty-state/empty-state.css +15 -0
- package/design/sdk/components/empty-state/empty-state.ts +57 -0
- package/design/sdk/components/floating-action/floating-action.css +51 -0
- package/design/sdk/components/floating-action/floating-action.ts +63 -0
- package/design/sdk/components/form-field/form-field.ts +23 -5
- package/design/sdk/components/grid/grid.css +17 -0
- package/design/sdk/components/grid/grid.ts +81 -0
- package/design/sdk/components/input/input.css +75 -0
- package/design/sdk/components/input/input.ts +80 -0
- package/design/sdk/components/kbd/kbd.css +25 -0
- package/design/sdk/components/kbd/kbd.ts +58 -0
- package/design/sdk/components/loader/loader.css +37 -0
- package/design/sdk/components/loader/loader.ts +69 -0
- package/design/sdk/components/masonry/masonry.css +7 -0
- package/design/sdk/components/masonry/masonry.ts +43 -0
- package/design/sdk/components/match/match.css +25 -0
- package/design/sdk/components/match/match.ts +77 -0
- package/design/sdk/components/menu/menu.css +22 -0
- package/design/sdk/components/menu/menu.ts +103 -0
- package/design/sdk/components/notification/notification.css +32 -0
- package/design/sdk/components/notification/notification.ts +107 -0
- package/design/sdk/components/otp-input/otp-input.css +35 -0
- package/design/sdk/components/otp-input/otp-input.ts +65 -0
- package/design/sdk/components/pagination/pagination.css +14 -0
- package/design/sdk/components/pagination/pagination.ts +76 -0
- package/design/sdk/components/picture/picture.css +37 -0
- package/design/sdk/components/picture/picture.ts +97 -0
- package/design/sdk/components/progress-steps/progress-steps.css +37 -0
- package/design/sdk/components/progress-steps/progress-steps.ts +92 -0
- package/design/sdk/components/query-error/query-error.css +33 -0
- package/design/sdk/components/query-error/query-error.ts +121 -0
- 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.css +55 -0
- package/design/sdk/components/scheduler/scheduler.ts +240 -0
- package/design/sdk/components/scrollable/scrollable.css +58 -0
- package/design/sdk/components/scrollable/scrollable.ts +133 -0
- package/design/sdk/components/scrollbar/scrollbar.css +78 -0
- package/design/sdk/components/scrollbar/scrollbar.ts +124 -0
- package/design/sdk/components/select/select.ts +1 -1
- package/design/sdk/components/select/shared/select-part.ts +25 -3
- package/design/sdk/components/select-panel/select-panel.css +3 -0
- package/design/sdk/components/select-panel/select-panel.ts +125 -0
- package/design/sdk/components/skeleton/skeleton.css +22 -0
- package/design/sdk/components/skeleton/skeleton.ts +51 -0
- package/design/sdk/components/slider/slider.css +52 -0
- package/design/sdk/components/slider/slider.ts +87 -0
- package/design/sdk/components/standings/standings.css +33 -0
- package/design/sdk/components/standings/standings.ts +131 -0
- package/design/sdk/components/stat-tile/stat-tile.css +15 -0
- package/design/sdk/components/stat-tile/stat-tile.ts +85 -0
- package/design/sdk/components/stream/stream.css +48 -0
- package/design/sdk/components/stream/stream.ts +43 -0
- package/design/sdk/components/switch/switch.css +37 -0
- package/design/sdk/components/switch/switch.ts +63 -0
- package/design/sdk/components/table/table.css +67 -0
- package/design/sdk/components/table/table.ts +161 -0
- package/design/sdk/components/tabs/tabs.css +13 -0
- package/design/sdk/components/tabs/tabs.ts +74 -0
- package/design/sdk/components/textarea/textarea.css +116 -0
- package/design/sdk/components/textarea/textarea.ts +65 -0
- package/design/sdk/components/timeline/timeline.css +30 -0
- package/design/sdk/components/timeline/timeline.ts +87 -0
- package/design/sdk/components/toolbar/toolbar.css +24 -0
- package/design/sdk/components/toolbar/toolbar.ts +88 -0
- package/design/sdk/components/tooltip/tooltip.css +15 -0
- package/design/sdk/components/tooltip/tooltip.ts +28 -0
- package/design/sdk/components/tree/selected-tint.css +15 -0
- package/design/sdk/components/tree/tree.ts +70 -0
- package/design/sdk/foundations/colors/colors.css +124 -4
- package/design/sdk/foundations/colors/colors.ts +1 -1
- package/design/sdk/foundations/colors/shared/contrast.ts +1 -1
- package/design/sdk/foundations/elevation/elevation.css +6 -0
- package/design/sdk/foundations/elevation/elevation.ts +11 -0
- package/design/sdk/foundations/elevation/shared/elevation/scene.css +101 -0
- package/design/sdk/foundations/elevation/shared/elevation/scene.ts +74 -0
- package/design/sdk/foundations/icons/icons.ts +119 -0
- package/design/sdk/pictures.json +1183 -0
- package/design/select.ts +5 -4
- package/design/skeleton.ts +67 -0
- package/design/slider.ts +155 -0
- package/design/standings.ts +161 -0
- package/design/stat-tile.ts +109 -0
- package/design/stream.ts +92 -0
- package/design/switch.ts +83 -0
- package/design/table.ts +302 -0
- package/design/tabs.ts +75 -0
- package/design/textarea.ts +94 -0
- package/design/timeline.ts +52 -0
- package/design/toolbar.ts +95 -0
- package/design/tooltip.ts +87 -0
- package/fesm2022/ethlete-components.mjs +1440 -1209
- package/fesm2022/ethlete-components.mjs.map +1 -1
- package/generators/generators.json +2 -0
- package/package.json +1 -1
- package/src/lib/accordion/accordion.component.css +2 -1
- package/src/lib/avatar/avatar.component.css +10 -0
- package/src/lib/badge/badge.component.css +2 -2
- package/src/lib/banner/banner.component.css +3 -1
- package/src/lib/breadcrumb/breadcrumb-outlet.component.css +5 -0
- package/src/lib/breadcrumb/breadcrumb.component.css +5 -1
- package/src/lib/button/button-properties-styles.component.css +6 -6
- package/src/lib/button/button.component.css +27 -4
- package/src/lib/button/button.types.ts +33 -0
- package/src/lib/button/icon-button.component.css +21 -22
- package/src/lib/button/split-button.component.css +5 -1
- package/src/lib/button/window-control-button.component.css +43 -3
- package/src/lib/calendar/calendar.component.css +15 -5
- package/src/lib/card/card.component.css +4 -0
- package/src/lib/carousel/carousel-autoplay-styles.component.css +1 -1
- package/src/lib/carousel/carousel.component.css +2 -2
- package/src/lib/chart/chart-axis.component.css +3 -3
- package/src/lib/chip/chip.component.css +12 -6
- package/src/lib/description-list/description-list.component.css +2 -1
- package/src/lib/empty-state/empty-state.component.css +4 -0
- package/src/lib/floating-action/floating-action-styles.component.css +27 -0
- package/src/lib/focus-ring/focus-ring-styles.component.css +4 -1
- package/src/lib/forms/checkbox/checkbox.component.css +31 -5
- package/src/lib/forms/color-input/color-input.component.css +3 -1
- package/src/lib/forms/color-input/color-picker-panel.component.css +6 -2
- package/src/lib/forms/date-time/date-input/date-input.component.css +1 -1
- package/src/lib/forms/date-time/date-time-input/date-time-input.component.css +1 -1
- package/src/lib/forms/date-time/duration-input/duration-input.component.css +1 -1
- package/src/lib/forms/date-time/range-input-shell-styles.component.css +1 -1
- package/src/lib/forms/date-time/time-input/time-input.component.css +1 -1
- package/src/lib/forms/description/description.component.css +7 -0
- package/src/lib/forms/dropzone/dropzone.component.css +26 -0
- package/src/lib/forms/form-field/form-field-control-suffix-styles.component.css +4 -2
- package/src/lib/forms/form-field/form-field-text-shell-styles.component.css +54 -5
- package/src/lib/forms/form-field/form-field-textarea-styles.component.css +62 -0
- package/src/lib/forms/form-field/form-field.component.css +6 -0
- package/src/lib/forms/form-field/headless/label.directive.css +1 -1
- package/src/lib/forms/input/input.component.css +6 -2
- package/src/lib/forms/input/number-input.component.css +2 -2
- package/src/lib/forms/input/password-input.component.css +4 -3
- package/src/lib/forms/otp-input/otp-input.component.css +23 -4
- package/src/lib/forms/phone-input/phone-input.component.css +4 -3
- package/src/lib/forms/rating/rating.component.css +2 -1
- package/src/lib/forms/rich-text-editor/rich-text-editor.component.css +1 -1
- package/src/lib/forms/selection-card-styles.component.css +3 -2
- package/src/lib/forms/selection-list/checkbox-group/checkbox-group-select-all.component.css +4 -2
- package/src/lib/forms/selection-list/checkbox-group/checkbox-option.component.css +4 -2
- package/src/lib/forms/selection-list/radio-group/radio.component.css +5 -2
- package/src/lib/forms/selection-list/segmented-button-group/segmented-button.component.css +2 -1
- package/src/lib/forms/slider/range-slider.component.css +98 -6
- package/src/lib/forms/slider/slider.component.css +96 -4
- package/src/lib/forms/switch/switch.component.css +45 -15
- package/src/lib/forms/tag-input/tag-input.component.css +2 -2
- package/src/lib/forms/textarea/textarea-autosize-styles.component.css +2 -3
- package/src/lib/forms/textarea/textarea.component.css +7 -2
- package/src/lib/grid/grid-item-toolbar.component.css +10 -0
- package/src/lib/grid/grid-item.component.css +6 -1
- package/src/lib/kbd/kbd.component.css +1 -1
- package/src/lib/loader/brand-loader/brand-loader.component.css +4 -1
- package/src/lib/loader/progress-bar/progress-bar.component.css +1 -1
- package/src/lib/loader/spinner/spinner-styles.component.css +1 -1
- package/src/lib/match/match-card.component.css +9 -3
- package/src/lib/match/match-score.component.css +4 -1
- package/src/lib/menu/menu-selection-item.component.css +1 -1
- package/src/lib/menu/menu.component.css +6 -1
- package/src/lib/notification/notification.component.css +3 -3
- package/src/lib/overlay/overlay-container.component.css +4 -0
- package/src/lib/pagination/pagination.component.css +4 -0
- package/src/lib/progress-steps/progress-step.component.css +4 -4
- package/src/lib/query-error/query-error.component.css +4 -0
- package/src/lib/scheduler/scheduler-appointment-styles.component.css +21 -5
- package/src/lib/scheduler/scheduler-month-view.component.css +4 -2
- package/src/lib/scheduler/scheduler-time-grid-view.component.css +8 -2
- package/src/lib/scrollable/headless/scrollable-navigation.component.css +1 -1
- package/src/lib/standings/standings-pick.component.css +1 -1
- package/src/lib/standings/standings.component.css +10 -10
- package/src/lib/stat-tile/stat-tile-sparkline.component.css +1 -1
- package/src/lib/stream/consent/stream-consent.component.css +99 -0
- package/src/lib/stream/error/stream-player-error.component.css +100 -0
- package/src/lib/stream/loading/stream-player-loading.component.css +16 -0
- package/src/lib/stream/pip/pip-slot-placeholder.component.css +68 -0
- package/src/lib/stream/stream-player-slot-styles.component.css +4 -0
- package/src/lib/table/table-resize-grip.component.css +2 -1
- package/src/lib/table/table-select-cell.component.css +45 -15
- package/src/lib/table/table.component.css +15 -5
- package/src/lib/tabs/tab-bar-styles.component.css +1 -1
- package/src/lib/tabs/tabs/tab-group.component.css +111 -0
- package/src/lib/time-picker/time-picker.component.css +2 -1
- package/src/lib/timeline/timeline-item.component.css +5 -1
- package/src/lib/toolbar/toolbar.component.css +4 -0
- package/src/lib/tooltip/tooltip.component.css +14 -0
- package/types/ethlete-components.d.ts +156 -128
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pagination,
|
|
3
|
+
type PaginationMockItem,
|
|
4
|
+
type PaginationMockOptions,
|
|
5
|
+
paginationStyles,
|
|
6
|
+
} from '@ethlete/components/design/pagination';
|
|
7
|
+
import { definePart, drawing, interactionRows } from '@design-system';
|
|
8
|
+
import edge from './pagination.css?inline';
|
|
9
|
+
|
|
10
|
+
type ItemInteraction = 'hover' | 'active' | 'focus-visible';
|
|
11
|
+
|
|
12
|
+
type Props = Omit<PaginationMockOptions, 'items'> & {
|
|
13
|
+
page: number;
|
|
14
|
+
pages: (number | null)[];
|
|
15
|
+
total: number;
|
|
16
|
+
target?: number;
|
|
17
|
+
forced?: ItemInteraction;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const MARK = 'data-et-control="item" data-can-animate';
|
|
21
|
+
|
|
22
|
+
const items = ({ page, pages, total, target, forced }: Props): PaginationMockItem[] => {
|
|
23
|
+
const attributes = (entry: number) => (forced && entry === target ? `${MARK} data-et-force="${forced}"` : MARK);
|
|
24
|
+
|
|
25
|
+
return [
|
|
26
|
+
{ type: 'first', page: 1, disabled: page === 1, attributes: MARK },
|
|
27
|
+
{ type: 'previous', page: page - 1, disabled: page === 1, attributes: MARK },
|
|
28
|
+
...pages.map((entry): PaginationMockItem =>
|
|
29
|
+
entry === null
|
|
30
|
+
? { type: 'ellipsis' }
|
|
31
|
+
: { type: 'page', page: entry, current: entry === page, attributes: attributes(entry) },
|
|
32
|
+
),
|
|
33
|
+
{ type: 'next', page: page + 1, disabled: page === total, attributes: MARK },
|
|
34
|
+
{ type: 'last', page: total, disabled: page === total, attributes: MARK },
|
|
35
|
+
];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const MIDDLE: Props = { page: 10, total: 20, pages: [1, null, 9, 10, 11, null, 20] };
|
|
39
|
+
|
|
40
|
+
const { states, grid } = interactionRows(
|
|
41
|
+
{
|
|
42
|
+
page: { ...MIDDLE, target: 11 },
|
|
43
|
+
current: { ...MIDDLE, target: 10 },
|
|
44
|
+
} satisfies Record<string, Props>,
|
|
45
|
+
{
|
|
46
|
+
interactions: ['hover', 'active', 'focus-visible'],
|
|
47
|
+
force: (props: Props, interaction: ItemInteraction): Props => ({ ...props, forced: interaction }),
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export default definePart({
|
|
52
|
+
note: 'Decided rules only',
|
|
53
|
+
madeBy: ['claude-opus-5-5'],
|
|
54
|
+
states: {
|
|
55
|
+
first: { page: 1, total: 20, pages: [1, 2, 3, 4, 5, null, 20] },
|
|
56
|
+
middle: MIDDLE,
|
|
57
|
+
last: { page: 20, total: 20, pages: [1, null, 16, 17, 18, 19, 20] },
|
|
58
|
+
few: { page: 2, total: 5, pages: [1, 2, 3, 4, 5] },
|
|
59
|
+
...states,
|
|
60
|
+
range: { ...MIDDLE, range: 'Showing 91–100 of 200' },
|
|
61
|
+
sm: { ...MIDDLE, size: 'sm' },
|
|
62
|
+
links: { ...MIDDLE, renderAs: 'links' },
|
|
63
|
+
compact: { ...MIDDLE, compactStatus: '10 / 20' },
|
|
64
|
+
},
|
|
65
|
+
grid,
|
|
66
|
+
widths: [480],
|
|
67
|
+
controls: {
|
|
68
|
+
item: { kind: 'button', input: ['pointer', 'keyboard'], disabled: true },
|
|
69
|
+
},
|
|
70
|
+
frame: (body) => `<div class="pagination-frame">${body}</div>`,
|
|
71
|
+
render: (props: Props) =>
|
|
72
|
+
drawing({
|
|
73
|
+
body: pagination({ ...props, items: items(props) }),
|
|
74
|
+
styles: [paginationStyles, edge].join('\n'),
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.picture-frame {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: 0.8rem;
|
|
5
|
+
max-inline-size: 520px;
|
|
6
|
+
padding: 2.4rem 1.6rem;
|
|
7
|
+
background: var(--et-surface-background-solid);
|
|
8
|
+
color: var(--et-surface-color-solid);
|
|
9
|
+
font-size: 1.4rem;
|
|
10
|
+
|
|
11
|
+
.picture-error {
|
|
12
|
+
margin: 0;
|
|
13
|
+
color: var(--et-surface-color-muted-solid);
|
|
14
|
+
font-size: 1.2rem;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.picture-fit-grid {
|
|
18
|
+
display: grid;
|
|
19
|
+
grid-template-columns: repeat(2, 180px);
|
|
20
|
+
gap: 1.6rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.picture-fit-cell {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
gap: 0.4rem;
|
|
27
|
+
margin: 0;
|
|
28
|
+
font-size: 1.2rem;
|
|
29
|
+
color: var(--et-surface-color-muted-solid);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.picture-fit-cell .et-picture {
|
|
33
|
+
inline-size: 180px;
|
|
34
|
+
block-size: 120px;
|
|
35
|
+
outline: 1px dashed var(--et-surface-border-solid);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { picture, pictureStyles, type PictureMockOptions } from '@ethlete/components/design/picture';
|
|
2
|
+
import { skeletonItem, skeletonStyles } from '@ethlete/components/design/skeleton';
|
|
3
|
+
import { definePart, drawing } from '@design-system';
|
|
4
|
+
import fallback from '@assets/fallback.svg?raw';
|
|
5
|
+
import tall from '@assets/tall.svg?raw';
|
|
6
|
+
import wide from '@assets/wide.svg?raw';
|
|
7
|
+
import frame from './picture.css?inline';
|
|
8
|
+
|
|
9
|
+
const svgUrl = (markup: string) => `data:image/svg+xml;utf8,${encodeURIComponent(markup.trim())}`;
|
|
10
|
+
|
|
11
|
+
type Fit = NonNullable<PictureMockOptions['fit']>;
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
ratio?: string;
|
|
15
|
+
caption?: 'short' | 'long' | 'none';
|
|
16
|
+
intrinsic?: boolean;
|
|
17
|
+
loading?: boolean;
|
|
18
|
+
error?: 'slot' | 'bare';
|
|
19
|
+
fit?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const WIDE = svgUrl(wide);
|
|
23
|
+
const TALL = svgUrl(tall);
|
|
24
|
+
const FALLBACK = svgUrl(fallback);
|
|
25
|
+
const BROKEN = 'data:image/png;base64,this-is-not-an-image';
|
|
26
|
+
|
|
27
|
+
const CAPTIONS = {
|
|
28
|
+
short: 'A crop that follows the viewport.',
|
|
29
|
+
long: 'Fulltime at the home ground: the visitors celebrate in front of the away end after the late winner, while the stewards hold the line and the floodlights come on over the north stand.',
|
|
30
|
+
none: undefined,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const FITS: Fit[] = ['contain', 'cover', 'fill', 'none', 'scale-down'];
|
|
34
|
+
|
|
35
|
+
const body = ({ ratio = '16 / 9', caption = 'short', intrinsic, loading, error, fit }: Props) => {
|
|
36
|
+
if (fit) {
|
|
37
|
+
const cells = FITS.map(
|
|
38
|
+
(mode) =>
|
|
39
|
+
`<figure class="picture-fit-cell">${picture({ src: FALLBACK, alt: `fit ${mode}`, fit: mode })}<span>${mode}</span></figure>`,
|
|
40
|
+
).join('');
|
|
41
|
+
|
|
42
|
+
return `<div class="picture-fit-grid">${cells}</div>`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (loading) {
|
|
46
|
+
return picture({
|
|
47
|
+
alt: 'An image whose URL arrives after the page',
|
|
48
|
+
aspectRatio: '16 / 9',
|
|
49
|
+
state: 'loading',
|
|
50
|
+
placeholder: skeletonItem({ shape: 'rect', style: 'block-size: 100%; inline-size: 100%' }),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (error) {
|
|
55
|
+
return picture({
|
|
56
|
+
src: BROKEN,
|
|
57
|
+
alt: 'An image that fails to load',
|
|
58
|
+
aspectRatio: '16 / 9',
|
|
59
|
+
state: 'error',
|
|
60
|
+
error: error === 'slot' ? '<p class="picture-error">This image is unavailable.</p>' : undefined,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return picture({
|
|
65
|
+
sources: intrinsic ? undefined : [{ srcset: WIDE, media: '(min-width: 700px)' }, { srcset: TALL }],
|
|
66
|
+
src: FALLBACK,
|
|
67
|
+
alt: 'A coloured block labelled with its aspect ratio',
|
|
68
|
+
aspectRatio: ratio === 'none' ? undefined : ratio,
|
|
69
|
+
width: intrinsic ? 800 : undefined,
|
|
70
|
+
height: intrinsic ? 450 : undefined,
|
|
71
|
+
figcaption: CAPTIONS[caption],
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export default definePart({
|
|
76
|
+
note: "Today's look",
|
|
77
|
+
madeBy: ['claude-opus-5-5'],
|
|
78
|
+
states: {
|
|
79
|
+
default: {},
|
|
80
|
+
'ratio-4-3': { ratio: '4 / 3' },
|
|
81
|
+
'no-ratio': { ratio: 'none' },
|
|
82
|
+
'width-height': { intrinsic: true },
|
|
83
|
+
'no-caption': { caption: 'none' },
|
|
84
|
+
'long-caption': { caption: 'long' },
|
|
85
|
+
fit: { fit: true },
|
|
86
|
+
loading: { loading: true },
|
|
87
|
+
'error-slot': { error: 'slot' },
|
|
88
|
+
'error-bare': { error: 'bare' },
|
|
89
|
+
},
|
|
90
|
+
widths: [480],
|
|
91
|
+
frame: (body) => `<div class="picture-frame">${body}</div>`,
|
|
92
|
+
render: (props: Props) =>
|
|
93
|
+
drawing({
|
|
94
|
+
body: body(props),
|
|
95
|
+
styles: [skeletonStyles, pictureStyles, frame].join('\n'),
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.progress-steps-frame {
|
|
2
|
+
padding: 2.4rem 1.6rem;
|
|
3
|
+
background: var(--et-surface-background-solid);
|
|
4
|
+
color: var(--et-surface-color-solid);
|
|
5
|
+
font-size: 1.4rem;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@layer components {
|
|
9
|
+
.et-progress-step {
|
|
10
|
+
--_et-focus-ring-color: var(--et-theme-color-ink-solid);
|
|
11
|
+
|
|
12
|
+
&:is(
|
|
13
|
+
[data-state='current'],
|
|
14
|
+
[data-state='complete'],
|
|
15
|
+
[data-state='success'],
|
|
16
|
+
[data-state='warning'],
|
|
17
|
+
[data-state='error']
|
|
18
|
+
)
|
|
19
|
+
.et-progress-step-marker {
|
|
20
|
+
border-color: var(--et-theme-color-ink-solid);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&:is([data-state='complete'], [data-state='success'], [data-state='warning'], [data-state='error']):not(
|
|
24
|
+
:last-child
|
|
25
|
+
)::after {
|
|
26
|
+
background: var(--et-theme-color-ink-solid);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&:is(a, button) {
|
|
30
|
+
@media (hover: hover) {
|
|
31
|
+
&:hover .et-progress-step-marker {
|
|
32
|
+
border-color: var(--et-theme-color-ink-solid);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { progressSteps, ProgressStepMockStep, progressStepsStyles } from '@ethlete/components/design/progress-steps';
|
|
2
|
+
import { definePart, drawing } from '@design-system';
|
|
3
|
+
import frame from './progress-steps.css?inline';
|
|
4
|
+
|
|
5
|
+
type Interaction = 'hover' | 'active' | 'focus-visible';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
set?: 'checkout' | 'outcomes' | 'described' | 'vertical' | 'links';
|
|
9
|
+
complete?: Interaction;
|
|
10
|
+
upcoming?: Interaction;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const mark = (control: string, interaction?: Interaction) =>
|
|
14
|
+
[`data-et-control="${control}"`, interaction && `data-et-force="${interaction}"`].filter(Boolean).join(' ');
|
|
15
|
+
|
|
16
|
+
const checkout: ProgressStepMockStep[] = [
|
|
17
|
+
{ label: 'Account', state: 'complete' },
|
|
18
|
+
{ label: 'Shipping', state: 'current' },
|
|
19
|
+
{ label: 'Payment' },
|
|
20
|
+
{ label: 'Review' },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const outcomes: ProgressStepMockStep[] = [
|
|
24
|
+
{ label: 'Upload', state: 'success' },
|
|
25
|
+
{ label: 'Validate', state: 'warning', color: 'warning' },
|
|
26
|
+
{ label: 'Import', state: 'error', color: 'danger' },
|
|
27
|
+
{ label: 'Publish' },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const described: ProgressStepMockStep[] = [
|
|
31
|
+
{ label: 'Team', state: 'complete', description: '18 players' },
|
|
32
|
+
{ label: 'Squad', state: 'error', color: 'danger', description: '2 missing' },
|
|
33
|
+
{ label: 'Kit', state: 'current', description: 'Home colours' },
|
|
34
|
+
{ label: 'Submit', description: 'By Friday' },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const vertical: ProgressStepMockStep[] = [
|
|
38
|
+
{ label: 'Registration received', state: 'complete', description: 'Mon, 12 Oct' },
|
|
39
|
+
{ label: 'Documents checked', state: 'warning', color: 'warning', description: 'Photo is blurry' },
|
|
40
|
+
{ label: 'Payment', state: 'current', description: 'Waiting for the transfer' },
|
|
41
|
+
{ label: 'Licence issued' },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const links = (props: Props): ProgressStepMockStep[] => [
|
|
45
|
+
{ label: 'Account', state: 'complete', as: 'a', attributes: mark('complete', props.complete) },
|
|
46
|
+
{ label: 'Shipping', state: 'current', as: 'a' },
|
|
47
|
+
{ label: 'Payment', as: 'a', attributes: mark('upcoming', props.upcoming) },
|
|
48
|
+
{ label: 'Review', as: 'a' },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const steps = (props: Props) => {
|
|
52
|
+
switch (props.set) {
|
|
53
|
+
case 'outcomes':
|
|
54
|
+
return progressSteps({ steps: outcomes });
|
|
55
|
+
case 'described':
|
|
56
|
+
return progressSteps({ steps: described });
|
|
57
|
+
case 'vertical':
|
|
58
|
+
return progressSteps({ steps: vertical, orientation: 'vertical' });
|
|
59
|
+
case 'links':
|
|
60
|
+
return progressSteps({ steps: links(props) });
|
|
61
|
+
default:
|
|
62
|
+
return progressSteps({ steps: checkout });
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default definePart({
|
|
67
|
+
note: 'Decided rules only',
|
|
68
|
+
madeBy: ['claude-opus-5-5'],
|
|
69
|
+
states: {
|
|
70
|
+
default: {},
|
|
71
|
+
outcomes: { set: 'outcomes' },
|
|
72
|
+
described: { set: 'described' },
|
|
73
|
+
vertical: { set: 'vertical' },
|
|
74
|
+
links: { set: 'links' },
|
|
75
|
+
'upcoming-hover': { set: 'links', upcoming: 'hover' },
|
|
76
|
+
'upcoming-active': { set: 'links', upcoming: 'active' },
|
|
77
|
+
'upcoming-focus-visible': { set: 'links', upcoming: 'focus-visible' },
|
|
78
|
+
'complete-hover': { set: 'links', complete: 'hover' },
|
|
79
|
+
'complete-focus-visible': { set: 'links', complete: 'focus-visible' },
|
|
80
|
+
},
|
|
81
|
+
widths: [480],
|
|
82
|
+
controls: {
|
|
83
|
+
complete: { kind: 'button', input: ['pointer', 'keyboard'] },
|
|
84
|
+
upcoming: { kind: 'button', input: ['pointer', 'keyboard'] },
|
|
85
|
+
},
|
|
86
|
+
frame: (body) => `<div class="progress-steps-frame">${body}</div>`,
|
|
87
|
+
render: (props: Props) =>
|
|
88
|
+
drawing({
|
|
89
|
+
body: steps(props),
|
|
90
|
+
styles: [progressStepsStyles, frame].join('\n'),
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.query-error-frame {
|
|
2
|
+
max-inline-size: 520px;
|
|
3
|
+
padding: 2.4rem 1.6rem;
|
|
4
|
+
background: var(--et-surface-background-solid);
|
|
5
|
+
color: var(--et-surface-color-solid);
|
|
6
|
+
font-size: 1.4rem;
|
|
7
|
+
|
|
8
|
+
.query-error-support {
|
|
9
|
+
color: inherit;
|
|
10
|
+
font-size: 1.2rem;
|
|
11
|
+
text-decoration: underline;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@layer components {
|
|
16
|
+
.et-banner {
|
|
17
|
+
border-color: var(--et-theme-color-ink-solid);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.et-button {
|
|
21
|
+
--_et-focus-ring-color: var(--et-theme-color-ink-solid);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.et-button:where([data-variant='filled']) {
|
|
25
|
+
--et-button-shadow: inset 0 0 0 1px var(--et-theme-color-ink-solid);
|
|
26
|
+
|
|
27
|
+
@media (hover: hover) {
|
|
28
|
+
&:hover {
|
|
29
|
+
--et-theme-color-primary-rgb: var(--et-color-primary-active);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { button } from '@ethlete/components/design/button';
|
|
2
|
+
import { queryError, queryErrorStyles } from '@ethlete/components/design/query-error';
|
|
3
|
+
import { definePart, drawing } from '@design-system';
|
|
4
|
+
import frame from './query-error.css?inline';
|
|
5
|
+
|
|
6
|
+
type Interaction = 'hover' | 'active' | 'focus-visible';
|
|
7
|
+
|
|
8
|
+
type Shape = 'message' | 'violations' | 'classValidator' | 'retryable' | 'empty' | 'echoesTitle' | 'network' | 'long';
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
shape: Shape;
|
|
12
|
+
alwaysAllowRetry?: boolean;
|
|
13
|
+
slots?: boolean;
|
|
14
|
+
color?: string;
|
|
15
|
+
retry?: Interaction;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const SHAPES: Record<Shape, { status: number; title: string; messages: string[]; canRetry: boolean }> = {
|
|
19
|
+
message: { status: 403, title: 'Forbidden', messages: ['You do not have access to this team.'], canRetry: false },
|
|
20
|
+
violations: {
|
|
21
|
+
status: 422,
|
|
22
|
+
title: 'Unprocessable entity',
|
|
23
|
+
messages: ['A name is required.', 'The email address is not valid.', 'The start date must be before the end date.'],
|
|
24
|
+
canRetry: false,
|
|
25
|
+
},
|
|
26
|
+
classValidator: {
|
|
27
|
+
status: 400,
|
|
28
|
+
title: 'Bad request',
|
|
29
|
+
messages: ['name should not be empty', 'email must be an email'],
|
|
30
|
+
canRetry: false,
|
|
31
|
+
},
|
|
32
|
+
retryable: {
|
|
33
|
+
status: 503,
|
|
34
|
+
title: 'Service unavailable',
|
|
35
|
+
messages: ['The service is briefly unavailable.'],
|
|
36
|
+
canRetry: true,
|
|
37
|
+
},
|
|
38
|
+
empty: {
|
|
39
|
+
status: 500,
|
|
40
|
+
title: 'Internal server error',
|
|
41
|
+
messages: ['Something went wrong on our end. Please try again later. (Code: 500)'],
|
|
42
|
+
canRetry: false,
|
|
43
|
+
},
|
|
44
|
+
echoesTitle: {
|
|
45
|
+
status: 404,
|
|
46
|
+
title: 'Not found',
|
|
47
|
+
messages: ['The requested resource was not found. (Code: 404)'],
|
|
48
|
+
canRetry: false,
|
|
49
|
+
},
|
|
50
|
+
network: {
|
|
51
|
+
status: 0,
|
|
52
|
+
title: 'Something went wrong',
|
|
53
|
+
messages: ['Something went wrong. Check your internet connection and try again later. (Code: 0)'],
|
|
54
|
+
canRetry: true,
|
|
55
|
+
},
|
|
56
|
+
long: {
|
|
57
|
+
status: 409,
|
|
58
|
+
title: 'Conflict',
|
|
59
|
+
messages: [
|
|
60
|
+
'The fixture for matchday 14 was moved by another organiser while you were editing it, so your changes to the kick-off time, the venue and the referee assignment could not be saved. Reload the fixture and quote request league.example.com/fixtures/2026_matchday_14_home_visitors_edit_request_8f3a9c2e7b1d',
|
|
61
|
+
],
|
|
62
|
+
canRetry: false,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const mark = (control: string, interaction?: Interaction) =>
|
|
67
|
+
[`data-et-control="${control}" data-can-animate`, interaction && `data-et-force="${interaction}"`]
|
|
68
|
+
.filter(Boolean)
|
|
69
|
+
.join(' ');
|
|
70
|
+
|
|
71
|
+
const slotActions = (interaction?: Interaction) =>
|
|
72
|
+
button({ label: 'Try again', size: 'sm' }).replace('<button ', `<button ${mark('retry', interaction)} `) +
|
|
73
|
+
'<a class="query-error-support" href="#">Contact support</a>';
|
|
74
|
+
|
|
75
|
+
const render = ({ shape, alwaysAllowRetry, slots, color = 'danger', retry }: Props) => {
|
|
76
|
+
const { status, title, messages, canRetry } = SHAPES[shape];
|
|
77
|
+
|
|
78
|
+
return queryError({
|
|
79
|
+
status,
|
|
80
|
+
title: slots && status === 403 ? 'This team is private' : title,
|
|
81
|
+
messages,
|
|
82
|
+
color,
|
|
83
|
+
retry: !slots && (canRetry || alwaysAllowRetry) ? 'Retry' : undefined,
|
|
84
|
+
retryAttributes: mark('retry', retry),
|
|
85
|
+
actions: slots ? slotActions(retry) : undefined,
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default definePart({
|
|
90
|
+
note: 'Decided rules only',
|
|
91
|
+
madeBy: ['claude-opus-5-5'],
|
|
92
|
+
states: {
|
|
93
|
+
message: { shape: 'message' },
|
|
94
|
+
violations: { shape: 'violations' },
|
|
95
|
+
'class-validator': { shape: 'classValidator' },
|
|
96
|
+
retryable: { shape: 'retryable' },
|
|
97
|
+
'empty-body': { shape: 'empty' },
|
|
98
|
+
'echoes-title': { shape: 'echoesTitle' },
|
|
99
|
+
network: { shape: 'network' },
|
|
100
|
+
'always-allow-retry': { shape: 'echoesTitle', alwaysAllowRetry: true },
|
|
101
|
+
'long-message': { shape: 'long' },
|
|
102
|
+
'custom-slots': { shape: 'message', slots: true },
|
|
103
|
+
'retry-hover': { shape: 'retryable', retry: 'hover' },
|
|
104
|
+
'retry-active': { shape: 'retryable', retry: 'active' },
|
|
105
|
+
'retry-focus-visible': { shape: 'retryable', retry: 'focus-visible' },
|
|
106
|
+
'slot-retry-focus-visible': { shape: 'message', slots: true, retry: 'focus-visible' },
|
|
107
|
+
'brand-color': { shape: 'retryable', color: 'brand' },
|
|
108
|
+
'brand-retry-hover': { shape: 'retryable', color: 'brand', retry: 'hover' },
|
|
109
|
+
'brand-retry-focus-visible': { shape: 'retryable', color: 'brand', retry: 'focus-visible' },
|
|
110
|
+
},
|
|
111
|
+
widths: [480],
|
|
112
|
+
controls: {
|
|
113
|
+
retry: { kind: 'button', input: ['pointer', 'keyboard'] },
|
|
114
|
+
},
|
|
115
|
+
frame: (body) => `<div class="query-error-frame">${body}</div>`,
|
|
116
|
+
render: (props: Props) =>
|
|
117
|
+
drawing({
|
|
118
|
+
body: render(props),
|
|
119
|
+
styles: [queryErrorStyles, frame].join('\n'),
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
.t-frame {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
display: grid;
|
|
4
|
+
justify-items: start;
|
|
5
|
+
gap: 1.6rem;
|
|
6
|
+
padding: 1.6rem;
|
|
7
|
+
background: var(--et-surface-background-solid);
|
|
8
|
+
color: var(--et-surface-color-solid);
|
|
9
|
+
font-size: 1.4rem;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@layer components {
|
|
13
|
+
et-radio:focus-visible .et-radio-circle {
|
|
14
|
+
border-color: light-dark(var(--et-theme-color-ink-solid), var(--et-theme-color-primary-solid));
|
|
15
|
+
outline-color: var(--et-theme-color-ink-solid);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
et-radio[aria-checked='true'] .et-radio-circle,
|
|
19
|
+
et-radio-group[data-mixed] .et-radio-circle {
|
|
20
|
+
border-color: light-dark(var(--et-theme-color-ink-solid), var(--et-theme-color-primary-solid));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
et-radio[aria-checked='true'] .et-radio-circle::after {
|
|
24
|
+
outline: 1px solid light-dark(var(--et-theme-color-ink-solid), transparent);
|
|
25
|
+
outline-offset: -1px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
et-radio.et-selection-card:where([aria-checked='true']) {
|
|
29
|
+
border-color: light-dark(var(--et-theme-color-ink-solid), var(--et-theme-color-primary-solid));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
et-radio.et-selection-card:where(:focus-visible) {
|
|
33
|
+
border-color: light-dark(var(--et-theme-color-ink-solid), var(--et-theme-color-primary-solid));
|
|
34
|
+
outline-color: var(--et-theme-color-ink-solid);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@media (hover: hover) {
|
|
38
|
+
et-radio[aria-checked='true']:hover {
|
|
39
|
+
--et-theme-color-primary-rgb: var(--et-color-primary-active);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.et-label-required-marker {
|
|
44
|
+
color: var(--et-theme-color-ink-solid);
|
|
45
|
+
}
|
|
46
|
+
}
|