Skip to content

Commit 605ca35

Browse files
committed
feat: migrate components in floating label, line ripple, and notched outline to runes
1 parent 7233ecc commit 605ca35

File tree

4 files changed

+141
-76
lines changed

4 files changed

+141
-76
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,10 @@ Svelte 5 Runes mode is being migrated to slowly. This is the todo list of compon
169169
- [x] Checkbox
170170
- [ ] Chips
171171
- [ ] Chip Input
172-
- [ ] Floating Label
172+
- [x] Floating Label
173173
- [x] Form Field
174-
- [ ] Line Ripple
175-
- [ ] Notched Outline
174+
- [x] Line Ripple
175+
- [x] Notched Outline
176176
- [x] Radio Button
177177
- [ ] Segmented Button
178178
- [ ] Select Menu

packages/floating-label/src/FloatingLabel.svelte

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<svelte:options runes={false} />
1+
<svelte:options runes />
22

33
{#if wrapped}
44
<span
@@ -15,7 +15,7 @@
1515
.map(([name, value]) => `${name}: ${value};`)
1616
.concat([style])
1717
.join(' ')}
18-
{...$$restProps}><slot /></span
18+
{...restProps}>{@render children?.()}</span
1919
>
2020
{:else}
2121
<label
@@ -33,12 +33,13 @@
3333
.concat([style])
3434
.join(' ')}
3535
for={forId || (inputProps ? inputProps.id : undefined)}
36-
{...$$restProps}><slot /></label
36+
{...restProps}>{@render children?.()}</label
3737
>
3838
{/if}
3939

4040
<script lang="ts">
4141
import { MDCFloatingLabelFoundation } from '@material/floating-label';
42+
import type { Snippet } from 'svelte';
4243
import { onMount, getContext } from 'svelte';
4344
import type { SmuiAttrs } from '@smui/common';
4445
import type { ActionArray } from '@smui/common/internal';
@@ -47,46 +48,75 @@
4748
import type { SMUIFloatingLabelAccessor } from './FloatingLabel.types.js';
4849
4950
type OwnProps = {
51+
/**
52+
* An array of Action or [Action, ActionProps] to be applied to the element.
53+
*/
5054
use?: ActionArray;
55+
/**
56+
* A space separated list of CSS classes.
57+
*/
5158
class?: string;
59+
/**
60+
* A list of CSS styles.
61+
*/
5262
style?: string;
63+
/**
64+
* The ID that this label is for.
65+
*/
5366
for?: string | undefined;
67+
/**
68+
* Whether to float the label.
69+
*/
5470
floatAbove?: boolean;
71+
/**
72+
* Whether to style for a required input.
73+
*/
5574
required?: boolean;
75+
/**
76+
* Whether the input is already wrapped in a label.
77+
*
78+
* If not, a label element will be used with the ID value in the `for` prop.
79+
*/
5680
wrapped?: boolean;
81+
82+
children?: Snippet;
5783
};
58-
type $$Props = SmuiAttrs<'span', keyof OwnProps> &
84+
let {
85+
use = [],
86+
class: className = '',
87+
style = '',
88+
for: forId,
89+
floatAbove = $bindable(false),
90+
required = $bindable(false),
91+
wrapped = false,
92+
children,
93+
...restProps
94+
}: SmuiAttrs<'span', keyof OwnProps> &
5995
SmuiAttrs<'label', keyof OwnProps> &
60-
OwnProps;
61-
62-
export let use: ActionArray = [];
63-
let className = '';
64-
export { className as class };
65-
export let style = '';
66-
let forId: string | undefined = undefined;
67-
export { forId as for };
68-
export let floatAbove = false;
69-
export let required = false;
70-
export let wrapped = false;
96+
OwnProps = $props();
7197
7298
let element: HTMLSpanElement | HTMLLabelElement;
73-
let instance: MDCFloatingLabelFoundation;
74-
let internalClasses: { [k: string]: boolean } = {};
75-
let internalStyles: { [k: string]: string } = {};
99+
let instance: MDCFloatingLabelFoundation | undefined = $state();
100+
let internalClasses: { [k: string]: boolean } = $state({});
101+
let internalStyles: { [k: string]: string } = $state({});
76102
let inputProps =
77103
getContext<{ id?: string } | undefined>('SMUI:generic:input:props') ?? {};
78104
79105
let previousFloatAbove = floatAbove;
80-
$: if (instance && previousFloatAbove !== floatAbove) {
81-
previousFloatAbove = floatAbove;
82-
instance.float(floatAbove);
83-
}
106+
$effect(() => {
107+
if (instance && previousFloatAbove !== floatAbove) {
108+
previousFloatAbove = floatAbove;
109+
instance.float(floatAbove);
110+
}
111+
});
84112
85113
let previousRequired = required;
86-
$: if (instance && previousRequired !== required) {
87-
previousRequired = required;
88-
instance.setRequired(required);
89-
}
114+
$effect(() => {
115+
if (instance && previousRequired !== required) {
116+
previousRequired = required;
117+
instance.setRequired(required);
118+
}
119+
});
90120
91121
const SMUIFloatingLabelMount = getContext<
92122
((accessor: SMUIFloatingLabelAccessor) => void) | undefined
@@ -131,7 +161,7 @@
131161
return () => {
132162
SMUIFloatingLabelUnmount && SMUIFloatingLabelUnmount(accessor);
133163
134-
instance.destroy();
164+
instance?.destroy();
135165
};
136166
});
137167
@@ -166,7 +196,7 @@
166196
}
167197
168198
export function shake(shouldShake: boolean) {
169-
instance.shake(shouldShake);
199+
instance?.shake(shouldShake);
170200
}
171201
172202
export function float(shouldFloat: boolean) {
@@ -178,6 +208,9 @@
178208
}
179209
180210
export function getWidth() {
211+
if (instance == null) {
212+
throw new Error('Instance is undefined.');
213+
}
181214
return instance.getWidth();
182215
}
183216

