@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,132 @@
|
|
|
1
|
+
import { interactiveStyles } from '@ethlete/core/design/interactive-styles';
|
|
2
|
+
import description from '../src/lib/forms/description/description.component.css?inline';
|
|
3
|
+
import formSupport from '../src/lib/forms/form-field/form-support-styles.component.css?inline';
|
|
4
|
+
import label from '../src/lib/forms/form-field/headless/label.directive.css?inline';
|
|
5
|
+
import selectionCard from '../src/lib/forms/selection-card-styles.component.css?inline';
|
|
6
|
+
import radioGroupBase from '../src/lib/forms/selection-list/radio-group/radio-group.component.css?inline';
|
|
7
|
+
import radioBase from '../src/lib/forms/selection-list/radio-group/radio.component.css?inline';
|
|
8
|
+
|
|
9
|
+
/** An interaction a frame forces with the `data-et-force` design marker. */
|
|
10
|
+
export type RadioMockForce = 'hover' | 'focus-visible' | 'active';
|
|
11
|
+
|
|
12
|
+
export type RadioGroupMockOption = {
|
|
13
|
+
/** The option label, as HTML. */
|
|
14
|
+
label: string;
|
|
15
|
+
checked?: boolean;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/** The `et-description` under the label, as HTML. */
|
|
18
|
+
description?: string;
|
|
19
|
+
/** Forced interactions on this option. */
|
|
20
|
+
force?: RadioMockForce | RadioMockForce[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type RadioGroupMockOptions = {
|
|
24
|
+
options: RadioGroupMockOption[];
|
|
25
|
+
/** The group label, as HTML. */
|
|
26
|
+
label?: string;
|
|
27
|
+
/** The hint, as HTML. Hidden while an `error` shows. */
|
|
28
|
+
hint?: string;
|
|
29
|
+
/** The error message, as HTML. Draws the group touched and invalid. */
|
|
30
|
+
error?: string;
|
|
31
|
+
/** The color theme name the app registers for errors, e.g. `danger` in Storybook. */
|
|
32
|
+
errorColor?: string;
|
|
33
|
+
/** The bulk-edit state: no option reads as checked yet, whatever its `checked`. */
|
|
34
|
+
mixed?: boolean;
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
/** View-only: the normal look, without the interactive affordance. */
|
|
37
|
+
readonly?: boolean;
|
|
38
|
+
required?: boolean;
|
|
39
|
+
/** Unique per frame: the label, description and message ids derive from it. */
|
|
40
|
+
id?: string;
|
|
41
|
+
size?: 'sm' | 'md' | 'lg';
|
|
42
|
+
orientation?: 'vertical' | 'horizontal';
|
|
43
|
+
variant?: 'plain' | 'card';
|
|
44
|
+
/** Where a `card` option puts its circle. */
|
|
45
|
+
controlPosition?: 'start' | 'end';
|
|
46
|
+
/** A color theme name the app registers. */
|
|
47
|
+
color?: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** The stylesheets `radioGroup()` draws with: the real `et-radio-group`, `et-radio` and form support CSS. */
|
|
51
|
+
export const radioGroupStyles = /* @__PURE__ */ [
|
|
52
|
+
interactiveStyles,
|
|
53
|
+
label,
|
|
54
|
+
description,
|
|
55
|
+
formSupport,
|
|
56
|
+
selectionCard,
|
|
57
|
+
radioGroupBase,
|
|
58
|
+
radioBase,
|
|
59
|
+
].join('\n');
|
|
60
|
+
|
|
61
|
+
const forceList = (force: RadioMockForce | RadioMockForce[] | undefined) =>
|
|
62
|
+
force === undefined ? [] : Array.isArray(force) ? force : [force];
|
|
63
|
+
|
|
64
|
+
const forceMarker = (force: RadioMockForce[]) => force.length > 0 && `data-et-force="${force.join(' ')}"`;
|
|
65
|
+
|
|
66
|
+
/** Draws `<et-radio-group>` with its `<et-radio>`s as HTML, with the DOM the components render. */
|
|
67
|
+
export const radioGroup = (options: RadioGroupMockOptions) => {
|
|
68
|
+
const { id = 'radio-group', variant = 'plain' } = options;
|
|
69
|
+
const ids = { hint: `et-form-field-hint-${id}`, error: `et-form-field-error-${id}` };
|
|
70
|
+
const labelId = options.label !== undefined ? `et-label-${id}` : null;
|
|
71
|
+
const invalid = options.error !== undefined;
|
|
72
|
+
const supportId = invalid ? ids.error : options.hint !== undefined ? ids.hint : null;
|
|
73
|
+
const colorClass = invalid && options.errorColor ? options.errorColor : (options.color ?? 'inherited');
|
|
74
|
+
const enabled = (option: RadioGroupMockOption) => !options.disabled && !option.disabled;
|
|
75
|
+
const isChecked = (option: RadioGroupMockOption) => !options.mixed && !!option.checked;
|
|
76
|
+
const tabStop = options.options.find((o) => isChecked(o) && enabled(o)) ?? options.options.find(enabled);
|
|
77
|
+
|
|
78
|
+
const groupAttributes = [
|
|
79
|
+
`class="et-radio-group et-color--${colorClass}"`,
|
|
80
|
+
'role="radiogroup"',
|
|
81
|
+
invalid && 'aria-invalid="true"',
|
|
82
|
+
options.required && 'aria-required="true"',
|
|
83
|
+
supportId && `aria-describedby="${supportId}"`,
|
|
84
|
+
labelId && `aria-labelledby="${labelId}"`,
|
|
85
|
+
options.disabled && 'data-disabled="true"',
|
|
86
|
+
options.mixed && 'data-mixed="true"',
|
|
87
|
+
options.readonly && 'aria-readonly="true" data-readonly="true"',
|
|
88
|
+
`data-size="${options.size ?? 'md'}"`,
|
|
89
|
+
`data-orientation="${options.orientation ?? 'vertical'}"`,
|
|
90
|
+
invalid && 'data-error="true"',
|
|
91
|
+
].filter(Boolean);
|
|
92
|
+
|
|
93
|
+
const items = options.options
|
|
94
|
+
.map((option, index) => {
|
|
95
|
+
const optionLabelId = `et-selection-option-label-${id}-${index}`;
|
|
96
|
+
const descriptionId = option.description !== undefined ? `et-description-${id}-${index}` : null;
|
|
97
|
+
const attributes = [
|
|
98
|
+
`class="et-color-interactive et-radio${variant === 'card' ? ' et-selection-card' : ''}"`,
|
|
99
|
+
'role="radio"',
|
|
100
|
+
`aria-checked="${isChecked(option)}"`,
|
|
101
|
+
`aria-labelledby="${optionLabelId}"`,
|
|
102
|
+
descriptionId && `aria-describedby="${descriptionId}"`,
|
|
103
|
+
!enabled(option) && 'aria-disabled="true"',
|
|
104
|
+
options.readonly && 'data-readonly="true"',
|
|
105
|
+
`tabindex="${option === tabStop ? 0 : -1}"`,
|
|
106
|
+
`data-variant="${variant}"`,
|
|
107
|
+
variant === 'card' && `data-control-position="${options.controlPosition ?? 'end'}"`,
|
|
108
|
+
forceMarker(forceList(option.force)),
|
|
109
|
+
].filter(Boolean);
|
|
110
|
+
const description = descriptionId
|
|
111
|
+
? `<et-description class="et-description" id="${descriptionId}">${option.description}</et-description>`
|
|
112
|
+
: '';
|
|
113
|
+
|
|
114
|
+
return `<et-radio ${attributes.join(' ')}><div class="et-radio-circle et-selection-card-control"></div><div class="et-radio-content et-selection-card-content"><span class="et-radio-label et-selection-card-label" id="${optionLabelId}">${option.label}</span>${description}</div></et-radio>`;
|
|
115
|
+
})
|
|
116
|
+
.join('');
|
|
117
|
+
|
|
118
|
+
const labelHtml = labelId
|
|
119
|
+
? `<et-label id="${labelId}"${options.disabled ? ' data-disabled="true"' : ''}><span class="et-label-content">${options.label}</span>${options.required ? '<span aria-hidden="true" class="et-label-required-marker">*</span>' : ''}</et-label>`
|
|
120
|
+
: '';
|
|
121
|
+
|
|
122
|
+
const support =
|
|
123
|
+
options.hint === undefined && options.error === undefined
|
|
124
|
+
? ''
|
|
125
|
+
: `<et-form-support class="et-form-support"><div class="et-form-support-stack">${
|
|
126
|
+
invalid
|
|
127
|
+
? `<div class="et-form-support-content et-form-support-errors${options.errorColor ? ` et-color--${options.errorColor}` : ''}" id="${ids.error}" aria-atomic="true" aria-live="polite" data-active="true" data-direction="from-below" data-state="active"><et-form-error class="et-form-error">${options.error}</et-form-error></div>`
|
|
128
|
+
: `<div class="et-form-support-content et-form-support-hint" id="${ids.hint}" data-active="true" data-direction="from-above" data-state="active"><et-hint>${options.hint}</et-hint></div>`
|
|
129
|
+
}</div></et-form-support>`;
|
|
130
|
+
|
|
131
|
+
return `<et-radio-group ${groupAttributes.join(' ')}>${labelHtml}${items}${support}</et-radio-group>`;
|
|
132
|
+
};
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import iconButtonBase from '../src/lib/button/icon-button.component.css?inline';
|
|
2
|
+
import segmentedButtonGroupBase from '../src/lib/forms/selection-list/segmented-button-group/segmented-button-group.component.css?inline';
|
|
3
|
+
import segmentedButtonBase from '../src/lib/forms/selection-list/segmented-button-group/segmented-button.component.css?inline';
|
|
4
|
+
import { CALENDAR_ICON } from '../src/lib/icon/headless/calendar-icon';
|
|
5
|
+
import { CHEVRON_ICON } from '../src/lib/icon/headless/chevron-icon';
|
|
6
|
+
import iconBase from '../src/lib/icon/headless/icon-styles.component.css?inline';
|
|
7
|
+
import { LOCATION_ICON } from '../src/lib/icon/headless/location-icon';
|
|
8
|
+
import { PLUS_ICON } from '../src/lib/icon/headless/plus-icon';
|
|
9
|
+
import agendaViewBase from '../src/lib/scheduler/scheduler-agenda-view.component.css?inline';
|
|
10
|
+
import appointmentDragBase from '../src/lib/scheduler/scheduler-appointment-drag-styles.component.css?inline';
|
|
11
|
+
import appointmentBase from '../src/lib/scheduler/scheduler-appointment-styles.component.css?inline';
|
|
12
|
+
import monthViewBase from '../src/lib/scheduler/scheduler-month-view.component.css?inline';
|
|
13
|
+
import timeGridViewBase from '../src/lib/scheduler/scheduler-time-grid-view.component.css?inline';
|
|
14
|
+
import schedulerBase from '../src/lib/scheduler/scheduler.component.css?inline';
|
|
15
|
+
import tabScale from '../src/lib/tabs/tab-scale-styles.component.css?inline';
|
|
16
|
+
import { buttonStyles } from './button';
|
|
17
|
+
import { iconMarkup } from './icon';
|
|
18
|
+
|
|
19
|
+
export type SchedulerMockView = 'month' | 'week' | 'day' | 'agenda';
|
|
20
|
+
|
|
21
|
+
export type SchedulerMockAppointment = {
|
|
22
|
+
title: string;
|
|
23
|
+
/** A color theme name the app registers. Left out, the appointment takes the color theme around the scheduler. */
|
|
24
|
+
color?: string;
|
|
25
|
+
/** The time range badge text. Left out, no time range badge (an all-day appointment). */
|
|
26
|
+
timeRange?: string;
|
|
27
|
+
location?: string;
|
|
28
|
+
/** The number of nested appointments, drawn by the chain count badge. */
|
|
29
|
+
chainCount?: number;
|
|
30
|
+
selected?: boolean;
|
|
31
|
+
dragging?: boolean;
|
|
32
|
+
/** A design marker on the appointment button, e.g. `hover` or `focus-visible`. */
|
|
33
|
+
force?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type SchedulerMockDay = {
|
|
37
|
+
weekday: string;
|
|
38
|
+
date: number;
|
|
39
|
+
/** The full day label the grid cells announce, e.g. `Monday, March 2`. */
|
|
40
|
+
label: string;
|
|
41
|
+
today?: boolean;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type SchedulerMockTimeBlock = SchedulerMockAppointment & {
|
|
45
|
+
/** The column index in the view. */
|
|
46
|
+
day: number;
|
|
47
|
+
/** Start and end in hours, e.g. 9.5 for 9:30. */
|
|
48
|
+
start: number;
|
|
49
|
+
end: number;
|
|
50
|
+
/** Inline offset and size in percent of the column, for overlapping appointments. */
|
|
51
|
+
inlineOffset?: number;
|
|
52
|
+
inlineSize?: number;
|
|
53
|
+
/** The nesting depth below a parent appointment. */
|
|
54
|
+
depth?: number;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type SchedulerMockAllDayEntry = SchedulerMockAppointment & {
|
|
58
|
+
day: number;
|
|
59
|
+
/** The number of days the entry spans. */
|
|
60
|
+
span: number;
|
|
61
|
+
row?: number;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type SchedulerMockTimeGridOptions = {
|
|
65
|
+
days: readonly SchedulerMockDay[];
|
|
66
|
+
/** The first and last hour drawn, as if the scrolling body sat on that window. */
|
|
67
|
+
fromHour: number;
|
|
68
|
+
toHour: number;
|
|
69
|
+
hourLabel: (hour: number) => string;
|
|
70
|
+
blocks?: readonly SchedulerMockTimeBlock[];
|
|
71
|
+
allDay?: readonly SchedulerMockAllDayEntry[];
|
|
72
|
+
/** The current time line: the column and the time in hours. */
|
|
73
|
+
now?: { day: number; time: number };
|
|
74
|
+
/** Non-business time per column, in hours. */
|
|
75
|
+
nonBusiness?: readonly { day: number; from: number; to: number }[];
|
|
76
|
+
/** A design marker on one slot, e.g. `focus-visible`. */
|
|
77
|
+
forcedSlot?: { day: number; hour: number; force: string };
|
|
78
|
+
ariaLabel: string;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export type SchedulerMockMonthCell = {
|
|
82
|
+
date: number;
|
|
83
|
+
label: string;
|
|
84
|
+
outsideMonth?: boolean;
|
|
85
|
+
today?: boolean;
|
|
86
|
+
appointments?: readonly SchedulerMockAppointment[];
|
|
87
|
+
/** The number of appointments behind the `+n more` trigger. */
|
|
88
|
+
overflow?: number;
|
|
89
|
+
force?: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type SchedulerMockMonthOptions = {
|
|
93
|
+
weekdays: readonly { short: string; long: string }[];
|
|
94
|
+
weeks: readonly (readonly SchedulerMockMonthCell[])[];
|
|
95
|
+
ariaLabel: string;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export type SchedulerMockAgendaRow = SchedulerMockAppointment & {
|
|
99
|
+
/** The tree guides in front of a nested appointment. */
|
|
100
|
+
guides?: readonly ('trunk' | 'branch' | 'last-branch' | 'blank')[];
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export type SchedulerMockAgendaOptions = {
|
|
104
|
+
days: readonly (SchedulerMockDay & { month?: string; rows: readonly SchedulerMockAgendaRow[] })[];
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export type SchedulerMockLabels = {
|
|
108
|
+
today: string;
|
|
109
|
+
previous: string;
|
|
110
|
+
next: string;
|
|
111
|
+
addAppointment: string;
|
|
112
|
+
views: Record<SchedulerMockView, string>;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type SchedulerMockOptions = {
|
|
116
|
+
view: SchedulerMockView;
|
|
117
|
+
headerLabel: string;
|
|
118
|
+
/** The rendered view, from `schedulerTimeGrid()`, `schedulerMonth()` or `schedulerAgenda()`. */
|
|
119
|
+
body: string;
|
|
120
|
+
labels?: SchedulerMockLabels;
|
|
121
|
+
/** Draws the add appointment toolbar action. */
|
|
122
|
+
addAction?: boolean;
|
|
123
|
+
/** Extra attributes on the host, e.g. a style or design markers. */
|
|
124
|
+
attributes?: string;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const DEFAULT_LABELS: SchedulerMockLabels = {
|
|
128
|
+
today: 'Today',
|
|
129
|
+
previous: 'Previous',
|
|
130
|
+
next: 'Next',
|
|
131
|
+
addAppointment: 'Add appointment',
|
|
132
|
+
views: { month: 'Month', week: 'Week', day: 'Day', agenda: 'Agenda' },
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/** The stylesheets the scheduler mocks draw with: the real scheduler, view, appointment, button, icon and segmented button CSS. */
|
|
136
|
+
export const schedulerStyles = /* @__PURE__ */ [
|
|
137
|
+
buttonStyles,
|
|
138
|
+
iconBase,
|
|
139
|
+
iconButtonBase,
|
|
140
|
+
tabScale,
|
|
141
|
+
segmentedButtonGroupBase,
|
|
142
|
+
segmentedButtonBase,
|
|
143
|
+
schedulerBase,
|
|
144
|
+
appointmentBase,
|
|
145
|
+
appointmentDragBase,
|
|
146
|
+
timeGridViewBase,
|
|
147
|
+
monthViewBase,
|
|
148
|
+
agendaViewBase,
|
|
149
|
+
].join('\n');
|
|
150
|
+
|
|
151
|
+
const styled = (css: string) => ` style="${css}"`;
|
|
152
|
+
|
|
153
|
+
const flag = (on: boolean | undefined, name: string) => (on ? ` ${name}=""` : '');
|
|
154
|
+
|
|
155
|
+
const forced = (force: string | undefined) => (force ? ` data-et-force="${force}"` : '');
|
|
156
|
+
|
|
157
|
+
const colored = (color: string | undefined) => (color ? ` et-color--${color}` : '');
|
|
158
|
+
|
|
159
|
+
const badges = (appointment: SchedulerMockAppointment) => {
|
|
160
|
+
const timeRange = appointment.timeRange
|
|
161
|
+
? `<span class="et-scheduler-appointment-time-range">${appointment.timeRange}</span>`
|
|
162
|
+
: '';
|
|
163
|
+
const location = appointment.location
|
|
164
|
+
? `<span class="et-scheduler-appointment-location">${iconMarkup(LOCATION_ICON, 'et-scheduler-appointment-location-icon')}<span class="et-scheduler-appointment-location-text">${appointment.location}</span></span>`
|
|
165
|
+
: '';
|
|
166
|
+
const chainCount = appointment.chainCount
|
|
167
|
+
? `<span class="et-scheduler-appointment-chain-count">${iconMarkup(CHEVRON_ICON, 'et-scheduler-appointment-chain-count-icon')}${appointment.chainCount}</span>`
|
|
168
|
+
: '';
|
|
169
|
+
|
|
170
|
+
return [
|
|
171
|
+
`<et-scheduler-badge-color-dot><span aria-hidden="true" class="et-scheduler-appointment-dot"></span></et-scheduler-badge-color-dot>`,
|
|
172
|
+
`<et-scheduler-badge-title><span class="et-scheduler-appointment-title">${appointment.title}</span></et-scheduler-badge-title>`,
|
|
173
|
+
`<et-scheduler-badge-time-range>${timeRange}</et-scheduler-badge-time-range>`,
|
|
174
|
+
`<et-scheduler-badge-location>${location}</et-scheduler-badge-location>`,
|
|
175
|
+
`<et-scheduler-badge-chain-count>${chainCount}</et-scheduler-badge-chain-count>`,
|
|
176
|
+
].join('');
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const appointmentAttributes = (appointment: SchedulerMockAppointment) =>
|
|
180
|
+
[
|
|
181
|
+
flag(appointment.selected, 'data-selected'),
|
|
182
|
+
' data-draggable=""',
|
|
183
|
+
flag(appointment.dragging, 'data-dragging'),
|
|
184
|
+
` title="${appointment.title}"`,
|
|
185
|
+
forced(appointment.force),
|
|
186
|
+
].join('');
|
|
187
|
+
|
|
188
|
+
const resizeHandles = (className: string) =>
|
|
189
|
+
`<span data-edge="start" aria-hidden="true" class="${className}"></span><span data-edge="end" aria-hidden="true" class="${className}"></span>`;
|
|
190
|
+
|
|
191
|
+
const percent = (hours: number, options: SchedulerMockTimeGridOptions) =>
|
|
192
|
+
((hours - options.fromHour) / (options.toHour - options.fromHour)) * 100;
|
|
193
|
+
|
|
194
|
+
/** Draws an `et-scheduler-time-grid-view` (the week or day grid) with its all-day lane, blocks and current time line, as HTML. */
|
|
195
|
+
export const schedulerTimeGrid = (options: SchedulerMockTimeGridOptions) => {
|
|
196
|
+
const hours = Array.from({ length: options.toHour - options.fromHour }, (_, index) => options.fromHour + index);
|
|
197
|
+
const allDay = options.allDay ?? [];
|
|
198
|
+
const allDayRows = allDay.length ? Math.max(...allDay.map((entry) => (entry.row ?? 0) + 1)) : 0;
|
|
199
|
+
|
|
200
|
+
const header = options.days
|
|
201
|
+
.map(
|
|
202
|
+
(day) =>
|
|
203
|
+
`<div role="columnheader" class="et-scheduler-time-grid-header-day"${flag(day.today, 'data-today')}><span class="et-scheduler-time-grid-header-weekday">${day.weekday}</span><span class="et-scheduler-time-grid-header-date">${day.date}</span></div>`,
|
|
204
|
+
)
|
|
205
|
+
.join('');
|
|
206
|
+
|
|
207
|
+
const allDayLane = allDayRows
|
|
208
|
+
? `<div role="row" class="et-scheduler-time-grid-row et-scheduler-time-grid-all-day"><div role="presentation" class="et-scheduler-time-grid-gutter"></div><div role="presentation" class="et-scheduler-time-grid-all-day-lane"${styled(`--_et-scheduler-time-grid-all-day-row-count: ${allDayRows}`)}>${options.days
|
|
209
|
+
.map((day, dayIndex) => {
|
|
210
|
+
const entries = allDay
|
|
211
|
+
.filter((entry) => entry.day === dayIndex)
|
|
212
|
+
.map(
|
|
213
|
+
(entry) =>
|
|
214
|
+
`<button type="button" tabindex="-1" class="et-scheduler-appointment et-scheduler-time-grid-all-day-entry${colored(entry.color)}"${appointmentAttributes(entry)}${styled(`--_et-scheduler-time-grid-all-day-offset: ${(dayIndex / options.days.length) * 100}; --_et-scheduler-time-grid-all-day-size: ${(entry.span / options.days.length) * 100}; --_et-scheduler-time-grid-all-day-row: ${entry.row ?? 0}`)}>${badges(entry)}${resizeHandles('et-scheduler-time-grid-all-day-resize')}</button>`,
|
|
215
|
+
)
|
|
216
|
+
.join('');
|
|
217
|
+
|
|
218
|
+
return `<div role="gridcell" class="et-scheduler-time-grid-all-day-cell" aria-label="${day.label}, All day" tabindex="-1">${entries}</div>`;
|
|
219
|
+
})
|
|
220
|
+
.join('')}</div></div>`
|
|
221
|
+
: '';
|
|
222
|
+
|
|
223
|
+
const gutter = hours
|
|
224
|
+
.map(
|
|
225
|
+
(hour) =>
|
|
226
|
+
`<div class="et-scheduler-time-grid-hour-row"><span class="et-scheduler-time-grid-hour-label">${options.hourLabel(hour)}</span></div>`,
|
|
227
|
+
)
|
|
228
|
+
.join('');
|
|
229
|
+
|
|
230
|
+
const columns = options.days
|
|
231
|
+
.map((day, dayIndex) => {
|
|
232
|
+
const nonBusiness = (options.nonBusiness ?? [])
|
|
233
|
+
.filter((segment) => segment.day === dayIndex)
|
|
234
|
+
.map(
|
|
235
|
+
(segment) =>
|
|
236
|
+
`<div role="presentation" class="et-scheduler-time-grid-non-business"${styled(`--_et-scheduler-time-grid-block-offset: ${percent(segment.from, options)}; --_et-scheduler-time-grid-block-span: ${percent(segment.to, options) - percent(segment.from, options)}`)}></div>`,
|
|
237
|
+
)
|
|
238
|
+
.join('');
|
|
239
|
+
const now =
|
|
240
|
+
options.now?.day === dayIndex
|
|
241
|
+
? `<div role="presentation" class="et-scheduler-time-grid-now"${styled(`--_et-scheduler-time-grid-now-offset: ${percent(options.now.time, options)}`)}></div>`
|
|
242
|
+
: '';
|
|
243
|
+
const slots = hours
|
|
244
|
+
.map((hour) => {
|
|
245
|
+
const blocks = (options.blocks ?? [])
|
|
246
|
+
.filter((block) => block.day === dayIndex && Math.floor(block.start) === hour)
|
|
247
|
+
.map((block) => {
|
|
248
|
+
const depth = block.depth ?? 0;
|
|
249
|
+
|
|
250
|
+
return `<button type="button" tabindex="-1" class="et-scheduler-time-grid-block${colored(block.color)}"${appointmentAttributes(block)}${flag(depth > 0, 'data-nested')}${styled(`--_et-scheduler-time-grid-block-offset: ${percent(block.start, options)}; --_et-scheduler-time-grid-block-span: ${percent(block.end, options) - percent(block.start, options)}; --_et-scheduler-time-grid-block-inline-offset: ${block.inlineOffset ?? 0}; --_et-scheduler-time-grid-block-inline-size: ${block.inlineSize ?? 100}; --_et-scheduler-time-grid-block-depth: ${depth}`)}>${badges(block)}${resizeHandles('et-scheduler-time-grid-block-resize')}</button>`;
|
|
251
|
+
})
|
|
252
|
+
.join('');
|
|
253
|
+
const slotForce =
|
|
254
|
+
options.forcedSlot?.day === dayIndex && options.forcedSlot.hour === hour
|
|
255
|
+
? forced(options.forcedSlot.force)
|
|
256
|
+
: '';
|
|
257
|
+
|
|
258
|
+
return `<div role="gridcell" class="et-scheduler-time-grid-hour-row et-scheduler-time-grid-slot" aria-label="${day.label}, ${options.hourLabel(hour)}" tabindex="-1"${slotForce}>${blocks}</div>`;
|
|
259
|
+
})
|
|
260
|
+
.join('');
|
|
261
|
+
|
|
262
|
+
return `<div role="presentation" class="et-scheduler-time-grid-day"${flag(day.today, 'data-today')}>${nonBusiness}${now}${slots}</div>`;
|
|
263
|
+
})
|
|
264
|
+
.join('');
|
|
265
|
+
|
|
266
|
+
return [
|
|
267
|
+
`<et-scheduler-time-grid-view role="grid" class="et-scheduler-time-grid-view" aria-label="${options.ariaLabel}">`,
|
|
268
|
+
`<div role="row" class="et-scheduler-time-grid-row et-scheduler-time-grid-header"><div role="presentation" class="et-scheduler-time-grid-gutter"></div><div role="presentation" class="et-scheduler-time-grid-days">${header}</div></div>`,
|
|
269
|
+
allDayLane,
|
|
270
|
+
`<div role="presentation" class="et-scheduler-time-grid-body-wrap"><div role="rowgroup" class="et-scheduler-time-grid-row et-scheduler-time-grid-body et-scrollbar-host">`,
|
|
271
|
+
`<div role="presentation" class="et-scheduler-time-grid-gutter">${gutter}</div>`,
|
|
272
|
+
`<div role="presentation" class="et-scheduler-time-grid-days">${columns}</div>`,
|
|
273
|
+
`</div></div></et-scheduler-time-grid-view>`,
|
|
274
|
+
].join('');
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
/** Draws an `et-scheduler-month-view` grid with its appointments and `+n more` triggers, as HTML. */
|
|
278
|
+
export const schedulerMonth = (options: SchedulerMockMonthOptions) => {
|
|
279
|
+
const weekdays = options.weekdays
|
|
280
|
+
.map(
|
|
281
|
+
(weekday) =>
|
|
282
|
+
`<span aria-label="${weekday.long}" role="columnheader" class="et-scheduler-month-view-weekday">${weekday.short}</span>`,
|
|
283
|
+
)
|
|
284
|
+
.join('');
|
|
285
|
+
|
|
286
|
+
const weeks = options.weeks
|
|
287
|
+
.map((week) => {
|
|
288
|
+
const cells = week
|
|
289
|
+
.map((cell) => {
|
|
290
|
+
const appointments = (cell.appointments ?? [])
|
|
291
|
+
.map(
|
|
292
|
+
(appointment) =>
|
|
293
|
+
`<button type="button" tabindex="-1" class="et-scheduler-appointment${colored(appointment.color)}"${appointmentAttributes(appointment)}>${badges(appointment)}</button>`,
|
|
294
|
+
)
|
|
295
|
+
.join('');
|
|
296
|
+
const overflow = cell.overflow
|
|
297
|
+
? `<div class="et-scheduler-month-view-overflow"><button aria-haspopup="menu" type="button" tabindex="-1" class="et-scheduler-month-view-overflow-trigger" aria-expanded="false">+${cell.overflow} more</button></div>`
|
|
298
|
+
: '';
|
|
299
|
+
|
|
300
|
+
return `<div role="gridcell" class="et-scheduler-month-view-cell"${flag(cell.outsideMonth, 'data-outside-month')}${flag(cell.today, 'data-today')}${cell.today ? ' aria-current="date"' : ''} aria-label="${cell.label}" tabindex="-1"${forced(cell.force)}><span aria-hidden="true" class="et-scheduler-month-view-cell-date">${cell.date}</span><div class="et-scheduler-month-view-cell-appointments">${appointments}${overflow}</div></div>`;
|
|
301
|
+
})
|
|
302
|
+
.join('');
|
|
303
|
+
|
|
304
|
+
return `<div role="row" class="et-scheduler-month-view-week">${cells}</div>`;
|
|
305
|
+
})
|
|
306
|
+
.join('');
|
|
307
|
+
|
|
308
|
+
return `<et-scheduler-month-view role="grid" class="et-scheduler-month-view" aria-label="${options.ariaLabel}"><div role="row" class="et-scheduler-month-view-weekdays">${weekdays}</div><div role="rowgroup" class="et-scheduler-month-view-weeks"><div aria-hidden="true" class="et-scheduler-month-view-draft-anchor"></div>${weeks}</div></et-scheduler-month-view>`;
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
/** Draws an `et-scheduler-agenda-view` list of days with their appointments and tree guides, as HTML. */
|
|
312
|
+
export const schedulerAgenda = (options: SchedulerMockAgendaOptions) => {
|
|
313
|
+
const days = options.days
|
|
314
|
+
.map((day) => {
|
|
315
|
+
const month = day.month ? `<h3 class="et-scheduler-agenda-view-month">${day.month}</h3>` : '';
|
|
316
|
+
const rows = day.rows
|
|
317
|
+
.map((row) => {
|
|
318
|
+
const guides = (row.guides ?? [])
|
|
319
|
+
.map(
|
|
320
|
+
(guide) =>
|
|
321
|
+
`<span aria-hidden="true" class="et-scheduler-agenda-view-guide" data-guide="${guide}"></span>`,
|
|
322
|
+
)
|
|
323
|
+
.join('');
|
|
324
|
+
|
|
325
|
+
return `<div class="et-scheduler-agenda-view-appointment">${guides}<button type="button" class="et-scheduler-appointment${colored(row.color)}"${flag(row.selected, 'data-selected')}${flag(guides.length > 0, 'data-nested')}${forced(row.force)}>${badges(row)}</button></div>`;
|
|
326
|
+
})
|
|
327
|
+
.join('');
|
|
328
|
+
|
|
329
|
+
return `${month}<div class="et-scheduler-agenda-view-day"><div class="et-scheduler-agenda-view-day-header"${flag(day.today, 'data-today')}><span class="et-scheduler-agenda-view-day-weekday">${day.weekday}</span><span class="et-scheduler-agenda-view-day-date">${day.date}</span></div><div class="et-scheduler-agenda-view-day-appointments">${rows}</div></div>`;
|
|
330
|
+
})
|
|
331
|
+
.join('');
|
|
332
|
+
|
|
333
|
+
return `<et-scheduler-agenda-view class="et-scheduler-agenda-view"><div class="et-scheduler-agenda-view-scroller et-scrollbar-host">${days}</div></et-scheduler-agenda-view>`;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const BUTTON_CLASSES = 'et-surface-interactive et-color-interactive';
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Draws an `et-scheduler` with its wide header (today button, toolbar action, previous and next, the range label
|
|
340
|
+
* and the view switch) around a view, as HTML. The visually hidden view switch label and the auto-hiding
|
|
341
|
+
* scrollbar are left out.
|
|
342
|
+
*/
|
|
343
|
+
export const scheduler = (options: SchedulerMockOptions) => {
|
|
344
|
+
const labels = options.labels ?? DEFAULT_LABELS;
|
|
345
|
+
|
|
346
|
+
const today = `<button type="button" class="${BUTTON_CLASSES} et-button et-scheduler-today-button et-focus-ring et-color--inherited" aria-label="${labels.today}" data-icon-alignment="start" data-variant="outline" data-size="sm"><div class="et-button-icon">${iconMarkup(CALENDAR_ICON)}</div><div class="et-button-contents"><span class="et-scheduler-today-button-label">${labels.today}</span></div></button>`;
|
|
347
|
+
const add = options.addAction
|
|
348
|
+
? `<button type="button" class="${BUTTON_CLASSES} et-button et-scheduler-toolbar-action et-focus-ring et-color--inherited" data-icon-alignment="start" data-variant="filled" data-size="sm"><div class="et-button-icon">${iconMarkup(PLUS_ICON)}</div><div class="et-button-contents">${labels.addAppointment}</div></button>`
|
|
349
|
+
: '';
|
|
350
|
+
const navButton = (direction: 'previous' | 'next') =>
|
|
351
|
+
`<button type="button" class="${BUTTON_CLASSES} et-icon-button et-scheduler-nav-button et-scheduler-nav-button--${direction} et-focus-ring et-color--inherited" aria-label="${labels[direction]}" data-variant="transparent" data-size="sm"><div class="et-icon-button-icon">${iconMarkup(CHEVRON_ICON)}</div></button>`;
|
|
352
|
+
const views = (['month', 'week', 'day', 'agenda'] as const)
|
|
353
|
+
.map((view) => {
|
|
354
|
+
const checked = view === options.view;
|
|
355
|
+
|
|
356
|
+
return `<et-segmented-button value="${view}" class="et-color-interactive et-segmented-button" role="radio" aria-checked="${checked}" tabindex="${checked ? 0 : -1}"><div class="et-segmented-button-bg"></div><span class="et-segmented-button-label">${labels.views[view]}</span></et-segmented-button>`;
|
|
357
|
+
})
|
|
358
|
+
.join('');
|
|
359
|
+
|
|
360
|
+
return [
|
|
361
|
+
`<et-scheduler class="et-scheduler" ${options.attributes ?? ''}><div class="et-scheduler-header">`,
|
|
362
|
+
today,
|
|
363
|
+
add,
|
|
364
|
+
`<div class="et-scheduler-nav-buttons">${navButton('previous')}${navButton('next')}</div>`,
|
|
365
|
+
`<span class="et-scheduler-header-label">${options.headerLabel}</span><div class="et-scheduler-header-spacer"></div>`,
|
|
366
|
+
`<et-segmented-button-group class="et-segmented-button-group et-scheduler-view-switch et-color--inherited et-tab-scale" role="radiogroup" data-size="sm" data-variant="tabs"><div class="et-segmented-button-group-buttons">${views}</div></et-segmented-button-group>`,
|
|
367
|
+
`</div><div class="et-scheduler-body">${options.body}</div></et-scheduler>`,
|
|
368
|
+
].join('');
|
|
369
|
+
};
|