@ethlete/components 1.0.0-next.80 → 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 CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0-next.81
4
+
5
+ ### Minor Changes
6
+
7
+ - Anchored overlays take `arrowAnchor`, an element the arrow points at instead of the origin; the `anchoredDialog()` design mock takes a matching `anchor` selector.
8
+ - The focus ring takes public `--et-focus-ring-*` tokens; `design check` stops flagging base parts and spinner clipping.
9
+ - Breaking: the `et-progress-step` input `state` is now `stepState`, so it no longer collides with the `state` input of `RouterLink`.
10
+ - The window control button takes `shape: 'caption'`, a full-height 46px Windows caption tile with a 10px glyph.
11
+
12
+ ### Patch Changes
13
+
14
+ - Name the scheduler appointment buttons with `aria-label` (the appointment title) in the month and time grid views. The `title` attribute stays. The scheduler test driver now selects appointments by `aria-label`.
15
+ - The select design mock takes an `ariaLabel` and names its trigger like `et-select` does.
16
+ - `etTooltip` now opens on touch devices with a long press. A normal tap still does only the trigger's own action. The tooltip hides 1.5s after the finger lifts.
17
+
3
18
  ## 1.0.0-next.80
4
19
 
5
20
  ### Minor Changes
@@ -11,6 +11,11 @@ export type AnchoredDialogMockOptions = {
11
11
  arrow?: boolean;
12
12
  /** The side the pane opened on, which places the arrow. Defaults to `bottom-end`, the strategy's default. */
13
13
  placement?: Placement;
14
+ /**
15
+ * A CSS selector of the drawn element the arrow points at, like `arrowAnchor` of the strategy. The design frame aims
16
+ * the arrow at its centre, and the render check reports a tip that misses it.
17
+ */
18
+ anchor?: string;
14
19
  /** The pane's role. Defaults to `dialog`. */
15
20
  role?: 'dialog' | 'alertdialog';
16
21
  /** Draws `aria-modal="true"`. Defaults to `true`, as for a modal overlay; `false` for `mode: 'non-modal'`. */
@@ -84,6 +89,7 @@ export const anchoredDialog = (options: AnchoredDialogMockOptions) => {
84
89
  options.labelledBy && `aria-labelledby="${options.labelledBy}"`,
85
90
  options.label && `aria-label="${options.label}"`,
86
91
  `data-overlay-placement="${placement}"`,
92
+ options.anchor && `data-et-arrow-anchor="${options.anchor.replaceAll('"', '"')}"`,
87
93
  `class="${classes.join(' ')}"`,
88
94
  ].filter(Boolean);
89
95
  const arrowMarkup = arrow ? '<div class="et-overlay-arrow" et-floating-arrow></div>' : '';
@@ -9,6 +9,7 @@ type Props = {
9
9
  label?: string;
10
10
  placement?: 'bottom-end' | 'bottom-start' | 'top-end' | 'top-start';
11
11
  arrow?: boolean;
12
+ anchor?: string;
12
13
  modal?: boolean;
13
14
  };
14
15
 
@@ -47,7 +48,15 @@ export default definePart({
47
48
  },
48
49
  frame: (body, { placement = 'bottom-end' }) =>
49
50
  `<div class="anchored-dialog-frame" style="--anchored-dialog-justify:${placement.endsWith('start') ? 'flex-start' : 'flex-end'}"><div data-et-anchor>${body}</div></div>`,
50
- render: async ({ kind = 'open-points', content, label, placement = 'bottom-end', arrow, modal = true }: Props) => {
51
+ render: async ({
52
+ kind = 'open-points',
53
+ content,
54
+ label,
55
+ placement = 'bottom-end',
56
+ arrow,
57
+ anchor,
58
+ modal = true,
59
+ }: Props) => {
51
60
  const apply = await button.render({ label: 'Apply', variant: 'filled' });
52
61
  const pane = content ?? (kind === 'filter' ? filter(apply.body) : openPoints());
53
62
 
@@ -56,6 +65,7 @@ export default definePart({
56
65
  label: label ?? (kind === 'filter' ? 'Filter' : 'Open points'),
57
66
  placement,
58
67
  arrow,
68
+ anchor,
59
69
  modal,
60
70
  content: pane,
61
71
  }),
@@ -27,7 +27,11 @@ const control = ({ interaction, ...options }: Props) => {
27
27
  return interaction ? forceInteraction(markup, interaction) : markup;
28
28
  };
29
29
 
30
- const plus = iconMarkup(SDK_ICONS.find((each) => each.name === 'et-plus')!);
30
+ const fail = (message: string): never => {
31
+ throw new Error(message);
32
+ };
33
+
34
+ const plus = iconMarkup(SDK_ICONS.find((each) => each.name === 'et-plus') ?? fail('SDK_ICONS has no et-plus'));
31
35
  const SIZES = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
32
36
  const VARIANTS = ['filled', 'outline', 'tonal', 'transparent'] as const;
33
37
  type Size = (typeof SIZES)[number];
@@ -73,7 +77,7 @@ export const grid = {
73
77
 
74
78
  export default definePart({
75
79
  note: 'scale of the decided shape, Q182, lead merge',
76
- madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5'],
80
+ madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5', 'design check'],
77
81
  states,
78
82
  grid,
79
83
  controls: { button: { kind: 'button', input: ['pointer', 'keyboard'], disabled: true } },
@@ -6,6 +6,7 @@ type FieldInteraction = 'hover' | 'active' | 'focus-visible';
6
6
 
7
7
  export type SelectProps = {
8
8
  label?: string;
9
+ ariaLabel?: string;
9
10
  options?: { value: string; label: string }[];
10
11
  value?: string;
11
12
  open?: boolean;
@@ -76,6 +77,7 @@ export const selectBody = (props: SelectProps) =>
76
77
  value: props.value,
77
78
  active: props.active,
78
79
  placeholder: 'Pick a status',
80
+ ariaLabel: props.ariaLabel,
79
81
  }),
80
82
  }),
81
83
  props,
@@ -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
+ }
@@ -23,14 +23,15 @@
23
23
  }
24
24
  },
25
25
  "components/anchored-dialog": {
26
- "review": {
27
- "hash": "02e3cce0bd8f11b6",
26
+ "record": {
27
+ "hash": "15ba4525ab01bffc",
28
28
  "states": {
29
29
  "open-points": "226f8135b514b073",
30
30
  "filter": "3ecf9f95f7739891",
31
31
  "no-arrow": "a071879be802f635",
32
32
  "top-start": "afe5a3fd876a51e4"
33
33
  },
34
+ "partHash": "1e60e9f9e74b4c91",
34
35
  "slots": true
35
36
  }
36
37
  },
@@ -1179,5 +1180,16 @@
1179
1180
  },
1180
1181
  "slots": true
1181
1182
  }
