ember-primitives 0.49.0 → 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.
- package/bin/index.mjs +271 -0
- package/declarations/components/rating/public-types.d.ts +0 -4
- package/declarations/components/rating/public-types.d.ts.map +1 -1
- package/declarations/components/rating/rating.d.ts +9 -1
- package/declarations/components/rating/rating.d.ts.map +1 -1
- package/declarations/components/rating/stars.d.ts.map +1 -1
- package/declarations/components/rating/state.d.ts +4 -0
- package/declarations/components/rating/state.d.ts.map +1 -1
- package/declarations/components/rating/utils.d.ts +0 -1
- package/declarations/components/rating/utils.d.ts.map +1 -1
- package/dist/components/rating.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{rating-CjBVsX6q.js → rating-BrIiwDLw.js} +21 -17
- package/dist/rating-BrIiwDLw.js.map +1 -0
- package/package.json +6 -2
- package/src/-private.ts +4 -0
- package/src/color-scheme.ts +165 -0
- package/src/components/-private/typed-elements.gts +13 -0
- package/src/components/-private/utils.ts +16 -0
- package/src/components/accordion/content.gts +34 -0
- package/src/components/accordion/header.gts +36 -0
- package/src/components/accordion/item.gts +55 -0
- package/src/components/accordion/public.ts +64 -0
- package/src/components/accordion/trigger.gts +32 -0
- package/src/components/accordion.gts +195 -0
- package/src/components/avatar.gts +108 -0
- package/src/components/dialog.gts +234 -0
- package/src/components/external-link.gts +14 -0
- package/src/components/form.gts +75 -0
- package/src/components/heading.gts +36 -0
- package/src/components/keys.gts +53 -0
- package/src/components/layout/hero.css +5 -0
- package/src/components/layout/hero.gts +17 -0
- package/src/components/layout/sticky-footer.css +9 -0
- package/src/components/layout/sticky-footer.gts +40 -0
- package/src/components/link.gts +172 -0
- package/src/components/menu.gts +373 -0
- package/src/components/one-time-password/buttons.gts +31 -0
- package/src/components/one-time-password/input.gts +198 -0
- package/src/components/one-time-password/otp.gts +130 -0
- package/src/components/one-time-password/utils.ts +201 -0
- package/src/components/one-time-password.gts +2 -0
- package/src/components/popover.gts +248 -0
- package/src/components/portal-targets.gts +136 -0
- package/src/components/portal.gts +194 -0
- package/src/components/progress.gts +154 -0
- package/src/components/rating/public-types.ts +44 -0
- package/src/components/rating/range.gts +22 -0
- package/src/components/rating/rating.gts +228 -0
- package/src/components/rating/stars.gts +60 -0
- package/src/components/rating/state.gts +144 -0
- package/src/components/rating/utils.ts +7 -0
- package/src/components/rating.gts +5 -0
- package/src/components/scroller.gts +179 -0
- package/src/components/shadowed.gts +110 -0
- package/src/components/switch.gts +103 -0
- package/src/components/tabs.gts +519 -0
- package/src/components/toggle-group.gts +265 -0
- package/src/components/toggle.gts +81 -0
- package/src/components/violations.css +105 -0
- package/src/components/violations.css.ts +1 -0
- package/src/components/visually-hidden.css +14 -0
- package/src/components/visually-hidden.gts +15 -0
- package/src/components/zoetrope/index.gts +358 -0
- package/src/components/zoetrope/styles.css +40 -0
- package/src/components/zoetrope/types.ts +65 -0
- package/src/components/zoetrope.ts +3 -0
- package/src/dom-context.gts +245 -0
- package/src/floating-ui/component.gts +186 -0
- package/src/floating-ui/middleware.ts +13 -0
- package/src/floating-ui/modifier.ts +183 -0
- package/src/floating-ui.ts +2 -0
- package/src/head.gts +37 -0
- package/src/helpers/body-class.ts +94 -0
- package/src/helpers/link.ts +125 -0
- package/src/helpers/service.ts +25 -0
- package/src/helpers.ts +2 -0
- package/src/iframe.ts +31 -0
- package/src/index.ts +43 -0
- package/src/load.gts +77 -0
- package/src/narrowing.ts +7 -0
- package/src/on-resize.ts +64 -0
- package/src/proper-links.ts +140 -0
- package/src/qp.ts +107 -0
- package/src/resize-observer.ts +132 -0
- package/src/service.ts +103 -0
- package/src/store.ts +72 -0
- package/src/styles.css.ts +5 -0
- package/src/tabster.ts +54 -0
- package/src/template-registry.ts +44 -0
- package/src/test-support/a11y.ts +50 -0
- package/src/test-support/dom.ts +112 -0
- package/src/test-support/otp.ts +64 -0
- package/src/test-support/rating.ts +144 -0
- package/src/test-support/routing.ts +62 -0
- package/src/test-support/zoetrope.ts +51 -0
- package/src/test-support.gts +6 -0
- package/src/type-utils.ts +1 -0
- package/src/utils.ts +75 -0
- package/src/viewport/in-viewport.gts +128 -0
- package/src/viewport/viewport.ts +122 -0
- package/src/viewport.ts +2 -0
- package/dist/rating-CjBVsX6q.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>;
|