@elysn/astro 0.0.2 → 0.0.4

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.
Files changed (54) hide show
  1. package/LICENSE +201 -0
  2. package/index.ts +46 -0
  3. package/package.json +36 -16
  4. package/src/AccessibleIcon.astro +14 -0
  5. package/src/AspectRatio.astro +14 -0
  6. package/src/Avatar.astro +54 -0
  7. package/src/Badge.astro +34 -0
  8. package/src/Blockquote.astro +21 -0
  9. package/src/Box.astro +13 -0
  10. package/src/Button.astro +27 -8
  11. package/src/Callout.astro +34 -0
  12. package/src/CalloutIcon.astro +12 -0
  13. package/src/CalloutText.astro +12 -0
  14. package/src/Card.astro +30 -0
  15. package/src/Checkbox.astro +212 -0
  16. package/src/Code.astro +21 -0
  17. package/src/Container.astro +26 -0
  18. package/src/DecoratedBox.astro +22 -0
  19. package/src/Em.astro +10 -0
  20. package/src/Flex.astro +25 -0
  21. package/src/Grid.astro +21 -0
  22. package/src/Heading.astro +43 -0
  23. package/src/InputControl.astro +40 -0
  24. package/src/InputField.astro +10 -0
  25. package/src/InputSlot.astro +41 -0
  26. package/src/Kbd.astro +11 -0
  27. package/src/Link.astro +33 -0
  28. package/src/Panel.astro +12 -0
  29. package/src/Progress.astro +63 -0
  30. package/src/Quote.astro +10 -0
  31. package/src/RadioCards.astro +71 -0
  32. package/src/RadioCardsItem.astro +41 -0
  33. package/src/RadioGroup.astro +70 -0
  34. package/src/RadioGroupItem.astro +53 -0
  35. package/src/Section.astro +23 -0
  36. package/src/SegmentedControl.astro +189 -0
  37. package/src/Separator.astro +25 -0
  38. package/src/Skeleton.astro +30 -0
  39. package/src/Spinner.astro +31 -0
  40. package/src/Strong.astro +10 -0
  41. package/src/Switch.astro +164 -0
  42. package/src/Tabs.astro +179 -0
  43. package/src/TabsContent.astro +20 -0
  44. package/src/TabsIndicator.astro +17 -0
  45. package/src/TabsList.astro +12 -0
  46. package/src/TabsTrigger.astro +23 -0
  47. package/src/Text.astro +43 -0
  48. package/src/TextArea.astro +30 -0
  49. package/src/TextField.astro +70 -0
  50. package/src/VisuallyHidden.astro +10 -0
  51. package/src/internal/radio-group.ts +82 -0
  52. package/src/internal/ssr.ts +18 -0
  53. package/src/internal/zag.ts +24 -0
  54. package/style.css +5 -0