1183
+ },
1184
+ "foundations/icons": {
1185
+ "record": {
1186
+ "hash": "8f54284f202642c8",
1187
+ "states": {
1188
+ "catalogue": "4e2a1394b85b1546",
1189
+ "construction": "be42f54e25b07e1f"
1190
+ },
1191
+ "partHash": "693a3ae986c6ad3f",
1192
+ "slots": true
1193
+ }
1182
1194
  }
1183
1195
  }
@@ -0,0 +1,64 @@
1
+ {
2
+ "foundations/colors": {
3
+ "hash": "90cda4cd58b51ef5",
4
+ "files": {
5
+ ".ethlete/design/sdk/foundations/colors/colors.ts": "5f21e1f2948db378",
6
+ ".ethlete/design/sdk/foundations/colors/overrides.json": "37529d9089744c64",
7
+ ".ethlete/design/sdk/foundations/colors/shared/contrast.ts": "b93de9afab5a930e"
8
+ },
9
+ "at": "2026-11-08T14:57:09.725Z",
10
+ "by": "et design check",
11
+ "cmd": "design check",
12
+ "pid": 1454598
13
+ },
14
+ "foundations/elevation": {
15
+ "hash": "097c0586609d90ad",
16
+ "files": {
17
+ ".ethlete/design/sdk/foundations/elevation/elevation.css": "f2f220dfb86a39c2",
18
+ ".ethlete/design/sdk/foundations/elevation/elevation.ts": "db933f910ada1a89",
19
+ ".ethlete/design/sdk/foundations/elevation/shared/elevation/scene.css": "1f8f38c213e70f13",
20
+ ".ethlete/design/sdk/foundations/elevation/shared/elevation/scene.ts": "936205798eb8c95c",
21
+ "libs/components/design/form-field.ts": "6910b0bf23eb0f3c",
22
+ "libs/components/design/icon.ts": "829a95253b948ba9",
23
+ "libs/components/design/select.ts": "d9dba51f6cbeb2df",
24
+ "libs/components/src/lib/forms/form-field/form-field-control-suffix-styles.component.css": "cc2cea40f4a0f4ae",
25
+ "libs/components/src/lib/forms/form-field/form-field-suffix-overlap-styles.component.css": "74e1b9ee85a9cc51",
26
+ "libs/components/src/lib/forms/form-field/form-field-text-shell-styles.component.css": "2eac704dfac0a6aa",
27
+ "libs/components/src/lib/forms/form-field/form-field.component.css": "4063eb2012233778",
28
+ "libs/components/src/lib/forms/form-field/headless/label.directive.css": "c010d55fd205c6fa",
29
+ "libs/components/src/lib/forms/form-field/hint.component.css": "d2c4f0ec2ef6bac4",
30
+ "libs/components/src/lib/forms/input/input.component.css": "02a190d06c08aa88",
31
+ "libs/components/src/lib/forms/select/select-all-option.component.css": "79b5a2ae71dbd24b",
32
+ "libs/components/src/lib/forms/select/select-option-group.component.css": "b6451eacb9b026b3",
33
+ "libs/components/src/lib/forms/select/select-option-styles.component.css": "24a12532fc82fb09",
34
+ "libs/components/src/lib/forms/select/select-panel.component.css": "b85bb18bab2890e3",
35
+ "libs/components/src/lib/forms/select/select.component.css": "fa54cb1b79ba643b",
36
+ "libs/components/src/lib/forms/textarea/textarea-autosize-styles.component.css": "27aa7dd9c197e96d",
37
+ "libs/components/src/lib/forms/textarea/textarea.component.css": "e1e6b6061ab5c476",
38
+ "libs/components/src/lib/icon/headless/check-icon.ts": "6a14df4cc853b42d",
39
+ "libs/components/src/lib/icon/headless/chevron-icon.ts": "d2c88d30d687a8bf",
40
+ "libs/components/src/lib/icon/headless/icon-definition.ts": "180b7ea77305a404",
41
+ "libs/components/src/lib/icon/headless/icon-styles.component.css": "c137a7a10599dc3f",
42
+ "libs/components/src/lib/icon/headless/times-icon.ts": "52047c20b1cf421d",
43
+ "libs/core/design/interactive-styles.ts": "781528322bd34499",
44
+ "libs/core/src/lib/theming/color-interactive-styles.component.css": "8baece3a25375ed8",
45
+ "libs/core/src/lib/theming/surface-interactive-styles.component.css": "944cbb76b1d15611"
46
+ },
47
+ "at": "2026-11-08T14:57:09.841Z",
48
+ "by": "et design check",
49
+ "cmd": "design check",
50
+ "pid": 1454598
51
+ },
52
+ "foundations/icons": {
53
+ "hash": "8f54284f202642c8",
54
+ "files": {
55
+ ".ethlete/design/sdk/foundations/icons/icons.ts": "92fe04df2b6735e5",
56
+ "libs/components/design/icon-set.ts": "2aab551c1dd9aedc",
57
+ "libs/components/src/lib/icon/headless/icon-definition.ts": "180b7ea77305a404"
58
+ },
59
+ "at": "2026-11-08T14:57:09.936Z",
60
+ "by": "et design check",
61
+ "cmd": "design check",
62
+ "pid": 1454598
63
+ }
64
+ }
@@ -0,0 +1,104 @@
1
+ {
2
+ "OFF-CENTRE": {
3
+ "components/button: size-lg at fitted: button[data-et-part=components/button]": {
4
+ "finding": "628",
5
+ "sketch": "components/button@off-centre"
6
+ },
7
+ "components/button: size-xl at fitted: button[data-et-part=components/button]": {
8
+ "finding": "628",
9
+ "sketch": "components/button@off-centre"
10
+ },
11
+ "components/chart: pie-tooltip at 480px: div.et-tooltip-mock-frame > div.et-overlay > et-tooltip.et-tooltip > div.et-tooltip__surface": {
12
+ "finding": "631",
13
+ "sketch": "components/chart@off-centre"
14
+ },
15
+ "components/pagination: current at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
16
+ "finding": "629",
17
+ "sketch": "components/pagination@off-centre"
18
+ },
19
+ "components/pagination: current-active at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
20
+ "finding": "629",
21
+ "sketch": "components/pagination@off-centre"
22
+ },
23
+ "components/pagination: current-focus-visible at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
24
+ "finding": "629",
25
+ "sketch": "components/pagination@off-centre"
26
+ },
27
+ "components/pagination: current-hover at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
28
+ "finding": "629",
29
+ "sketch": "components/pagination@off-centre"
30
+ },
31
+ "components/pagination: few at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
32
+ "finding": "629",
33
+ "sketch": "components/pagination@off-centre"
34
+ },
35
+ "components/pagination: first at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
36
+ "finding": "629",
37
+ "sketch": "components/pagination@off-centre"
38
+ },
39
+ "components/pagination: last at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
40
+ "finding": "629",
41
+ "sketch": "components/pagination@off-centre"
42
+ },
43
+ "components/pagination: links at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > a.et-surface-interactive": {
44
+ "finding": "629",
45
+ "sketch": "components/pagination@off-centre"
46
+ },
47
+ "components/pagination: middle at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
48
+ "finding": "629",
49
+ "sketch": "components/pagination@off-centre"
50
+ },
51
+ "components/pagination: page at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
52
+ "finding": "629",
53
+ "sketch": "components/pagination@off-centre"
54
+ },
55
+ "components/pagination: page-active at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
56
+ "finding": "629",
57
+ "sketch": "components/pagination@off-centre"
58
+ },
59
+ "components/pagination: page-focus-visible at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
60
+ "finding": "629",
61
+ "sketch": "components/pagination@off-centre"
62
+ },
63
+ "components/pagination: page-hover at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
64
+ "finding": "629",
65
+ "sketch": "components/pagination@off-centre"
66
+ },
67
+ "components/pagination: range at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
68
+ "finding": "629",
69
+ "sketch": "components/pagination@off-centre"
70
+ },
71
+ "components/pagination: sm at 480px: et-pagination[data-et-part=components/pagination] > ul.et-pagination-list > li.et-pagination-item > button.et-surface-interactive": {
72
+ "finding": "629",
73
+ "sketch": "components/pagination@off-centre"
74
+ },
75
+ "components/scrollable: vertical-border-mask at 480px: et-scrollable.et-scrollable > div.et-scrollable-wrapper > div.et-scrollable-container > button.et-scrollable-item": {
76
+ "finding": "630",
77
+ "sketch": "components/scrollable@off-centre"
78
+ },
79
+ "components/scrollable: vertical-end at 480px: et-scrollable.et-scrollable > div.et-scrollable-wrapper > div.et-scrollable-container > button.et-scrollable-item": {
80
+ "finding": "630",
81
+ "sketch": "components/scrollable@off-centre"
82
+ },
83
+ "components/scrollable: vertical-middle at 480px: et-scrollable.et-scrollable > div.et-scrollable-wrapper > div.et-scrollable-container > button.et-scrollable-item": {
84
+ "finding": "630",
85
+ "sketch": "components/scrollable@off-centre"
86
+ },
87
+ "components/scrollable: vertical-navigation at 480px: et-scrollable.et-scrollable > div.et-scrollable-wrapper > div.et-scrollable-container > button.et-scrollable-item": {
88
+ "finding": "630",
89
+ "sketch": "components/scrollable@off-centre"
90
+ },
91
+ "components/scrollable: vertical-start at 480px: et-scrollable.et-scrollable > div.et-scrollable-wrapper > div.et-scrollable-container > button.et-scrollable-item": {
92
+ "finding": "630",
93
+ "sketch": "components/scrollable@off-centre"
94
+ },
95
+ "components/skeleton: in-text at 480px: div.skeleton-frame": {
96
+ "finding": "633",
97
+ "sketch": "components/skeleton@off-centre"
98
+ },
99
+ "components/table: group-header at 480px: et-table[data-et-part=components/table] > div.et-table > et-table-group-header-row.et-table-group-row > div.et-table-group-cell": {
100
+ "finding": "632",
101
+ "sketch": "components/table@off-centre"
102
+ }
103
+ }
104
+ }
package/design/select.ts CHANGED
@@ -56,6 +56,8 @@ export type SelectMockOptions = {
56
56
  panelColor?: string;
57
57
  /** A surface theme name the app registers, for the panel. Left out, the panel takes the surface one elevation above its parent. */
58
58
  panelSurface?: string;
59
+ /** The trigger's `aria-label`, for a select without a visible label. */
60
+ ariaLabel?: string;
59
61
  };
60
62
 
61
63
  /** The stylesheets `formField()` with a `select()` control draws with: the real `et-select` CSS. */
@@ -158,7 +160,8 @@ export const select = (options: SelectMockOptions): FormFieldControlMock => {
158
160
  'role="combobox"',
159
161
  'aria-haspopup="listbox"',
160
162
  `aria-expanded="${state.open}"`,
161
- `aria-labelledby="${[state.labelId, triggerId].filter(Boolean).join(' ')}"`,
163
+ options.ariaLabel && `aria-label="${options.ariaLabel}"`,
164
+ state.labelId && `aria-labelledby="${state.labelId} ${triggerId}"`,
162
165
  `tabindex="${state.disabled ? -1 : 0}"`,
163
166
  state.disabled && 'aria-disabled="true" data-disabled="true"',
164
167
  state.open && activeIndex >= 0 && `aria-activedescendant="et-select-option-${state.id}-${activeIndex}"`,