Skip to content

Commit a815d3c

Browse files
committed
Some tests were missing
1 parent efcee4e commit a815d3c

3 files changed

Lines changed: 144 additions & 67 deletions

File tree

docs-app/public/docs/3-ui/switch.md

Lines changed: 77 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -62,79 +62,86 @@ const toggleTheme = (e) =>
6262
6363
* {box-sizing: border-box;}
6464
65-
div {
66-
padding: 1rem;
67-
font-family: "Montserrat", sans-serif;
68-
background-color: #eee;
69-
display: flex;
70-
justify-content: center;
71-
align-items: center;
72-
flex-direction: column;
73-
text-align: center;
74-
margin: 0;
75-
transition: background 0.2s linear;
76-
width: 100%;
77-
}
65+
@scope {
66+
div {
67+
padding: 1rem;
68+
font-family: "Montserrat", sans-serif;
69+
background-color: #eee;
70+
display: flex;
71+
justify-content: center;
72+
align-items: center;
73+
flex-direction: column;
74+
text-align: center;
75+
margin: 0;
76+
transition: background 0.2s linear;
77+
width: 100%;
78+
}
7879
79-
div.dark {background-color: #292c35;}
80-
div.dark label { background-color: #9b59b6; }
80+
div.dark {background-color: #292c35;}
81+
div.dark label { background-color: #9b59b6; }
8182
8283
83-
input[type='checkbox'][role='switch'] {
84-
opacity: 0;
85-
position: absolute;
86-
}
84+
input[type='checkbox'][role='switch'] {
85+
opacity: 0;
86+
position: absolute;
87+
}
8788
88-
.sr-only {
89-
width: 0px;
90-
max-width: 0px;
91-
height: 0px;
92-
max-height: 0px;
93-
overflow: hidden;
94-
margin-left: -0.5rem;
95-
}
89+
.sr-only {
90+
width: 0px;
91+
max-width: 0px;
92+
height: 0px;
93+
max-height: 0px;
94+
overflow: hidden;
95+
margin-left: -0.5rem;
96+
}
9697
97-
label {
98-
background-color: #aaaaff;
99-
border: 1px solid;
100-
width: 60px;
101-
height: 32px;
102-
border-radius: 50px;
103-
position: relative;
104-
padding: 5px;
105-
cursor: pointer;
106-
display: flex;
107-
justify-content: space-between;
108-
align-items: center;
109-
gap: 0.5rem;
110-
}
98+
label {
99+
background-color: #aaaaff;
100+
border: 1px solid;
101+
width: 60px;
102+
height: 32px;
103+
border-radius: 50px;
104+
position: relative;
105+
padding: 5px;
106+
cursor: pointer;
107+
display: flex;
108+
justify-content: space-between;
109+
align-items: center;
110+
gap: 0.5rem;
111+
}
111112
112-
svg { fill: currentColor; position: absolute; top: 3px; left: 3px; }
113-
.fa-moon { color: #f1c40f; }
114-
.sun { color: #f39c12; }
115-
116-
label .ball {
117-
background-color: #111;
118-
width: 26px;
119-
height: 26px;
120-
position: absolute;
121-
left: 2px;
122-
top: 2px;
123-
border-radius: 50%;
124-
transition-property: transform;
125-
transition-duration: 0.2s;
126-
transition-timing-function: linear(0, 0.1, 0.25, 0.5, 0.68, 0.8, 0.88, 0.94, 0.98, 0.995, 1);;
127-
border: 2px solid #f1c40f;
128-
129-
&[data-state="on"] {
130-
border: 2px solid purple;
113+
svg { fill: currentColor; position: absolute; top: 3px; left: 3px; }
114+
.moon { color: #f1c4ff; }
115+
.sun { color: #f39c12; }
116+
117+
label .ball {
118+
background-color: #111;
119+
width: 26px;
120+
height: 26px;
121+
position: absolute;
122+
left: 2px;
123+
top: 2px;
124+
border-radius: 50%;
125+
transition-property: transform filter;
126+
transition-duration: 0.2s;
127+
transition-timing-function: linear(0, 0.1, 0.25, 0.5, 0.68, 0.8, 0.88, 0.94, 0.98, 0.995, 1);;
128+
border: 2px solid #f1c40f;
129+
130+
&[data-state="on"] {
131+
border: 2px solid #f1c4ff;
132+
}
131133
}
132-
}
133134
134-
input[type='checkbox'][role='switch']:checked + label .ball {
135-
transform: translateX(28px);
135+
label:active .ball {
136+
filter: drop-shadow(0 0 10px #f1c40f);
137+
}
138+
input[type='checkbox'][role='switch']:checked + label .ball {
139+
transform: translateX(28px);
140+
}
141+
input[type='checkbox'][role='switch']:checked:active + label .ball {
142+
filter: drop-shadow(0 0 10px #f1c4ff);
143+
}
136144
}
137-
138145
</style>
139146
</Shadowed>
140147
</template>
@@ -286,3 +293,9 @@ Adheres to the `switch` [role requirements](https://www.w3.org/WAI/ARIA/apg/patt
286293
| <kbd>Enter</kbd> | Toggles the component's state |
287294

288295
In addition, a label is required so that users know what the switch is for.
296+
297+
## References
298+
299+
- https://web.dev/articles/building/a-switch-component
300+
- https://getbootstrap.com/docs/5.3/forms/checks-radios/#switches
301+
- https://web.dev/articles/building/a-switch-component

ember-primitives/src/components/switch.gts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,27 @@ export interface Signature {
2727
Blocks: {
2828
default?: [
2929
{
30+
/**
31+
* The current state of the Switch.
32+
*
33+
* ```gjs
34+
* import { Switch } from 'ember-primitives/components/switch';
35+
*
36+
* <template>
37+
* <Switch as |s|>
38+
* {{s.isChecked}}
39+
* </Switch>
40+
* </template>
41+
* ```
42+
*/
43+
isChecked: boolean;
3044
/**
3145
* The Switch Element.
3246
* It has a pre-wired `id` so that the relevant Label is
3347
* appropriately associated via the `for` property of the Label.
3448
*
3549
* ```gjs
36-
* import { Switch } from 'ember-primitives';
50+
* import { Switch } from 'ember-primitives/components/switch';
3751
*
3852
* <template>
3953
* <Switch as |s|>
@@ -48,7 +62,7 @@ export interface Signature {
4862
* the association to the Control by setting the `for` attribute to the `id` of the Control
4963
*
5064
* ```gjs
51-
* import { Switch } from 'ember-primitives';
65+
* import { Switch } from 'ember-primitive/components/switchs';
5266
*
5367
* <template>
5468
* <Switch as |s|>
@@ -81,13 +95,17 @@ const Checkbox: TOC<ControlSignature> = <template>
8195
/>
8296
</template>;
8397

98+
function defaultFalse(value: unknown) {
99+
return value ?? false;
100+
}
101+
84102
/**
85103
* @public
86104
*/
87105
export const Switch: TOC<Signature> = <template>
88106
<div ...attributes data-prim-switch>
89107
{{#let (uniqueId) as |id|}}
90-
{{#let (cell @checked) as |checked|}}
108+
{{#let (cell (defaultFalse @checked)) as |checked|}}
91109
{{! @glint-nocheck }}
92110
{{yield
93111
(hash
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { click, render } from '@ember/test-helpers';
2+
import { module, test } from 'qunit';
3+
import { setupRenderingTest } from 'ember-qunit';
4+
5+
import { Switch } from 'ember-primitives/components/switch';
6+
7+
module('Switch', function (hooks) {
8+
setupRenderingTest(hooks);
9+
10+
test('it yields only 3 things', async function (assert) {
11+
let keys: any = [];
12+
const capture = (obj: any) => (keys = Object.keys(obj));
13+
14+
await render(
15+
<template>
16+
<Switch as |s|>
17+
{{! @glint-expect-error }}
18+
{{capture s}}
19+
</Switch>
20+
</template>
21+
);
22+
assert.deepEqual(keys, ['isChecked', 'Control', 'Label']);
23+
});
24+
25+
test('togglin', async function (assert) {
26+
const capture = (x: boolean) => assert.step(String(x));
27+
28+
await render(
29+
<template>
30+
<Switch as |s|>
31+
{{capture s.isChecked}}
32+
<s.Control />
33+
<s.Label>hi</s.Label>
34+
</Switch>
35+
</template>
36+
);
37+
38+
assert.verifySteps(['false']);
39+
40+
await click('[role=switch]');
41+
assert.verifySteps(['true']);
42+
43+
await click('[role=switch]');
44+
assert.verifySteps(['false']);
45+
});
46+
});

0 commit comments

Comments
 (0)