ember-primitives 0.48.2 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/bin/index.mjs +271 -0
  2. package/declarations/components/portal.d.ts.map +1 -1
  3. package/declarations/components/rating/public-types.d.ts +0 -4
  4. package/declarations/components/rating/public-types.d.ts.map +1 -1
  5. package/declarations/components/rating/rating.d.ts +9 -1
  6. package/declarations/components/rating/rating.d.ts.map +1 -1
  7. package/declarations/components/rating/stars.d.ts.map +1 -1
  8. package/declarations/components/rating/state.d.ts +4 -0
  9. package/declarations/components/rating/state.d.ts.map +1 -1
  10. package/declarations/components/rating/utils.d.ts +0 -1
  11. package/declarations/components/rating/utils.d.ts.map +1 -1
  12. package/declarations/tabster.d.ts.map +1 -1
  13. package/declarations/utils.d.ts.map +1 -1
  14. package/declarations/viewport/in-viewport.d.ts +70 -0
  15. package/declarations/viewport/in-viewport.d.ts.map +1 -0
  16. package/declarations/viewport/viewport.d.ts +59 -0
  17. package/declarations/viewport/viewport.d.ts.map +1 -0
  18. package/declarations/viewport.d.ts +3 -0
  19. package/declarations/viewport.d.ts.map +1 -0
  20. package/dist/-private.js +0 -1
  21. package/dist/-private.js.map +1 -1
  22. package/dist/color-scheme.js +0 -1
  23. package/dist/color-scheme.js.map +1 -1
  24. package/dist/{component-Bs3N-G9z.js → component-BXy_iafw.js} +2 -3
  25. package/dist/component-BXy_iafw.js.map +1 -0
  26. package/dist/components/accordion.js +5 -6
  27. package/dist/components/accordion.js.map +1 -1
  28. package/dist/components/avatar.js +3 -4
  29. package/dist/components/avatar.js.map +1 -1
  30. package/dist/components/dialog.js +2 -3
  31. package/dist/components/dialog.js.map +1 -1
  32. package/dist/components/external-link.js +1 -2
  33. package/dist/components/external-link.js.map +1 -1
  34. package/dist/components/form.js +1 -2
  35. package/dist/components/form.js.map +1 -1
  36. package/dist/components/heading.js +1 -2
  37. package/dist/components/heading.js.map +1 -1
  38. package/dist/components/keys.js +2 -3
  39. package/dist/components/keys.js.map +1 -1
  40. package/dist/components/layout/hero.js +1 -1
  41. package/dist/components/layout/sticky-footer.js +1 -1
  42. package/dist/components/link.js +1 -2
  43. package/dist/components/link.js.map +1 -1
  44. package/dist/components/menu.js +6 -8
  45. package/dist/components/menu.js.map +1 -1
  46. package/dist/components/one-time-password.js +1 -2
  47. package/dist/components/popover.js +3 -4
  48. package/dist/components/popover.js.map +1 -1
  49. package/dist/components/portal-targets.js +2 -3
  50. package/dist/components/portal-targets.js.map +1 -1
  51. package/dist/components/portal.js +3 -7
  52. package/dist/components/portal.js.map +1 -1
  53. package/dist/components/progress.js +2 -3
  54. package/dist/components/progress.js.map +1 -1
  55. package/dist/components/rating.js +1 -2
  56. package/dist/components/scroller.js +1 -2
  57. package/dist/components/scroller.js.map +1 -1
  58. package/dist/components/shadowed.js +2 -3
  59. package/dist/components/shadowed.js.map +1 -1
  60. package/dist/components/switch.js +5 -6
  61. package/dist/components/switch.js.map +1 -1
  62. package/dist/components/tabs.js +6 -7
  63. package/dist/components/tabs.js.map +1 -1
  64. package/dist/components/toggle-group.js +3 -4
  65. package/dist/components/toggle-group.js.map +1 -1
  66. package/dist/components/toggle.js +2 -3
  67. package/dist/components/toggle.js.map +1 -1
  68. package/dist/components/visually-hidden.js +1 -2
  69. package/dist/components/visually-hidden.js.map +1 -1
  70. package/dist/components/zoetrope.js +1 -2
  71. package/dist/dom-context.js +2 -3
  72. package/dist/dom-context.js.map +1 -1
  73. package/dist/floating-ui.js +1 -2
  74. package/dist/head.js +1 -2
  75. package/dist/head.js.map +1 -1
  76. package/dist/helpers/body-class.js +0 -1
  77. package/dist/helpers/body-class.js.map +1 -1
  78. package/dist/helpers/link.js +0 -1
  79. package/dist/helpers/link.js.map +1 -1
  80. package/dist/helpers/service.js +0 -1
  81. package/dist/helpers/service.js.map +1 -1
  82. package/dist/helpers.js +0 -1
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/iframe.js +0 -1
  85. package/dist/iframe.js.map +1 -1
  86. package/dist/{index-DKE67I8L.js → index-gRO4Cvlf.js} +2 -2
  87. package/dist/index-gRO4Cvlf.js.map +1 -0
  88. package/dist/index.js +3 -4
  89. package/dist/index.js.map +1 -1
  90. package/dist/load.js +0 -1
  91. package/dist/load.js.map +1 -1
  92. package/dist/narrowing.js +0 -1
  93. package/dist/narrowing.js.map +1 -1
  94. package/dist/on-resize.js +0 -1
  95. package/dist/on-resize.js.map +1 -1
  96. package/dist/{otp-C6hCCXKx.js → otp-7rz1PWP0.js} +6 -7
  97. package/dist/otp-7rz1PWP0.js.map +1 -0
  98. package/dist/proper-links.js +0 -1
  99. package/dist/proper-links.js.map +1 -1
  100. package/dist/qp.js +0 -1
  101. package/dist/qp.js.map +1 -1
  102. package/dist/rating-BrIiwDLw.js +152 -0
  103. package/dist/rating-BrIiwDLw.js.map +1 -0
  104. package/dist/resize-observer.js +0 -1
  105. package/dist/resize-observer.js.map +1 -1
  106. package/dist/service.js +0 -1
  107. package/dist/service.js.map +1 -1
  108. package/dist/store.js +0 -1
  109. package/dist/store.js.map +1 -1
  110. package/dist/styles.css.js +0 -1
  111. package/dist/tabster.js +0 -1
  112. package/dist/tabster.js.map +1 -1
  113. package/dist/test-support.js +0 -1
  114. package/dist/test-support.js.map +1 -1
  115. package/dist/{utils-C5796IKA.js → utils-D0v9WKmV.js} +1 -2
  116. package/dist/utils-D0v9WKmV.js.map +1 -0
  117. package/dist/utils.js +4 -1
  118. package/dist/utils.js.map +1 -1
  119. package/dist/viewport/in-viewport.js +82 -0
  120. package/dist/viewport/in-viewport.js.map +1 -0
  121. package/dist/viewport/viewport.js +92 -0
  122. package/dist/viewport/viewport.js.map +1 -0
  123. package/dist/viewport.js +3 -0
  124. package/dist/viewport.js.map +1 -0
  125. package/package.json +24 -20
  126. package/src/-private.ts +4 -0
  127. package/src/color-scheme.ts +165 -0
  128. package/src/components/-private/typed-elements.gts +13 -0
  129. package/src/components/-private/utils.ts +16 -0
  130. package/src/components/accordion/content.gts +34 -0
  131. package/src/components/accordion/header.gts +36 -0
  132. package/src/components/accordion/item.gts +55 -0
  133. package/src/components/accordion/public.ts +64 -0
  134. package/src/components/accordion/trigger.gts +32 -0
  135. package/src/components/accordion.gts +195 -0
  136. package/src/components/avatar.gts +108 -0
  137. package/src/components/dialog.gts +234 -0
  138. package/src/components/external-link.gts +14 -0
  139. package/src/components/form.gts +75 -0
  140. package/src/components/heading.gts +36 -0
  141. package/src/components/keys.gts +53 -0
  142. package/src/components/layout/hero.css +5 -0
  143. package/src/components/layout/hero.gts +17 -0
  144. package/src/components/layout/sticky-footer.css +9 -0
  145. package/src/components/layout/sticky-footer.gts +40 -0
  146. package/src/components/link.gts +172 -0
  147. package/src/components/menu.gts +373 -0
  148. package/src/components/one-time-password/buttons.gts +31 -0
  149. package/src/components/one-time-password/input.gts +198 -0
  150. package/src/components/one-time-password/otp.gts +130 -0
  151. package/src/components/one-time-password/utils.ts +201 -0
  152. package/src/components/one-time-password.gts +2 -0
  153. package/src/components/popover.gts +248 -0
  154. package/src/components/portal-targets.gts +136 -0
  155. package/src/components/portal.gts +194 -0
  156. package/src/components/progress.gts +154 -0
  157. package/src/components/rating/public-types.ts +44 -0
  158. package/src/components/rating/range.gts +22 -0
  159. package/src/components/rating/rating.gts +228 -0
  160. package/src/components/rating/stars.gts +60 -0
  161. package/src/components/rating/state.gts +144 -0
  162. package/src/components/rating/utils.ts +7 -0
  163. package/src/components/rating.gts +5 -0
  164. package/src/components/scroller.gts +179 -0
  165. package/src/components/shadowed.gts +110 -0
  166. package/src/components/switch.gts +103 -0
  167. package/src/components/tabs.gts +519 -0
  168. package/src/components/toggle-group.gts +265 -0
  169. package/src/components/toggle.gts +81 -0
  170. package/src/components/violations.css +105 -0
  171. package/src/components/violations.css.ts +1 -0
  172. package/src/components/visually-hidden.css +14 -0
  173. package/src/components/visually-hidden.gts +15 -0
  174. package/src/components/zoetrope/index.gts +358 -0
  175. package/src/components/zoetrope/styles.css +40 -0
  176. package/src/components/zoetrope/types.ts +65 -0
  177. package/src/components/zoetrope.ts +3 -0
  178. package/src/dom-context.gts +245 -0
  179. package/src/floating-ui/component.gts +186 -0
  180. package/src/floating-ui/middleware.ts +13 -0
  181. package/src/floating-ui/modifier.ts +183 -0
  182. package/src/floating-ui.ts +2 -0
  183. package/src/head.gts +37 -0
  184. package/src/helpers/body-class.ts +94 -0
  185. package/src/helpers/link.ts +125 -0
  186. package/src/helpers/service.ts +25 -0
  187. package/src/helpers.ts +2 -0
  188. package/src/iframe.ts +31 -0
  189. package/src/index.ts +43 -0
  190. package/src/load.gts +77 -0
  191. package/src/narrowing.ts +7 -0
  192. package/src/on-resize.ts +64 -0
  193. package/src/proper-links.ts +140 -0
  194. package/src/qp.ts +107 -0
  195. package/src/resize-observer.ts +132 -0
  196. package/src/service.ts +103 -0
  197. package/src/store.ts +72 -0
  198. package/src/styles.css.ts +5 -0
  199. package/src/tabster.ts +54 -0
  200. package/src/template-registry.ts +44 -0
  201. package/src/test-support/a11y.ts +50 -0
  202. package/src/test-support/dom.ts +112 -0
  203. package/src/test-support/otp.ts +64 -0
  204. package/src/test-support/rating.ts +144 -0
  205. package/src/test-support/routing.ts +62 -0
  206. package/src/test-support/zoetrope.ts +51 -0
  207. package/src/test-support.gts +6 -0
  208. package/src/type-utils.ts +1 -0
  209. package/src/utils.ts +75 -0
  210. package/src/viewport/in-viewport.gts +128 -0
  211. package/src/viewport/viewport.ts +122 -0
  212. package/src/viewport.ts +2 -0
  213. package/dist/component-Bs3N-G9z.js.map +0 -1
  214. package/dist/index-DKE67I8L.js.map +0 -1
  215. package/dist/otp-C6hCCXKx.js.map +0 -1
  216. package/dist/rating-D052JWRa.js +0 -149
  217. package/dist/rating-D052JWRa.js.map +0 -1
  218. package/dist/utils-C5796IKA.js.map +0 -1