@@ -0,0 +1,41 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ interface Props extends Omit<HTMLAttributes<"label">, "value" | "color"> {
5
+ className?: string;
6
+ color?: string;
7
+ disabled?: boolean;
8
+ value: string;
9
+ }
10
+ const { className, color, disabled, value, ...rest } = Astro.props as Props;
11
+ ---
12
+
13
+ <label
14
+ {...rest}
15
+ data-scope="radio-group"
16
+ data-part="item"
17
+ data-state="unchecked"
18
+ data-accent-color={color}
19
+ data-item-value={value}
20
+ data-item-disabled={disabled ? "" : undefined}
21
+ data-disabled={disabled ? "" : undefined}
22
+ class:list={["el-BaseCard el-RadioCardsItem", className]}
23
+ >
24
+ <span
25
+ data-scope="radio-group"
26
+ data-part="item-text"
27
+ data-state="unchecked"
28
+ data-item-value={value}
29
+ >
30
+ <slot />
31
+ </span>
32
+ <input
33
+ type="radio"
34
+ data-part="hidden-input"
35
+ data-state="unchecked"
36
+ data-item-value={value}
37
+ value={value}
38
+ disabled={disabled}
39
+ style="border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap;word-wrap:normal"
40
+ />
41
+ </label>
@@ -0,0 +1,70 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { markChecked } from "./internal/ssr";
4
+
5
+ type Size = "xs" | "sm" | "md" | "lg";
6
+
7
+ interface Props extends Omit<HTMLAttributes<"div">, "color" | "dir" | "name"> {
8
+ className?: string;
9
+ color?: string;
10
+ defaultValue?: string;
11
+ dir?: "ltr" | "rtl";
12
+ disabled?: boolean;
13
+ highContrast?: boolean;
14
+ name?: string;
15
+ orientation?: "horizontal" | "vertical";
16
+ radius?: "none" | "small" | "medium" | "large" | "full";
17
+ required?: boolean;
18
+ size?: Size;
19
+ variant?: "surface" | "soft";
20
+ }
21
+ const {
22
+ className,
23
+ color,
24
+ defaultValue,
25
+ dir,
26
+ disabled,
27
+ highContrast,
28
+ name,
29
+ orientation = "vertical",
30
+ radius,
31
+ required,
32
+ size = "md",
33
+ variant = "surface",
34
+ ...rest
35
+ } = Astro.props as Props;
36
+
37
+ const sizes: Record<Size, string> = {
38
+ xs: "el-RadioGroup-size-xs",
39
+ sm: "el-RadioGroup-size-sm",
40
+ md: "el-RadioGroup-size-md",
41
+ lg: "el-RadioGroup-size-lg",
42
+ };
43
+ const items = markChecked(await Astro.slots.render("default"), defaultValue);
44
+ ---
45
+
46
+ <el-radio-group
47
+ {...rest}
48
+ role="radiogroup"
49
+ data-scope="radio-group"
50
+ data-part="root"
51
+ data-accent-color={color}
52
+ data-default-value={defaultValue}
53
+ data-dir={dir}
54
+ data-disabled={disabled ? "" : undefined}
55
+ data-high-contrast={highContrast ? "true" : undefined}
56
+ data-name={name}
57
+ data-orientation={orientation}
58
+ data-radius={radius}
59
+ data-required={required ? "true" : undefined}
60
+ data-variant={variant}
61
+ class:list={["el-RadioGroup", sizes[size], className]}
62
+ >
63
+ <Fragment set:html={items} />
64
+ </el-radio-group>
65
+
66
+ <script>
67
+ import { defineRadioGroup } from "./internal/radio-group";
68
+
69
+ defineRadioGroup();
70
+ </script>
@@ -0,0 +1,53 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ interface Props extends Omit<HTMLAttributes<"label">, "value"> {
5
+ className?: string;
6
+ disabled?: boolean;
7
+ value: string;
8
+ }
9
+ const { className, disabled, value, ...rest } = Astro.props as Props;
10
+ const hasText = Astro.slots.has("default");
11
+ ---
12
+
13
+ <label
14
+ {...rest}
15
+ data-scope="radio-group"
16
+ data-part="item"
17
+ data-state="unchecked"
18
+ data-item-value={value}
19
+ data-item-disabled={disabled ? "" : undefined}
20
+ data-disabled={disabled ? "" : undefined}
21
+ class:list={["el-RadioGroup-item", className]}
22
+ >
23
+ <div
24
+ data-scope="radio-group"
25
+ data-part="item-control"
26
+ data-state="unchecked"
27
+ data-item-value={value}
28
+ class="el-RadioGroup-itemControl"
29
+ >
30
+ </div>
31
+ {
32
+ hasText && (
33
+ <span
34
+ data-scope="radio-group"
35
+ data-part="item-text"
36
+ data-state="unchecked"
37
+ data-item-value={value}
38
+ class="el-RadioGroup-itemText"
39
+ >
40
+ <slot />
41
+ </span>
42
+ )
43
+ }
44
+ <input
45
+ type="radio"
46
+ data-part="hidden-input"
47
+ data-state="unchecked"
48
+ data-item-value={value}
49
+ value={value}
50
+ disabled={disabled}
51
+ style="border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap;word-wrap:normal"
52
+ />
53
+ </label>
@@ -0,0 +1,23 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ type Size = "xs" | "sm" | "md" | "lg";
5
+
6
+ interface Props extends Omit<HTMLAttributes<"div">, "color"> {
7
+ className?: string;
8
+ color?: string;
9
+ size?: Size;
10
+ }
11
+ const { className, color, size = "md", ...rest } = Astro.props as Props;
12
+
13
+ const sizes: Record<Size, string> = {
14
+ xs: "el-Section-size-xs",
15
+ sm: "el-Section-size-sm",
16
+ md: "el-Section-size-md",
17
+ lg: "el-Section-size-lg",
18
+ };
19
+ ---
20
+
21
+ <div {...rest} data-accent-color={color} class:list={["el-Section", sizes[size], className]}>
22
+ <slot />
23
+ </div>
@@ -0,0 +1,189 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ type Size = "xs" | "sm" | "md" | "lg";
5
+
6
+ interface Item {
7
+ disabled?: boolean;
8
+ label: string;
9
+ value: string;
10
+ }
11
+
12
+ interface Props extends Omit<HTMLAttributes<"div">, "color" | "dir" | "name"> {
13
+ className?: string;
14
+ color?: string;
15
+ defaultValue?: string;
16
+ dir?: "ltr" | "rtl";
17
+ disabled?: boolean;
18
+ items: Item[];
19
+ name?: string;
20
+ radius?: "none" | "small" | "medium" | "large" | "full";
21
+ size?: Size;
22
+ }
23
+ const {
24
+ className,
25
+ color,
26
+ defaultValue,
27
+ dir,
28
+ disabled,
29
+ items,
30
+ name,
31
+ radius,
32
+ size = "md",
33
+ ...rest
34
+ } = Astro.props as Props;
35
+
36
+ const sizes: Record<Size, string> = {
37
+ xs: "el-SegmentedControl-size-xs",
38
+ sm: "el-SegmentedControl-size-sm",
39
+ md: "el-SegmentedControl-size-md",
40
+ lg: "el-SegmentedControl-size-lg",
41
+ };
42
+ ---
43
+
44
+ <el-segmented-control
45
+ {...rest}
46
+ role="radiogroup"
47
+ data-scope="segment-group"
48
+ data-part="root"
49
+ data-accent-color={color}
50
+ data-default-value={defaultValue}
51
+ data-dir={dir}
52
+ data-disabled={disabled ? "" : undefined}
53
+ data-name={name}
54
+ data-orientation="horizontal"
55
+ data-radius={radius}
56
+ class:list={["el-SegmentedControl", sizes[size], className]}
57
+ >
58
+ {
59
+ items.map((item) => {
60
+ const state = item.value === defaultValue ? "checked" : "unchecked";
61
+ return (
62
+ <label
63
+ data-scope="segment-group"
64
+ data-part="item"
65
+ data-state={state}
66
+ data-item-value={item.value}
67
+ data-item-disabled={item.disabled ? "" : undefined}
68
+ data-disabled={item.disabled || disabled ? "" : undefined}
69
+ class="el-SegmentedControl-item"
70
+ >
71
+ <span
72
+ data-scope="segment-group"
73
+ data-part="item-text"
74
+ data-state={state}
75
+ data-text={item.label}
76
+ class="el-SegmentedControl-itemText"
77
+ >
78
+ {item.label}
79
+ </span>
80
+ <input
81
+ type="radio"
82
+ data-part="hidden-input"
83
+ data-item-value={item.value}
84
+ value={item.value}
85
+ checked={state === "checked"}
86
+ disabled={item.disabled || disabled}
87
+ style="border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap;word-wrap:normal"
88
+ />
89
+ </label>
90
+ );
91
+ })
92
+ }
93
+ <div
94
+ data-scope="segment-group"
95
+ data-part="indicator"
96
+ data-orientation="horizontal"
97
+ class="el-SegmentedControl-indicator"
98
+ >
99
+ </div>
100
+ </el-segmented-control>
101
+
102
+ <script>
103
+ import * as zradio from "@zag-js/radio-group";
104
+ import { VanillaMachine, normalizeProps } from "@zag-js/vanilla";
105
+ import { createSpreader, nextId, textDirection } from "./internal/zag";
106
+
107
+ type Machine = ReturnType<typeof createMachine>;
108
+ const createMachine = (props: zradio.Props) => new VanillaMachine(zradio.machine, props);
109
+
110
+ class ElSegmentedControl extends HTMLElement {
111
+ #machine?: Machine;
112
+ #unsubscribe?: () => void;
113
+ #spread = createSpreader("");
114
+
115
+ connectedCallback() {
116
+ if (this.#machine) return;
117
+ const id = nextId("el-segmented-control");
118
+ this.#spread = createSpreader(id);
119
+ const machine = createMachine({
120
+ id,
121
+ defaultValue: this.dataset["defaultValue"] ?? null,
122
+ name: this.dataset["name"],
123
+ disabled: this.hasAttribute("data-disabled"),
124
+ orientation: "horizontal",
125
+ dir: textDirection(this),
126
+ getRootNode: () => this.getRootNode(),
127
+ onValueChange: ({ value }: { value: string | null }) =>
128
+ this.dispatchEvent(
129
+ new CustomEvent("el-segmented-control:value-change", {
130
+ detail: { value },
131
+ bubbles: true,
132
+ }),
133
+ ),
134
+ });
135
+ this.#machine = machine;
136
+ // The indicator is positioned from the item rects, which need the ids on the DOM first
137
+ this.#render();
138
+ machine.start();
139
+ this.#render();
140
+ this.#unsubscribe = machine.subscribe(() => this.#render());
141
+ this.dataset["ready"] = "";
142
+ }
143
+
144
+ disconnectedCallback() {
145
+ this.#unsubscribe?.();
146
+ this.#spread.clear();
147
+ this.#machine?.stop();
148
+ this.#machine = undefined;
149
+ delete this.dataset["ready"];
150
+ }
151
+
152
+ /** Programmatic API: `el.value` / `el.value = "b"`. */
153
+ get value() {
154
+ return this.#api()?.value ?? null;
155
+ }
156
+ set value(value: string | null) {
157
+ this.#api()?.setValue(value as string);
158
+ }
159
+
160
+ #api() {
161
+ return this.#machine && zradio.connect(this.#machine.service, normalizeProps);
162
+ }
163
+
164
+ #render() {
165
+ const api = this.#api();
166
+ if (!api) return;
167
+ const { id: _id, ...rootProps } = api.getRootProps();
168
+ this.#spread.apply(this, rootProps);
169
+ for (const item of this.querySelectorAll<HTMLElement>("[data-part='item']")) {
170
+ const props = {
171
+ value: item.dataset["itemValue"] ?? "",
172
+ disabled: item.hasAttribute("data-item-disabled"),
173
+ };
174
+ const part = (name: string) => item.querySelector<HTMLElement>(`[data-part='${name}']`);
175
+ this.#spread.apply(item, api.getItemProps(props));
176
+ this.#spread.apply(part("item-text"), api.getItemTextProps(props));
177
+ this.#spread.apply(part("hidden-input"), api.getItemHiddenInputProps(props));
178
+ }
179
+ this.#spread.apply(
180
+ this.querySelector("[data-part='indicator']"),
181
+ api.getIndicatorProps(),
182
+ );
183
+ }
184
+ }
185
+
186
+ if (!customElements.get("el-segmented-control")) {
187
+ customElements.define("el-segmented-control", ElSegmentedControl);
188
+ }
189
+ </script>
@@ -0,0 +1,25 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ interface Props extends Omit<HTMLAttributes<"div">, "color"> {
5
+ className?: string;
6
+ color?: string;
7
+ decorative?: boolean;
8
+ orientation?: "horizontal" | "vertical";
9
+ size?: "1" | "2" | "3" | "4";
10
+ }
11
+ const { className, color, decorative, orientation = "horizontal", size = "1", ...rest } =
12
+ Astro.props as Props;
13
+ ---
14
+
15
+ <div
16
+ {...rest}
17
+ role={decorative ? undefined : "separator"}
18
+ aria-hidden={decorative ? "true" : undefined}
19
+ aria-orientation={decorative ? undefined : orientation}
20
+ data-accent-color={color}
21
+ data-orientation={orientation}
22
+ data-size={size}
23
+ class:list={["el-Separator", className]}
24
+ >
25
+ </div>
@@ -0,0 +1,30 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ interface Props extends Omit<HTMLAttributes<"span">, "style"> {
5
+ className?: string;
6
+ height?: string;
7
+ loading?: boolean;
8
+ style?: Record<string, string | number>;
9
+ width?: string;
10
+ }
11
+ const { className, height, loading = true, style, width, ...rest } = Astro.props as Props;
12
+ // Like Radix: when not loading, render the bare slot (no wrapper element).
13
+ // Whitespace-only slots are emptied so the `:empty` block placeholder rule still applies.
14
+ const html = loading && Astro.slots.has("default") ? await Astro.slots.render("default") : "";
15
+ const content = html.trim() === "" ? "" : html;
16
+ ---
17
+
18
+ {
19
+ loading ? (
20
+ <span
21
+ {...rest}
22
+ data-loading
23
+ class:list={["el-Skeleton", className]}
24
+ style={{ width, height, ...style }}
25
+ set:html={content}
26
+ />
27
+ ) : (
28
+ <slot />
29
+ )
30
+ }
@@ -0,0 +1,31 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ type Size = "xs" | "sm" | "md" | "lg" | "xl";
5
+
6
+ interface Props extends HTMLAttributes<"span"> {
7
+ className?: string;
8
+ loading?: boolean;
9
+ size?: Size;
10
+ }
11
+ const { className, loading = true, size = "md", ...rest } = Astro.props as Props;
12
+
13
+ const sizes: Record<Size, string> = {
14
+ xs: "el-Spinner-size-xs",
15
+ sm: "el-Spinner-size-sm",
16
+ md: "el-Spinner-size-md",
17
+ lg: "el-Spinner-size-lg",
18
+ xl: "el-Spinner-size-xl",
19
+ };
20
+ ---
21
+
22
+ {
23
+ loading && (
24
+ <span
25
+ {...rest}
26
+ role="status"
27
+ aria-label="Loading"
28
+ class:list={["el-Spinner", sizes[size], className]}
29
+ />
30
+ )
31
+ }
@@ -0,0 +1,10 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ interface Props extends HTMLAttributes<"strong"> {
5
+ className?: string;
6
+ }
7
+ const { className, ...rest } = Astro.props as Props;
8
+ ---
9
+
10
+ <strong {...rest} class:list={["el-Strong", className]}><slot /></strong>
@@ -0,0 +1,164 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+
4
+ type Size = "xs" | "sm" | "md" | "lg";
5
+
6
+ interface Props extends Omit<HTMLAttributes<"label">, "color" | "dir" | "name"> {
7
+ className?: string;
8
+ color?: string;
9
+ defaultChecked?: boolean;
10
+ dir?: "ltr" | "rtl";
11
+ disabled?: boolean;
12
+ highContrast?: boolean;
13
+ name?: string;
14
+ radius?: "none" | "small" | "medium" | "large" | "full";
15
+ required?: boolean;
16
+ size?: Size;
17
+ value?: string;
18
+ variant?: "surface" | "soft";
19
+ }
20
+ const {
21
+ className,
22
+ color,
23
+ defaultChecked,
24
+ dir,
25
+ disabled,
26
+ highContrast,
27
+ name,
28
+ radius,
29
+ required,
30
+ size = "md",
31
+ value = "on",
32
+ variant = "surface",
33
+ ...rest
34
+ } = Astro.props as Props;
35
+
36
+ const sizes: Record<Size, string> = {
37
+ xs: "el-Switch-size-xs",
38
+ sm: "el-Switch-size-sm",
39
+ md: "el-Switch-size-md",
40
+ lg: "el-Switch-size-lg",
41
+ };
42
+ const state = defaultChecked ? "checked" : "unchecked";
43
+ const hasLabel = Astro.slots.has("default");
44
+ ---
45
+
46
+ <!-- display: contents keeps the Zag root (a <label>) as the visual box -->
47
+ <el-switch
48
+ style="display: contents"
49
+ data-default-checked={defaultChecked ? "true" : undefined}
50
+ data-dir={dir}
51
+ >
52
+ <label
53
+ {...rest}
54
+ data-scope="switch"
55
+ data-part="root"
56
+ data-state={state}
57
+ data-disabled={disabled ? "" : undefined}
58
+ data-accent-color={color}
59
+ data-high-contrast={highContrast ? "true" : undefined}
60
+ data-radius={radius}
61
+ data-variant={variant}
62
+ class:list={["el-Switch", sizes[size], className]}
63
+ >
64
+ <span data-scope="switch" data-part="control" data-state={state} class="el-Switch-control">
65
+ <span data-scope="switch" data-part="thumb" data-state={state} class="el-Switch-thumb"></span>
66
+ </span>
67
+ {
68
+ hasLabel && (
69
+ <span data-scope="switch" data-part="label" data-state={state} class="el-Switch-label">
70
+ <slot />
71
+ </span>
72
+ )
73
+ }
74
+ <input
75
+ type="checkbox"
76
+ data-part="hidden-input"
77
+ name={name}
78
+ value={value}
79
+ checked={defaultChecked}
80
+ disabled={disabled}
81
+ required={required}
82
+ style="border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap;word-wrap:normal"
83
+ />
84
+ </label>
85
+ </el-switch>
86
+
87
+ <script>
88
+ import * as zswitch from "@zag-js/switch";
89
+ import { VanillaMachine, normalizeProps } from "@zag-js/vanilla";
90
+ import { createSpreader, nextId, textDirection } from "./internal/zag";
91
+
92
+ type Machine = ReturnType<typeof createMachine>;
93
+ const createMachine = (props: zswitch.Props) => new VanillaMachine(zswitch.machine, props);
94
+
95
+ class ElSwitch extends HTMLElement {
96
+ #machine?: Machine;
97
+ #unsubscribe?: () => void;
98
+ #spread = createSpreader("");
99
+
100
+ connectedCallback() {
101
+ if (this.#machine) return;
102
+ const id = nextId("el-switch");
103
+ this.#spread = createSpreader(id);
104
+ const input = this.#part("hidden-input") as HTMLInputElement | undefined;
105
+ const machine = createMachine({
106
+ id,
107
+ defaultChecked: this.dataset["defaultChecked"] === "true",
108
+ disabled: input?.disabled,
109
+ required: input?.required,
110
+ name: input?.name || undefined,
111
+ value: input?.value,
112
+ dir: textDirection(this),
113
+ getRootNode: () => this.getRootNode(),
114
+ onCheckedChange: ({ checked }: { checked: boolean }) =>
115
+ this.dispatchEvent(
116
+ new CustomEvent("el-switch:checked-change", { detail: { checked }, bubbles: true }),
117
+ ),
118
+ });
119
+ this.#machine = machine;
120
+ machine.start();
121
+ this.#render();
122
+ this.#unsubscribe = machine.subscribe(() => this.#render());
123
+ this.dataset["ready"] = "";
124
+ }
125
+
126
+ disconnectedCallback() {
127
+ this.#unsubscribe?.();
128
+ this.#spread.clear();
129
+ this.#machine?.stop();
130
+ this.#machine = undefined;
131
+ delete this.dataset["ready"];
132
+ }
133
+
134
+ /** Programmatic API: `el.checked` / `el.checked = true`. */
135
+ get checked() {
136
+ return this.#api()?.checked ?? false;
137
+ }
138
+ set checked(checked: boolean) {
139
+ this.#api()?.setChecked(checked);
140
+ }
141
+
142
+ #api() {
143
+ return this.#machine && zswitch.connect(this.#machine.service, normalizeProps);
144
+ }
145
+
146
+ #part(name: string) {
147
+ return this.querySelector<HTMLElement>(`[data-part='${name}']`) ?? undefined;
148
+ }
149
+
150
+ #render() {
151
+ const api = this.#api();
152
+ if (!api) return;
153
+ // Zag never looks the root up by id, so keep the author's `id` instead of its generated one
154
+ const { id: _id, ...rootProps } = api.getRootProps();
155
+ this.#spread.apply(this.#part("root"), rootProps);
156
+ this.#spread.apply(this.#part("control"), api.getControlProps());
157
+ this.#spread.apply(this.#part("thumb"), api.getThumbProps());
158
+ this.#spread.apply(this.#part("label"), api.getLabelProps());
159
+ this.#spread.apply(this.#part("hidden-input"), api.getHiddenInputProps());
160
+ }
161
+ }
162
+
163
+ if (!customElements.get("el-switch")) customElements.define("el-switch", ElSwitch);
164
+ </script>