Skip to content

Commit b1b81d5

Browse files
committed
feat: updated Switch for MDC v10
1 parent 278806b commit b1b81d5

File tree

9 files changed

+833
-856
lines changed

9 files changed

+833
-856
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ Update Progress Checklist:
235235
- [ ] Select Helper Text
236236
- [ ] Select Icon
237237
- [x] Sliders
238-
- [ ] Switches
238+
- [x] Switches
239239
- [ ] Text Field
240240
- [ ] Text Field Character Counter
241241
- [ ] Text Field Helper Text

packages/checkbox/Checkbox.svelte

-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
: null}
5151
on:change={handleChange}
5252
on:change={() => instance && instance.handleChange()}
53-
on:input={handleChange}
5453
on:change
5554
on:input
5655
on:blur

packages/switch/Switch.svelte

+122-72
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
'mdc-switch': true,
88
'mdc-switch--disabled': disabled,
99
'mdc-switch--checked': nativeChecked,
10+
...internalClasses,
1011
})}
1112
{...exclude($$props, [
1213
'use',
@@ -19,44 +20,61 @@
1920
])}
2021
>
2122
<div class="mdc-switch__track" />
22-
<div class="mdc-switch__thumb-underlay">
23-
<div class="mdc-switch__thumb">
24-
<input
25-
use:useActions={input$use}
26-
class={classMap({
27-
[input$class]: true,
28-
'mdc-switch__native-control': true,
29-
})}
30-
type="checkbox"
31-
role="switch"
32-
{...inputProps}
33-
{disabled}
34-
bind:checked={nativeChecked}
35-
value={valueKey === uninitializedValue ? value : valueKey}
36-
on:change={handleChange}
37-
on:change
38-
on:input
39-
on:blur
40-
on:focus
41-
{...exclude(prefixFilter($$props, 'input$'), ['use', 'class'])}
42-
/>
43-
</div>
23+
<div
24+
class={classMap({
25+
'mdc-switch__thumb-underlay': true,
26+
...thumbUnderlayClasses,
27+
})}
28+
use:Ripple={{
29+
unbounded: true,
30+
addClass: addThumbUnderlayClass,
31+
removeClass: removeThumbUnderlayClass,
32+
active: rippleActive,
33+
}}
34+
>
35+
<div class="mdc-switch__thumb" />
36+
<input
37+
use:useActions={input$use}
38+
class={classMap({
39+
[input$class]: true,
40+
'mdc-switch__native-control': true,
41+
})}
42+
type="checkbox"
43+
role="switch"
44+
{...inputProps}
45+
{disabled}
46+
bind:checked={nativeChecked}
47+
aria-checked={nativeChecked ? 'true' : 'false'}
48+
value={valueKey === uninitializedValue ? value : valueKey}
49+
on:change={handleChange}
50+
on:change={(event) => instance && instance.handleChange(event)}
51+
on:change
52+
on:input
53+
on:blur
54+
on:focus
55+
{...internalAttrs}
56+
{...exclude(prefixFilter($$props, 'input$'), ['use', 'class'])}
57+
/>
4458
</div>
4559
</div>
4660