@@ -0,0 +1,265 @@
1
+ import Component from "@glimmer/component";
2
+ import { cached } from "@glimmer/tracking";
3
+ import { hash } from "@ember/helper";
4
+
5
+ import { getTabsterAttribute, MoverDirections } from "tabster";
6
+ import { TrackedSet } from "tracked-built-ins";
7
+ // The consumer will need to provide types for tracked-toolbox.
8
+ // Or.. better yet, we PR to trakcked-toolbox to provide them
9
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
10
+ // @ts-ignore
11
+ import { localCopy } from "tracked-toolbox";
12
+
13
+ import { Toggle } from "./toggle.gts";
14
+
15
+ import type { ComponentLike } from "@glint/template";
16
+
17
+ const TABSTER_CONFIG = getTabsterAttribute(
18
+ {
19
+ mover: {
20
+ direction: MoverDirections.Both,
21
+ cyclic: true,
22
+ },
23
+ },
24
+ true,
25
+ );
26
+
27
+ export interface ItemSignature<Value = any> {
28
+ /**
29
+ * The button element will have aria-pressed="true" on it when the button is in the pressed state.
30
+ */
31
+ Element: HTMLButtonElement;
32
+ Args: {
33
+ /**
34
+ * When used in a group of Toggles, this option will be helpful to
35
+ * know which toggle was pressed if you're using the same @onChange
36
+ * handler for multiple toggles.
37
+ */
38
+ value?: Value;
39
+ };
40
+ Blocks: {
41
+ default: [
42
+ /**
43
+ * the current pressed state of the toggle button
44
+ *
45
+ * Useful when using the toggle button as an uncontrolled component
46
+ */
47
+ pressed: boolean,
48
+ ];
49
+ };
50
+ }
51
+
52
+ export type Item<Value = any> = ComponentLike<ItemSignature<Value>>;
53
+
54
+ export interface SingleSignature<Value> {
55
+ Element: HTMLDivElement;
56
+ Args: {
57
+ /**
58
+ * Optionally set the initial toggle state
59
+ */
60
+ value?: Value;
61
+ /**
62
+ * Callback for when the toggle-group's state is changed.
63
+ *
64
+ * Can be used to control the state of the component.
65
+ *
66
+ *
67
+ * When none of the toggles are selected, undefined will be passed.
68
+ */
69
+ onChange?: (value: Value | undefined) => void;
70
+ };
71
+ Blocks: {
72
+ default: [
73
+ {
74
+ /**
75
+ * The Toggle Switch
76
+ */
77
+ Item: Item;
78
+ },
79
+ ];
80
+ };
81
+ }
82
+
83
+ export interface MultiSignature<Value = any> {
84
+ Element: HTMLDivElement;
85
+ Args: {
86
+ /**
87
+ * Optionally set the initial toggle state
88
+ */
89
+ value?: Value[] | Set<Value> | Value;
90
+ /**
91
+ * Callback for when the toggle-group's state is changed.
92
+ *
93
+ * Can be used to control the state of the component.
94
+ *
95
+ *
96
+ * When none of the toggles are selected, undefined will be passed.
97
+ */
98
+ onChange?: (value: Set<Value>) => void;
99
+ };
100
+ Blocks: {
101
+ default: [
102
+ {
103
+ /**
104
+ * The Toggle Switch
105
+ */
106
+ Item: Item;
107
+ },
108
+ ];
109
+ };
110
+ }
111
+
112
+ interface PrivateSingleSignature<Value = any> {
113
+ Element: HTMLDivElement;
114
+ Args: {
115
+ type?: "single";
116
+
117
+ /**
118
+ * Optionally set the initial toggle state
119
+ */
120
+ value?: Value;
121
+ /**
122
+ * Callback for when the toggle-group's state is changed.
123
+ *
124
+ * Can be used to control the state of the component.
125
+ *
126
+ *
127
+ * When none of the toggles are selected, undefined will be passed.
128
+ */
129
+ onChange?: (value: Value | undefined) => void;
130
+ };
131
+ Blocks: {
132
+ default: [
133
+ {
134
+ Item: Item;
135
+ },
136
+ ];
137
+ };
138
+ }
139
+
140
+ interface PrivateMultiSignature<Value = any> {
141
+ Element: HTMLDivElement;
142
+ Args: {
143
+ type: "multi";
144
+ /**
145
+ * Optionally set the initial toggle state
146
+ */
147
+ value?: Value[] | Set<Value> | Value;
148
+ /**
149
+ * Callback for when the toggle-group's state is changed.
150
+ *
151
+ * Can be used to control the state of the component.
152
+ *
153
+ *
154
+ * When none of the toggles are selected, undefined will be passed.
155
+ */
156
+ onChange?: (value: Set<Value>) => void;
157
+ };
158
+ Blocks: {
159
+ default: [
160
+ {
161
+ Item: Item;
162
+ },
163
+ ];
164
+ };
165
+ }
166
+
167
+ function isMulti(x: "single" | "multi" | undefined): x is "multi" {
168
+ return x === "multi";
169
+ }
170
+
171
+ export class ToggleGroup<Value = any> extends Component<
172
+ PrivateSingleSignature<Value> | PrivateMultiSignature<Value>
173
+ > {
174
+ // See: https://github.com/typed-ember/glint/issues/715
175
+ <template>
176
+ {{#if (isMulti this.args.type)}}
177
+ <MultiToggleGroup
178
+ @value={{this.args.value}}
179
+ @onChange={{this.args.onChange}}
180
+ ...attributes
181
+ as |x|
182
+ >
183
+ {{yield x}}
184
+ </MultiToggleGroup>
185
+ {{else}}
186
+ <SingleToggleGroup
187
+ @value={{this.args.value}}
188
+ @onChange={{this.args.onChange}}
189
+ ...attributes
190
+ as |x|
191
+ >
192
+ {{yield x}}
193
+ </SingleToggleGroup>
194
+ {{/if}}
195
+ </template>
196
+ }
197
+
198
+ class SingleToggleGroup<Value = any> extends Component<SingleSignature<Value>> {
199
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
200
+ @localCopy("args.value") activePressed?: Value;
201
+
202
+ handleToggle = (value: Value) => {
203
+ if (this.activePressed === value) {
204
+ this.activePressed = undefined;
205
+
206
+ return;
207
+ }
208
+
209
+ this.activePressed = value;
210
+
211
+ this.args.onChange?.(this.activePressed);
212
+ };
213
+
214
+ isPressed = (value: Value | undefined) => value === this.activePressed;
215
+
216
+ <template>
217
+ <div data-tabster={{TABSTER_CONFIG}} ...attributes>
218
+ {{yield (hash Item=(component Toggle onChange=this.handleToggle isPressed=this.isPressed))}}
219
+ </div>
220
+ </template>
221
+ }
222
+
223
+ class MultiToggleGroup<Value = any> extends Component<MultiSignature<Value>> {
224
+ /**
225
+ * Normalizes @value to a Set
226
+ * and makes sure that even if the input Set is reactive,
227
+ * we don't mistakenly dirty it.
228
+ */
229
+ @cached
230
+ get activePressed(): TrackedSet<Value> {
231
+ const value = this.args.value;
232
+
233
+ if (!value) {
234
+ return new TrackedSet();
235
+ }
236
+
237
+ if (Array.isArray(value)) {
238
+ return new TrackedSet(value);
239
+ }
240
+
241
+ if (value instanceof Set) {
242
+ return new TrackedSet(value);
243
+ }
244
+
245
+ return new TrackedSet([value]);
246
+ }
247
+
248
+ handleToggle = (value: Value) => {
249
+ if (this.activePressed.has(value)) {
250
+ this.activePressed.delete(value);
251
+ } else {
252
+ this.activePressed.add(value);
253
+ }
254
+
255
+ this.args.onChange?.(new Set<Value>(this.activePressed.values()));
256
+ };
257
+
258
+ isPressed = (value: Value) => this.activePressed.has(value);
259
+
260
+ <template>
261
+ <div data-tabster={{TABSTER_CONFIG}} ...attributes>
262
+ {{yield (hash Item=(component Toggle onChange=this.handleToggle isPressed=this.isPressed))}}
263
+ </div>
264
+ </template>
265
+ }
@@ -0,0 +1,81 @@
1
+ // import Component from '@glimmer/component';
2
+ import { fn } from "@ember/helper";
3
+ import { on } from "@ember/modifier";
4
+
5
+ import { cell } from "ember-resources";
6
+
7
+ import { toggleWithFallback } from "./-private/utils.ts";
8
+
9
+ import type { TOC } from "@ember/component/template-only";
10
+
11
+ export interface Signature<Value = any> {
12
+ Element: HTMLButtonElement;
13
+ Args: {
14
+ /**
15
+ * The pressed-state of the toggle.
16
+ *
17
+ * Can be used to control the state of the component.
18
+ */
19
+ pressed?: boolean;
20
+ /**
21
+ * Callback for when the toggle's state is changed.
22
+ *
23
+ * Can be used to control the state of the component.
24
+ *
25
+ * if a `@value` is passed to this `<Toggle>`, that @value will
26
+ * be passed to the `@onChange` handler.
27
+ *
28
+ * This can be useful when using the same function for the `@onChange`
29
+ * handler with multiple `<Toggle>` components.
30
+ */
31
+ onChange?: (value: Value | undefined, pressed: boolean) => void;
32
+
33
+ /**
34
+ * When used in a group of Toggles, this option will be helpful to
35
+ * know which toggle was pressed if you're using the same @onChange
36
+ * handler for multiple toggles.
37
+ */
38
+ value?: Value;
39
+
40
+ /**
41
+ * When controlling state in a wrapping component, this function can be used in conjunction with `@value` to determine if this `<Toggle>` should appear pressed.
42
+ */
43
+ isPressed?: (value?: Value) => boolean;
44
+ };
45
+ Blocks: {
46
+ default: [
47
+ /**
48
+ * the current pressed state of the toggle button
49
+ *
50
+ * Useful when using the toggle button as an uncontrolled component
51
+ */
52
+ pressed: boolean,
53
+ ];
54
+ };
55
+ }
56
+
57
+ function isPressed(
58
+ pressed?: boolean,
59
+ value?: unknown,
60
+ isPressed?: (value?: unknown) => boolean,
61
+ ): boolean {
62
+ if (!value) return Boolean(pressed);
63
+ if (!isPressed) return Boolean(pressed);
64
+
65
+ return isPressed(value);
66
+ }
67
+
68
+ export const Toggle: TOC<Signature> = <template>
69
+ {{#let (cell (isPressed @pressed @value @isPressed)) as |pressed|}}
70
+ <button
71
+ type="button"
72
+ aria-pressed="{{pressed.current}}"
73
+ {{on "click" (fn toggleWithFallback pressed.toggle @onChange @value)}}
74
+ ...attributes
75
+ >
76
+ {{yield pressed.current}}
77
+ </button>
78
+ {{/let}}
79
+ </template>;
80
+
81
+ export default Toggle;
@@ -0,0 +1,105 @@
1
+ span[data-prim-avatar]:has(img[alt="__missing__"])::after,
2
+ [aria-label="__missing__"] {
3
+ border: red;
4
+ }
5
+ label [aria-label="__missing__"] {
6
+ border: unset;
7
+ }
8
+
9
+ /**
10
+ * ExternalLink
11
+ */
12
+ a[href='##missing##'],
13
+ /**
14
+ * Avatar
15
+ */
16
+ span[data-prim-avatar]:has(img[alt='__missing__'])::after,
17
+ /**
18
+ * Switch
19
+ */
20
+ div[data-prim-switch]:has(input[role="switch"]):not(:has(label)) input[role="switch"] {
21
+ position: relative;
22
+ border: 1px solid black;
23
+ padding: 0.125rem 0.25rem;
24
+ border-radius: 0.125rem;
25
+ min-width: 10px;
26
+ }
27
+
28
+ :is(
29
+ /**
30
+ * ExternalLink
31
+ */
32
+ a[href='##missing##'],
33
+ /**
34
+ * Avatar
35
+ */
36
+ span[data-prim-avatar]:has(img[alt='__missing__'])::after,
37
+ /**
38
+ * Switch
39
+ */
40
+ div[data-prim-switch]:not(:has(label)):has(input[role="switch"]) input[role="switch"]
41
+ )::after {
42
+ color: red;
43
+ position: absolute;
44
+ font-size: 0.75rem;
45
+ font-family: monospace;
46
+ background: black;
47
+ padding: 0.125rem 0.25rem;
48
+ display: flex;
49
+ border-radius: 0.125rem;
50
+ transform: translate(0.5rem, 1rem);
51
+ left: 0;
52
+ bottom: 0;
53
+ width: max-content;
54
+ z-index: 10000000000000000;
55
+ }
56
+
57
+ a[href="##missing##"]::after {
58
+ content: "empty href";
59
+ }
60
+
61
+ span[data-prim-avatar]:has(img[alt="__missing__"])::after {
62
+ content: "missing alt";
63
+ }
64
+
65
+ div[data-prim-switch]:not(:has(label)):has(input[role="switch"]) input[role="switch"]::after {
66
+ content: "missing label";
67
+ }
68
+
69
+ @media (prefers-color-scheme: light) {
70
+ :is(
71
+ a[href="##missing##"],
72
+ span[data-prim-avatar]:has(img[alt="__missing__"]),
73
+ div[data-prim-switch]:has(input[role="switch"]):not(:has(label)) input[role="switch"]
74
+ ) {
75
+ border-color: black;
76
+ }
77
+ :is(
78
+ a[href="##missing##"],
79
+ span[data-prim-avatar]:has(img[alt="__missing__"]),
80
+ div[data-prim-switch]:not(:has(label)):has(input[role="switch"]) input[role="switch"]
81
+ ):after {
82
+ background: white;
83
+ border: 1px solid black;
84
+ color: darkred;
85
+ }
86
+ }
87
+
88
+ @media (prefers-color-scheme: dark) {
89
+ :is(
90
+ a[href="##missing##"],
91
+ span[data-prim-avatar]:has(img[alt="__missing__"]),
92
+ div[data-prim-switch]:has(input[role="switch"]):not(:has(label)) input[role="switch"]
93
+ ) {
94
+ border-color: red;
95
+ }
96
+ :is(
97
+ a[href="##missing##"],
98
+ span[data-prim-avatar]:has(img[alt="__missing__"]),
99
+ div[data-prim-switch]:not(:has(label)):has(input[role="switch"]) input[role="switch"]
100
+ ):after {
101
+ background: #222;
102
+ border: 1px solid red;
103
+ color: red;
104
+ }
105
+ }
@@ -0,0 +1 @@
1
+ import './violations.css';
@@ -0,0 +1,14 @@
1
+ /* See: https://github.com/twbs/bootstrap/blob/main/scss/mixins/_visually-hidden.scss */
2
+ .ember-primitives__visually-hidden,
3
+ [visually-hidden] {
4
+ position: absolute;
5
+ border: 0;
6
+ width: 1px;
7
+ height: 1px;
8
+ padding: 0;
9
+ margin: -1px;
10
+ overflow: hidden;
11
+ clip: rect(0, 0, 0, 0);
12
+ white-space: nowrap;
13
+ word-wrap: normal;
14
+ }
@@ -0,0 +1,15 @@
1
+ import "./visually-hidden.css";
2
+
3
+ import type { TOC } from "@ember/component/template-only";
4
+
5
+ export const VisuallyHidden: TOC<{
6
+ Element: HTMLSpanElement;
7
+ Blocks: {
8
+ /**
9
+ * Content to hide visually
10
+ */
11
+ default: [];
12
+ };
13
+ }> = <template>
14
+ <span class="ember-primitives__visually-hidden" ...attributes>{{yield}}</span>
15
+ </template>;