|
1 |
| -<svelte:options runes={false} /> |
| 1 | +<svelte:options runes /> |
2 | 2 |
|
3 | 3 | <button
|
4 | 4 | bind:this={element}
|
|
25 | 25 | aria-pressed={!singleSelect ? (selected ? 'true' : 'false') : undefined}
|
26 | 26 | aria-checked={singleSelect ? (selected ? 'true' : 'false') : undefined}
|
27 | 27 | {...internalAttrs}
|
28 |
| - {...$$restProps} |
| 28 | + {...restProps} |
29 | 29 | onclick={(e) => {
|
30 |
| - $$restProps.onclick?.(e); |
| 30 | + restProps.onclick?.(e); |
31 | 31 | if (!e.defaultPrevented && instance && !manualSelection) {
|
32 | 32 | instance.handleClick();
|
33 | 33 | }
|
34 | 34 | }}
|
35 |
| - >{#if ripple}<div class="mdc-segmented-button__ripple"></div>{/if}<slot |
36 |
| - />{#if touch}<div |
| 35 | + >{#if ripple}<div |
| 36 | + class="mdc-segmented-button__ripple" |
| 37 | + ></div>{/if}{@render children?.()}{#if touch}<div |
37 | 38 | class="mdc-segmented-button__segment__touch"
|
38 | 39 | ></div>{/if}</button
|
39 | 40 | >
|
40 | 41 |
|
41 |
| -<script lang="ts"> |
| 42 | +<script lang="ts" generics="SegmentKey extends Object | string | number"> |
42 | 43 | // TODO: Remove this when MDC's segmented button is fixed.
|
43 | 44 | // TODO: Also remove @material/base and @material/ripple from the package.json
|
44 | 45 | // @ts-ignore
|
45 | 46 | import { MDCSegmentedButtonSegmentFoundation } from './mdc-segmented-button/index.js';
|
| 47 | + import type { Snippet } from 'svelte'; |
46 | 48 | import { onMount, getContext } from 'svelte';
|
47 | 49 | import type { SmuiAttrs } from '@smui/common';
|
48 | 50 | import type { ActionArray } from '@smui/common/internal';
|
|
51 | 53 |
|
52 | 54 | import type { SMUISegmentedButtonSegmentAccessor } from './Segment.types.js';
|
53 | 55 |
|
| 56 | + interface UninitializedValue extends Function {} |
| 57 | + let uninitializedValue: UninitializedValue = () => {}; |
| 58 | + function isUninitializedValue(value: any): value is UninitializedValue { |
| 59 | + return value === uninitializedValue; |
| 60 | + } |
| 61 | +
|
54 | 62 | type OwnProps = {
|
| 63 | + /** |
| 64 | + * An array of Action or [Action, ActionProps] to be applied to the element. |
| 65 | + */ |
55 | 66 | use?: ActionArray;
|
| 67 | + /** |
| 68 | + * A space separated list of CSS classes. |
| 69 | + */ |
56 | 70 | class?: string;
|
| 71 | + /** |
| 72 | + * A list of CSS styles. |
| 73 | + */ |
57 | 74 | style?: string;
|
58 |
| - segment: any; |
| 75 | + /** |
| 76 | + * The segment object this segment is for. |
| 77 | + */ |
| 78 | + segment: SegmentKey; |
| 79 | + /** |
| 80 | + * Whether to show a ripple animation. |
| 81 | + */ |
59 | 82 | ripple?: boolean;
|
| 83 | + /** |
| 84 | + * Whether to use touch styling |
| 85 | + */ |
60 | 86 | touch?: boolean;
|
| 87 | + /** |
| 88 | + * Whether this segment is selected. |
| 89 | + * |
| 90 | + * You don't need to set this unless you are manually handling selection. |
| 91 | + */ |
61 | 92 | selected?: boolean;
|
62 |
| - }; |
63 |
| - type $$Props = OwnProps & SmuiAttrs<'button', keyof OwnProps>; |
64 | 93 |
|
65 |
| - interface UninitializedValue extends Function {} |
66 |
| - let uninitializedValue: UninitializedValue = () => {}; |
67 |
| - function isUninitializedValue(value: any): value is UninitializedValue { |
68 |
| - return value === uninitializedValue; |
69 |
| - } |
| 94 | + children?: Snippet; |
| 95 | + }; |
| 96 | + let { |
| 97 | + use = [], |
| 98 | + class: className = '', |
| 99 | + style = '', |
| 100 | + segment: segmentId, |
| 101 | + ripple = true, |
| 102 | + touch = false, |
| 103 | + selected = $bindable(uninitializedValue as unknown as boolean), |
| 104 | + children, |
| 105 | + ...restProps |
| 106 | + }: OwnProps & SmuiAttrs<'button', keyof OwnProps> = $props(); |
70 | 107 |
|
71 |
| - // Remember to update $$Props if you add/remove/rename props. |
72 |
| - export let use: ActionArray = []; |
73 |
| - let className = ''; |
74 |
| - export { className as class }; |
75 |
| - export let style = ''; |
76 |
| - let segmentId: any; |
77 |
| - export { segmentId as segment }; |
78 |
| - export let ripple = true; |
79 |
| - export let touch = false; |
80 | 108 | const initialSelectedStore = getContext<SvelteStore<boolean>>(
|
81 | 109 | 'SMUI:segmented-button:segment:initialSelected',
|
82 | 110 | );
|
83 |
| -
|
84 | 111 | // Some trickery to detect uninitialized values but also have the right types.
|
85 |
| - /** You don't need to set this unless you are manually handling selection. */ |
86 |
| - export let selected: boolean = uninitializedValue as unknown as boolean; |
87 | 112 | let manualSelection: boolean = !isUninitializedValue(selected);
|
88 | 113 | if (isUninitializedValue(selected)) {
|
89 | 114 | selected = $initialSelectedStore;
|
90 | 115 | }
|
91 | 116 | // Done with the trickery.
|
92 | 117 |
|
93 | 118 | let element: HTMLButtonElement;
|
94 |
| - let instance: MDCSegmentedButtonSegmentFoundation; |
95 |
| - let internalClasses: { [k: string]: boolean } = {}; |
96 |
| - let internalStyles: { [k: string]: string } = {}; |
97 |
| - let internalAttrs: { [k: string]: string | undefined } = {}; |
| 119 | + let instance: MDCSegmentedButtonSegmentFoundation | undefined = $state(); |
| 120 | + let internalClasses: { [k: string]: boolean } = $state({}); |
| 121 | + let internalStyles: { [k: string]: string } = $state({}); |
| 122 | + let internalAttrs: { [k: string]: string | undefined } = $state({}); |
98 | 123 | const singleSelect = getContext<SvelteStore<boolean>>(
|
99 | 124 | 'SMUI:segmented-button:singleSelect',
|
100 | 125 | );
|
101 | 126 | const index = getContext<SvelteStore<number>>(
|
102 | 127 | 'SMUI:segmented-button:segment:index',
|
103 | 128 | );
|
104 | 129 |
|
105 |
| - if (!segmentId) { |
106 |
| - throw new Error( |
107 |
| - 'The segment property is required! It should be passed down from the SegmentedButton to the Segment.', |
108 |
| - ); |
109 |
| - } |
110 |
| -
|
111 |
| - $: if (instance && instance.isSelected() && !selected) { |
112 |
| - instance.setUnselected(); |
113 |
| - } |
| 130 | + $effect(() => { |
| 131 | + if (instance && instance.isSelected() && !selected) { |
| 132 | + instance.setUnselected(); |
| 133 | + } |
| 134 | + }); |
114 | 135 |
|
115 |
| - $: if (instance && !instance.isSelected() && selected) { |
116 |
| - instance.setSelected(); |
117 |
| - } |
| 136 | + $effect(() => { |
| 137 | + if (instance && !instance.isSelected() && selected) { |
| 138 | + instance.setSelected(); |
| 139 | + } |
| 140 | + }); |
118 | 141 |
|
119 | 142 | const SMUISegmentedButtonSegmentMount = getContext<
|
120 | 143 | ((accessor: SMUISegmentedButtonSegmentAccessor) => void) | undefined
|
|
168 | 191 | SMUISegmentedButtonSegmentUnmount &&
|
169 | 192 | SMUISegmentedButtonSegmentUnmount(accessor);
|
170 | 193 |
|
171 |
| - instance.destroy(); |
| 194 | + instance?.destroy(); |
172 | 195 | };
|
173 | 196 | });
|
174 | 197 |
|
|
0 commit comments