4761
<script>
48-
import { MDCSwitch } from '@material/switch';
49-
import { onMount, onDestroy, getContext } from 'svelte';
62+
import { MDCSwitchFoundation } from '@material/switch';
63+
import { onMount, getContext } from 'svelte';
5064
import { get_current_component } from 'svelte/internal';
5165
import {
5266
forwardEventsBuilder,
5367
classMap,
5468
exclude,
5569
prefixFilter,
5670
useActions,
71+
dispatch,
5772
} from '@smui/common/internal.js';
73+
import Ripple from '@smui/ripple/bare.js';
5874
59-
const forwardEvents = forwardEventsBuilder(get_current_component());
75+
const forwardEvents = forwardEventsBuilder(get_current_component(), [
76+
'SMUI:generic:input:mount',
77+
]);
6078
let uninitializedValue = () => {};
6179
6280
export let use = [];
@@ -71,8 +89,12 @@
7189
export let input$class = '';
7290
7391
let element;
74-
let switchControl;
75-
let formField = getContext('SMUI:form-field');
92+
let instance;
93+
let internalClasses = {};
94+
let thumbUnderlayClasses = {};
95+
// These are added to the native control, not `element`.
96+
let internalAttrs = {};
97+
let rippleActive = false;
7698
let inputProps = getContext('SMUI:generic:input:props') || {};
7799
let setChecked = getContext('SMUI:generic:input:setChecked');
78100
let nativeChecked =
@@ -82,73 +104,101 @@
82104
: checked
83105
: group.indexOf(value) !== -1;
84106
85-
$: if (switchControl && $formField && $formField.input !== switchControl) {
86-
$formField.input = switchControl;
87-
}
88-
89107
$: if (setChecked) {
90108
setChecked(nativeChecked);
91109
}
92110
93-
$: if (switchControl) {
94-
if (group !== uninitializedValue) {
95-
const isChecked = group.indexOf(value) !== -1;
96-
if (switchControl.checked !== isChecked) {
97-
switchControl.checked = isChecked;
98-
}
99-
} else if (
100-
checked !== uninitializedValue &&
101-
switchControl.checked !== checked
102-
) {
103-
switchControl.checked = checked;
104-
}
105-
}
106-
107-
$: if (switchControl && switchControl.disabled !== disabled) {
108-
switchControl.disabled = disabled;
109-
}
110-
111-
$: if (
112-
switchControl &&
113-
valueKey === uninitializedValue &&
114-
switchControl.value !== value
115-
) {
116-
switchControl.value = value;
117-
}
118-
119-
$: if (
120-
switchControl &&
121-
valueKey !== uninitializedValue &&
122-
switchControl.value !== valueKey
123-
) {
124-
switchControl.value = valueKey;
125-
}
126-
127111
let previousChecked = checked;
128112
$: if (checked !== uninitializedValue) {
129113
if (checked === previousChecked) {
130114
checked = nativeChecked;
131115
} else if (nativeChecked !== checked) {
132116
nativeChecked = checked;
117+
instance && instance.handleChange();
133118
}
134119
previousChecked = checked;
135120
}
136121
137122
onMount(() => {
138-
switchControl = new MDCSwitch(element);
123+
instance = new MDCSwitchFoundation({
124+
addClass,
125+
removeClass,
126+
setNativeControlChecked: (checked) => (nativeChecked = checked),
127+
setNativeControlDisabled: (disabledValue) => (disabled = disabledValue),
128+
setNativeControlAttr: addAttr,
129+
});
130+
131+
dispatch(element, 'SMUI:generic:input:mount', {
132+
get element() {
133+
return getElement();
134+
},
135+
get checked() {
136+
return nativeChecked;
137+
},
138+
set checked(checked) {
139+
if (nativeChecked !== checked) {
140+
nativeChecked = checked;
141+
handleChange();
142+
instance && instance.handleChange();
143+
}
144+
},
145+
activateRipple() {
146+
if (!disabled) {
147+
rippleActive = true;
148+
}
149+
},
150+
deactivateRipple() {
151+
rippleActive = false;
152+
},
153+
});
154+
155+
instance.init();
156+
157+
return () => {
158+
instance.destroy();
159+
};
139160
});
140161
141-
onDestroy(() => {
142-
switchControl && switchControl.destroy();
143-
});
162+
function addClass(className) {
163+
if (!internalClasses[className]) {
164+
internalClasses[className] = true;
165+
}
166+
}
167+
168+
function removeClass(className) {
169+
if (!(className in internalClasses) || internalClasses[className]) {
170+
internalClasses[className] = false;
171+
}
172+
}
173+
174+
function addThumbUnderlayClass(className) {
175+
if (!thumbUnderlayClasses[className]) {
176+
thumbUnderlayClasses[className] = true;
177+
}
178+
}
179+
180+
function removeThumbUnderlayClass(className) {
181+
if (
182+
!(className in thumbUnderlayClasses) ||
183+
thumbUnderlayClasses[className]
184+
) {
185+
thumbUnderlayClasses[className] = false;
186+
}
187+
}
188+
189+
function addAttr(name, value) {
190+
if (internalAttrs[name] !== value) {
191+
internalAttrs[name] = value;
192+
}
193+
}
144194
145-
function handleChange(e) {
195+
function handleChange() {
146196
if (group !== uninitializedValue) {
147197
const idx = group.indexOf(value);
148-
if (switchControl.checked && idx === -1) {
198+
if (nativeChecked && idx === -1) {
149199
group.push(value);
150200
group = group;
151-
} else if (!switchControl.checked && idx !== -1) {
201+
} else if (!nativeChecked && idx !== -1) {
152202
group.splice(idx, 1);
153203
group = group;
154204
}

packages/switch/_index.scss

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
@import "smui-theme";
2-
@import "./style";
1+
@use 'smui-theme';
2+
@use './style';

packages/switch/_style.scss

+4-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
@import "@material/switch/mdc-switch";
1+
@use '@material/switch';
2+
@use '@smui/ripple/style';
3+
4+
@include switch.core-styles;

0 commit comments

Comments
 (0)