packages/line-ripple/src/LineRipple.svelte

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<svelte:options runes={false} />
1+
<svelte:options runes />
22

33
<div
44
bind:this={element}
@@ -13,7 +13,7 @@
1313
.map(([name, value]) => `${name}: ${value};`)
1414
.concat([style])
1515
.join(' ')}
16-
{...$$restProps}
16+
{...restProps}
1717
></div>
1818

1919
<script lang="ts">
@@ -24,24 +24,35 @@
2424
import { classMap, useActions } from '@smui/common/internal';
2525
2626
type OwnProps = {
27+
/**
28+
* An array of Action or [Action, ActionProps] to be applied to the element.
29+
*/
2730
use?: ActionArray;
31+
/**
32+
* A space separated list of CSS classes.
33+
*/
2834
class?: string;
35+
/**
36+
* A list of CSS styles.
37+
*/
2938
style?: string;
39+
/**
40+
* Whether the line is active.
41+
*/
3042
active?: boolean;
3143
};
32-
type $$Props = OwnProps & SmuiAttrs<'div', keyof OwnProps>;
33-
34-
// Remember to update $$Props if you add/remove/rename props.
35-
export let use: ActionArray = [];
36-
let className = '';
37-
export { className as class };
38-
export let style = '';
39-
export let active = false;
44+
let {
45+
use = [],
46+
class: className = '',
47+
style = '',
48+
active = false,
49+
...restProps
50+
}: OwnProps & SmuiAttrs<'div', keyof OwnProps> = $props();
4051
4152
let element: HTMLDivElement;
42-
let instance: MDCLineRippleFoundation;
43-
let internalClasses: { [k: string]: boolean } = {};
44-
let internalStyles: { [k: string]: string } = {};
53+
let instance: MDCLineRippleFoundation | undefined = $state();
54+
let internalClasses: { [k: string]: boolean } = $state({});
55+
let internalStyles: { [k: string]: string } = $state({});
4556
4657
onMount(() => {
4758
instance = new MDCLineRippleFoundation({
@@ -58,7 +69,7 @@
5869
instance.init();
5970
6071
return () => {
61-
instance.destroy();
72+
instance?.destroy();
6273
};
6374
});
6475
@@ -92,15 +103,15 @@
92103
}
93104
94105
export function activate() {
95-
instance.activate();
106+
instance?.activate();
96107
}
97108
98109
export function deactivate() {
99-
instance.deactivate();
110+
instance?.deactivate();
100111
}
101112
102113
export function setRippleCenter(xCoordinate: number) {
103-
instance.setRippleCenter(xCoordinate);
114+
instance?.setRippleCenter(xCoordinate);
104115
}
105116
106117
export function getElement() {

packages/notched-outline/src/NotchedOutline.svelte

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<svelte:options runes={false} />
1+
<svelte:options runes />
22

33
<div
44
bind:this={element}
@@ -10,7 +10,7 @@
1010
'mdc-notched-outline--no-label': noLabel,
1111
...internalClasses,
1212
})}
13-
{...$$restProps}
13+
{...restProps}
1414
>
1515
<div class="mdc-notched-outline__leading"></div>
1616
{#if !noLabel}
@@ -20,52 +20,73 @@
2020
.map(([name, value]) => `${name}: ${value};`)
2121
.join(' ')}
2222
>
23-
<slot />
23+
{@render children?.()}
2424
</div>
2525
{/if}
2626
<div class="mdc-notched-outline__trailing"></div>
2727
</div>
2828

2929
<script lang="ts">
3030
import { MDCNotchedOutlineFoundation } from '@material/notched-outline';
31+
import type { Snippet } from 'svelte';
3132
import { onMount, setContext } from 'svelte';
3233
import type { SmuiAttrs } from '@smui/common';
3334
import type { ActionArray } from '@smui/common/internal';
3435
import { classMap, useActions } from '@smui/common/internal';
3536
import type { SMUIFloatingLabelAccessor } from '@smui/floating-label';
3637
3738
type OwnProps = {
39+
/**
40+
* An array of Action or [Action, ActionProps] to be applied to the element.
41+
*/
3842
use?: ActionArray;
43+
/**
44+
* A space separated list of CSS classes.
45+
*/
3946
class?: string;
47+
/**
48+
* The notched state of the outline.
49+
*/
4050
notched?: boolean;
51+
/**
52+
* Don't render a label.
53+
*/
4154
noLabel?: boolean;
42-
};
43-
type $$Props = OwnProps & SmuiAttrs<'div', keyof OwnProps>;
4455
45-
// Remember to update $$Props if you add/remove/rename props.
46-
export let use: ActionArray = [];
47-
let className = '';
48-
export { className as class };
49-
export let notched = false;
50-
export let noLabel = false;
56+
children?: Snippet;
57+
};
58+
let {
59+
use = [],
60+
class: className = '',
61+
notched = false,
62+
noLabel = false,
63+
children,
64+
...restProps
65+
}: OwnProps & SmuiAttrs<'div', keyof OwnProps> = $props();
5166
5267
let element: HTMLDivElement;
53-
let instance: MDCNotchedOutlineFoundation;
54-
let floatingLabel: SMUIFloatingLabelAccessor | undefined;
55-
let internalClasses: { [k: string]: boolean } = {};
56-
let notchStyles: { [k: string]: string } = {};
57-
58-
$: if (floatingLabel) {
59-
floatingLabel.addStyle('transition-duration', '0s');
60-
addClass('mdc-notched-outline--upgraded');
61-
requestAnimationFrame(() => {
68+
let instance: MDCNotchedOutlineFoundation | undefined = $state();
69+
let floatingLabel: SMUIFloatingLabelAccessor | undefined = $state();
70+
let internalClasses: { [k: string]: boolean } = $state({});
71+
let notchStyles: { [k: string]: string } = $state({});
72+
73+
let previousFloatingLabel: SMUIFloatingLabelAccessor | undefined = undefined;
74+
$effect(() => {
75+
if (floatingLabel !== previousFloatingLabel) {
6276
if (floatingLabel) {
63-
floatingLabel.removeStyle('transition-duration');
77+
floatingLabel.addStyle('transition-duration', '0s');
78+
addClass('mdc-notched-outline--upgraded');
79+
requestAnimationFrame(() => {
80+
if (floatingLabel) {
81+
floatingLabel.removeStyle('transition-duration');
82+
}
83+
});
84+
} else {
85+
removeClass('mdc-notched-outline--upgraded');
6486
}
65-
});
66-
} else {
67-
removeClass('mdc-notched-outline--upgraded');
68-
}
87+
previousFloatingLabel = floatingLabel;
88+
}
89+
});
6990
7091
setContext(
7192
'SMUI:floating-label:mount',
@@ -88,7 +109,7 @@
88109
instance.init();
89110
90111
return () => {
91-
instance.destroy();
112+
instance?.destroy();
92113
};
93114
});
94115
@@ -123,11 +144,11 @@
123144
}
124145
125146
export function notch(notchWidth: number) {
126-
instance.notch(notchWidth);
147+
instance?.notch(notchWidth);
127148
}
128149
129150
export function closeNotch() {
130-
instance.closeNotch();
151+
instance?.closeNotch();
131152
}
132153
133154
export function getElement() {

0 commit comments

Comments
 (0)