@svelte-thing/primitives 0.0.0

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 (137) hide show
  1. package/README.md +1 -0
  2. package/dist/button/index.d.mts +9 -0
  3. package/dist/button/index.mjs +6 -0
  4. package/dist/chunk-D7D4PA-g.mjs +13 -0
  5. package/dist/context-BJAwVB1S.mjs +5 -0
  6. package/dist/context-D77KIx26.mjs +5 -0
  7. package/dist/context-DwEoOJU2.mjs +5 -0
  8. package/dist/createInput.svelte-DTz79zNF.d.mts +9 -0
  9. package/dist/createInput.svelte-DzcT9u1t.mjs +92 -0
  10. package/dist/field/date/index.d.mts +2 -0
  11. package/dist/field/date/index.mjs +27 -0
  12. package/dist/field/error/index.d.mts +2 -0
  13. package/dist/field/error/index.mjs +10 -0
  14. package/dist/field/index.d.mts +13 -0
  15. package/dist/field/index.mjs +25 -0
  16. package/dist/field/input/index.d.mts +2 -0
  17. package/dist/field/input/index.mjs +2 -0
  18. package/dist/field/label/index.d.mts +2 -0
  19. package/dist/field/label/index.mjs +15 -0
  20. package/dist/field/password/index.d.mts +2 -0
  21. package/dist/field/password/index.mjs +61 -0
  22. package/dist/field/root/index.d.mts +2 -0
  23. package/dist/field/root/index.mjs +79 -0
  24. package/dist/index-07sbgO0w.d.mts +9 -0
  25. package/dist/index-B-PBb_8h.d.mts +14 -0
  26. package/dist/index-BLb5EVhG.d.mts +35 -0
  27. package/dist/index-BVVgDSdq.d.mts +1 -0
  28. package/dist/index-Boej-mdy.d.mts +25 -0
  29. package/dist/index-C-ME1Tk9.d.mts +9 -0
  30. package/dist/index-CA_POIj_.d.mts +9 -0
  31. package/dist/index-CbchmhrC.d.mts +9 -0
  32. package/dist/index-D2vzMU8o.d.mts +13 -0
  33. package/dist/index-DAHEDQQS.d.mts +9 -0
  34. package/dist/index-OI9KlY5x.d.mts +9 -0
  35. package/dist/index-j-8eH9nJ.d.mts +29 -0
  36. package/dist/index.d.mts +3 -0
  37. package/dist/index.mjs +3 -0
  38. package/dist/menu/index.d.mts +5 -0
  39. package/dist/menu/index.mjs +6 -0
  40. package/dist/menu/item/index.d.mts +14 -0
  41. package/dist/menu/item/index.mjs +86 -0
  42. package/dist/menu/popup/index.d.mts +19 -0
  43. package/dist/menu/popup/index.mjs +121 -0
  44. package/dist/menu/root/index.d.mts +28 -0
  45. package/dist/menu/root/index.mjs +69 -0
  46. package/dist/menu/trigger/index.d.mts +13 -0
  47. package/dist/menu/trigger/index.mjs +27 -0
  48. package/dist/pagination/content/index.d.mts +9 -0
  49. package/dist/pagination/content/index.mjs +6 -0
  50. package/dist/pagination/ellipsis/index.d.mts +9 -0
  51. package/dist/pagination/ellipsis/index.mjs +6 -0
  52. package/dist/pagination/index.d.mts +6 -0
  53. package/dist/pagination/index.mjs +6 -0
  54. package/dist/pagination/item/index.d.mts +9 -0
  55. package/dist/pagination/item/index.mjs +6 -0
  56. package/dist/pagination/link/index.d.mts +13 -0
  57. package/dist/pagination/link/index.mjs +13 -0
  58. package/dist/pagination/root/index.d.mts +9 -0
  59. package/dist/pagination/root/index.mjs +9 -0
  60. package/dist/tab/index.d.mts +13 -0
  61. package/dist/tab/index.mjs +21 -0
  62. package/dist/tab/indicator/index.d.mts +2 -0
  63. package/dist/tab/indicator/index.mjs +42 -0
  64. package/dist/tab/list/index.d.mts +2 -0
  65. package/dist/tab/list/index.mjs +20 -0
  66. package/dist/tab/panel/index.d.mts +2 -0
  67. package/dist/tab/panel/index.mjs +28 -0
  68. package/dist/tab/root/index.d.mts +2 -0
  69. package/dist/tab/root/index.mjs +57 -0
  70. package/dist/tab/title/index.d.mts +2 -0
  71. package/dist/tab/title/index.mjs +18 -0
  72. package/dist/tab/trigger/index.d.mts +2 -0
  73. package/dist/tab/trigger/index.mjs +94 -0
  74. package/dist/table/index.d.mts +2 -0
  75. package/dist/table/index.mjs +2 -0
  76. package/dist/table/row/index.d.mts +17 -0
  77. package/dist/table/row/index.mjs +17 -0
  78. package/package.json +64 -0
  79. package/src/button/createButton.svelte.ts +11 -0
  80. package/src/button/index.ts +1 -0
  81. package/src/field/date/createPicker.svelte.ts +41 -0
  82. package/src/field/date/index.ts +1 -0
  83. package/src/field/error/createError.svelte.ts +21 -0
  84. package/src/field/error/index.ts +1 -0
  85. package/src/field/index.ts +6 -0
  86. package/src/field/input/createInput.svelte.ts +136 -0
  87. package/src/field/input/index.ts +1 -0
  88. package/src/field/label/createLabel.svelte.ts +24 -0
  89. package/src/field/label/index.ts +1 -0
  90. package/src/field/password/context.ts +5 -0
  91. package/src/field/password/createPassword.svelte.ts +43 -0
  92. package/src/field/password/createShow.svelte.ts +47 -0
  93. package/src/field/password/index.ts +3 -0
  94. package/src/field/root/context.ts +5 -0
  95. package/src/field/root/createRoot.svelte.ts +113 -0
  96. package/src/field/root/index.ts +2 -0
  97. package/src/index.ts +2 -0
  98. package/src/menu/index.ts +4 -0
  99. package/src/menu/item/createItem.svelte.ts +123 -0
  100. package/src/menu/item/index.ts +1 -0
  101. package/src/menu/popup/createPopup.svelte.ts +186 -0
  102. package/src/menu/popup/index.ts +1 -0
  103. package/src/menu/root/context.ts +5 -0
  104. package/src/menu/root/createRoot.svelte.ts +96 -0
  105. package/src/menu/root/index.ts +2 -0
  106. package/src/menu/trigger/createTrigger.svelte.ts +44 -0
  107. package/src/menu/trigger/index.ts +1 -0
  108. package/src/pagination/content/createContent.svelte.ts +11 -0
  109. package/src/pagination/content/index.ts +1 -0
  110. package/src/pagination/ellipsis/createEllipsis.svelte.ts +13 -0
  111. package/src/pagination/ellipsis/index.ts +1 -0
  112. package/src/pagination/index.ts +5 -0
  113. package/src/pagination/item/createItem.svelte.ts +11 -0
  114. package/src/pagination/item/index.ts +1 -0
  115. package/src/pagination/link/createLink.svelte.ts +23 -0
  116. package/src/pagination/link/index.ts +1 -0
  117. package/src/pagination/root/createRoot.svelte.ts +14 -0
  118. package/src/pagination/root/index.ts +1 -0
  119. package/src/style.css +10 -0
  120. package/src/tab/index.ts +6 -0
  121. package/src/tab/indicator/createIndicator.svelte.ts +79 -0
  122. package/src/tab/indicator/index.ts +1 -0
  123. package/src/tab/list/createList.svelte.ts +27 -0
  124. package/src/tab/list/index.ts +1 -0
  125. package/src/tab/panel/createPanel.svelte.ts +42 -0
  126. package/src/tab/panel/index.ts +1 -0
  127. package/src/tab/root/context.ts +5 -0
  128. package/src/tab/root/createRoot.svelte.ts +85 -0
  129. package/src/tab/root/index.ts +2 -0
  130. package/src/tab/title/createTitle.svelte.ts +27 -0
  131. package/src/tab/title/index.ts +1 -0
  132. package/src/tab/trigger/createTrigger.svelte.ts +129 -0
  133. package/src/tab/trigger/index.ts +1 -0
  134. package/src/table/index.ts +1 -0
  135. package/src/table/row/context.ts +5 -0
  136. package/src/table/row/createRow.svelte.ts +26 -0
  137. package/src/table/row/index.ts +2 -0
@@ -0,0 +1,57 @@
1
+ import { n as setRoot, t as getRoot } from "../../context-DwEoOJU2.mjs";
2
+ import { uid } from "uid";
3
+ //#region src/tab/root/createRoot.svelte.ts
4
+ function createRoot(props) {
5
+ const activateOnFocus = $derived(props.activateOnFocus ?? true);
6
+ const direction = $derived(props.direction ?? "ltr");
7
+ const id = $derived(uid());
8
+ const orientation = $derived(props.orientation ?? "horizontal");
9
+ let hasTitle = $state(false);
10
+ let value = $derived(props.value ?? null);
11
+ let panel = $derived(props.value ?? null);
12
+ const root = {
13
+ get activateOnFocus() {
14
+ return activateOnFocus;
15
+ },
16
+ get direction() {
17
+ return direction;
18
+ },
19
+ get hasTitle() {
20
+ return hasTitle;
21
+ },
22
+ set hasTitle(h) {
23
+ hasTitle = h;
24
+ },
25
+ get id() {
26
+ return id;
27
+ },
28
+ get orientation() {
29
+ return orientation;
30
+ },
31
+ get panel() {
32
+ return panel;
33
+ },
34
+ set panel(p) {
35
+ panel = p;
36
+ },
37
+ get value() {
38
+ return value;
39
+ },
40
+ set value(v) {
41
+ value = v;
42
+ },
43
+ props: {
44
+ get "data-orientation"() {
45
+ return orientation;
46
+ },
47
+ get id() {
48
+ return id;
49
+ },
50
+ "data-tab-root": ""
51
+ }
52
+ };
53
+ setRoot(root);
54
+ return root;
55
+ }
56
+ //#endregion
57
+ export { createRoot, getRoot, setRoot };
@@ -0,0 +1,2 @@
1
+ import { n as createTitle, t as TitleState } from "../../index-DAHEDQQS.mjs";
2
+ export { TitleState, createTitle };
@@ -0,0 +1,18 @@
1
+ import { t as getRoot } from "../../context-DwEoOJU2.mjs";
2
+ import { onDestroy } from "svelte";
3
+ //#region src/tab/title/createTitle.svelte.ts
4
+ function createTitle() {
5
+ const root = getRoot();
6
+ root.hasTitle = true;
7
+ onDestroy(() => {
8
+ root.hasTitle = false;
9
+ });
10
+ return { props: {
11
+ get id() {
12
+ return `${root.id}-title`;
13
+ },
14
+ "data-tab-title": ""
15
+ } };
16
+ }
17
+ //#endregion
18
+ export { createTitle };
@@ -0,0 +1,2 @@
1
+ import { n as TriggerState, r as createTrigger, t as CreateTriggerProps } from "../../index-B-PBb_8h.mjs";
2
+ export { CreateTriggerProps, TriggerState, createTrigger };
@@ -0,0 +1,94 @@
1
+ import { t as getRoot } from "../../context-DwEoOJU2.mjs";
2
+ //#region src/tab/trigger/createTrigger.svelte.ts
3
+ function createTrigger(props) {
4
+ const root = getRoot();
5
+ const isSelected = $derived(root.value === props.value);
6
+ if (root.value === null) {
7
+ root.value = props.value;
8
+ root.panel = props.value;
9
+ }
10
+ return { props: {
11
+ get "aria-controls"() {
12
+ return `${root.id}-panel-${props.value}`;
13
+ },
14
+ get "aria-selected"() {
15
+ return isSelected;
16
+ },
17
+ get "data-disabled"() {
18
+ return props.disabled ? true : void 0;
19
+ },
20
+ get "data-orientation"() {
21
+ return root.orientation;
22
+ },
23
+ get "data-root-id"() {
24
+ return root.id;
25
+ },
26
+ get "data-selected"() {
27
+ return isSelected ? "" : void 0;
28
+ },
29
+ get "data-value"() {
30
+ return props.value;
31
+ },
32
+ get id() {
33
+ return `${root.id}-trigger-${props.value}`;
34
+ },
35
+ get tabindex() {
36
+ return isSelected ? void 0 : -1;
37
+ },
38
+ "data-tabs-trigger": "",
39
+ type: "button",
40
+ role: "tab",
41
+ onclick(event) {
42
+ root.value = props.value;
43
+ root.panel = props.value;
44
+ event.currentTarget.focus();
45
+ },
46
+ onkeydown(event) {
47
+ if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return;
48
+ let preventDefault = false;
49
+ let pendingValue = null;
50
+ const button = event.currentTarget;
51
+ const triggers = [...document.querySelectorAll(`[data-tabs-trigger][data-root-id="${root.id}"]:not([data-disabled])`)];
52
+ const currentIndex = triggers.indexOf(button);
53
+ const nextKeyName = root.orientation === "horizontal" ? "ArrowRight" : "ArrowDown";
54
+ const previousKeyName = root.orientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
55
+ switch (event.key) {
56
+ case previousKeyName: {
57
+ const nextIndex = currentIndex === 0 ? triggers.length - 1 : currentIndex - 1;
58
+ pendingValue = triggers[nextIndex]?.dataset.value ?? null;
59
+ triggers[nextIndex]?.focus();
60
+ preventDefault = true;
61
+ break;
62
+ }
63
+ case nextKeyName: {
64
+ const nextIndex = (currentIndex + 1) % triggers.length;
65
+ pendingValue = triggers[nextIndex]?.dataset.value ?? null;
66
+ triggers[nextIndex]?.focus();
67
+ preventDefault = true;
68
+ break;
69
+ }
70
+ case "Home":
71
+ pendingValue = triggers[0]?.dataset.value ?? null;
72
+ triggers[0]?.focus();
73
+ preventDefault = true;
74
+ break;
75
+ case "End":
76
+ pendingValue = triggers.at(-1)?.dataset.value ?? null;
77
+ triggers.at(-1)?.focus();
78
+ preventDefault = true;
79
+ break;
80
+ default: break;
81
+ }
82
+ if (pendingValue !== null) {
83
+ root.value = pendingValue;
84
+ if (root.activateOnFocus) root.panel = pendingValue;
85
+ }
86
+ if (preventDefault) {
87
+ event.stopPropagation();
88
+ event.preventDefault();
89
+ }
90
+ }
91
+ } };
92
+ }
93
+ //#endregion
94
+ export { createTrigger };
@@ -0,0 +1,2 @@
1
+ import { CreateRowProps, RowState, createRow, getRow, setRow } from "./row/index.mjs";
2
+ export { CreateRowProps, RowState, createRow, getRow, setRow };
@@ -0,0 +1,2 @@
1
+ import { createRow, getRow, setRow } from "./row/index.mjs";
2
+ export { createRow, getRow, setRow };
@@ -0,0 +1,17 @@
1
+ import { Exact } from "@svelte-thing/type-utils";
2
+ import { HTMLAttributes } from "svelte/elements";
3
+
4
+ //#region src/table/row/createRow.svelte.d.ts
5
+ interface CreateRowProps {
6
+ href: string | undefined;
7
+ }
8
+ interface RowState {
9
+ href: string | undefined;
10
+ props: HTMLAttributes<HTMLElement>;
11
+ }
12
+ declare function createRow<T extends CreateRowProps>(props: Exact<CreateRowProps, T>): RowState;
13
+ //#endregion
14
+ //#region src/table/row/context.d.ts
15
+ declare const getRow: () => RowState, setRow: (context: RowState) => RowState;
16
+ //#endregion
17
+ export { CreateRowProps, RowState, createRow, getRow, setRow };
@@ -0,0 +1,17 @@
1
+ import { createContext } from "svelte";
2
+ //#region src/table/row/context.ts
3
+ const [getRow, setRow] = createContext();
4
+ //#endregion
5
+ //#region src/table/row/createRow.svelte.ts
6
+ function createRow(props) {
7
+ const row = {
8
+ get href() {
9
+ return props.href;
10
+ },
11
+ props: {}
12
+ };
13
+ setRow(row);
14
+ return row;
15
+ }
16
+ //#endregion
17
+ export { createRow, getRow, setRow };
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@svelte-thing/primitives",
3
+ "version": "0.0.0",
4
+ "files": [
5
+ "src",
6
+ "dist",
7
+ "!**/*.test.js",
8
+ "!**/*.test.js.map",
9
+ "!**/*.test.d.ts"
10
+ ],
11
+ "type": "module",
12
+ "exports": {
13
+ ".": "./dist/index.mjs",
14
+ "./button": "./dist/button/index.mjs",
15
+ "./field": "./dist/field/index.mjs",
16
+ "./field/date": "./dist/field/date/index.mjs",
17
+ "./field/error": "./dist/field/error/index.mjs",
18
+ "./field/input": "./dist/field/input/index.mjs",
19
+ "./field/label": "./dist/field/label/index.mjs",
20
+ "./field/password": "./dist/field/password/index.mjs",
21
+ "./field/root": "./dist/field/root/index.mjs",
22
+ "./menu": "./dist/menu/index.mjs",
23
+ "./menu/item": "./dist/menu/item/index.mjs",
24
+ "./menu/popup": "./dist/menu/popup/index.mjs",
25
+ "./menu/root": "./dist/menu/root/index.mjs",
26
+ "./menu/trigger": "./dist/menu/trigger/index.mjs",
27
+ "./pagination": "./dist/pagination/index.mjs",
28
+ "./pagination/content": "./dist/pagination/content/index.mjs",
29
+ "./pagination/ellipsis": "./dist/pagination/ellipsis/index.mjs",
30
+ "./pagination/item": "./dist/pagination/item/index.mjs",
31
+ "./pagination/link": "./dist/pagination/link/index.mjs",
32
+ "./pagination/root": "./dist/pagination/root/index.mjs",
33
+ "./tab": "./dist/tab/index.mjs",
34
+ "./tab/indicator": "./dist/tab/indicator/index.mjs",
35
+ "./tab/list": "./dist/tab/list/index.mjs",
36
+ "./tab/panel": "./dist/tab/panel/index.mjs",
37
+ "./tab/root": "./dist/tab/root/index.mjs",
38
+ "./tab/title": "./dist/tab/title/index.mjs",
39
+ "./tab/trigger": "./dist/tab/trigger/index.mjs",
40
+ "./table": "./dist/table/index.mjs",
41
+ "./table/row": "./dist/table/row/index.mjs",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "dependencies": {
45
+ "@svelte-thing/component-utils": "^0.0.16",
46
+ "@svelte-thing/type-utils": "^0.0.1",
47
+ "esm-env": "^1.2.2",
48
+ "uid": "2.0.2"
49
+ },
50
+ "devDependencies": {
51
+ "@arethetypeswrong/core": "^0.18.3",
52
+ "@svelte-thing/tailwind-radix-colors": "^0.0.0",
53
+ "@sveltejs/package": "^2.5.8",
54
+ "publint": "0.3.21",
55
+ "svelte": "5.53.7",
56
+ "tailwindcss": "4.1.18",
57
+ "typescript": "6.0.3",
58
+ "vite-plus": "^0.1.24"
59
+ },
60
+ "peerDependencies": {
61
+ "svelte": "5.53.7",
62
+ "tailwindcss": "4.1.18"
63
+ }
64
+ }
@@ -0,0 +1,11 @@
1
+ import type { HTMLButtonAttributes } from 'svelte/elements';
2
+
3
+ export interface ButtonState {
4
+ props: HTMLButtonAttributes;
5
+ }
6
+
7
+ export function createButton(): ButtonState {
8
+ return {
9
+ props: {},
10
+ };
11
+ }
@@ -0,0 +1 @@
1
+ export * from './createButton.svelte.js';
@@ -0,0 +1,41 @@
1
+ import type { HTMLButtonAttributes } from 'svelte/elements';
2
+
3
+ import { getRoot } from '../root/context.js';
4
+
5
+ export interface PickerState {
6
+ props: HTMLButtonAttributes;
7
+ }
8
+
9
+ export function createPicker(): PickerState {
10
+ const root = getRoot();
11
+ const picker: PickerState = {
12
+ props: {
13
+ get disabled() {
14
+ return root.isDisabled;
15
+ },
16
+ get 'aria-controls'() {
17
+ return root.controlId;
18
+ },
19
+ get 'data-disabled'() {
20
+ return root.isDisabled ? '' : undefined;
21
+ },
22
+ type: 'button',
23
+ onmousedown(event) {
24
+ // Prevent losing focus on the input when clicking the toggle.
25
+ event.preventDefault();
26
+ },
27
+ onclick() {
28
+ if (root.isDisabled) {
29
+ return;
30
+ }
31
+
32
+ const input = document.getElementById(root.controlId) as HTMLInputElement | null;
33
+ if (input && 'showPicker' in input) {
34
+ input.showPicker();
35
+ }
36
+ },
37
+ },
38
+ };
39
+
40
+ return picker;
41
+ }
@@ -0,0 +1 @@
1
+ export * from './createPicker.svelte.js';
@@ -0,0 +1,21 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+
3
+ import { getRoot } from '../root/context.js';
4
+
5
+ export interface ErrorState {
6
+ props: HTMLAttributes<HTMLElement>;
7
+ }
8
+
9
+ export function createError(): ErrorState {
10
+ const root = getRoot();
11
+
12
+ const error: ErrorState = {
13
+ props: {
14
+ get id() {
15
+ return root.errorId;
16
+ },
17
+ },
18
+ };
19
+
20
+ return error;
21
+ }
@@ -0,0 +1 @@
1
+ export * from './createError.svelte.js';
@@ -0,0 +1,6 @@
1
+ export * from './date/index.js';
2
+ export * from './error/index.js';
3
+ export * from './input/index.js';
4
+ export * from './label/index.js';
5
+ export * from './password/index.js';
6
+ export * from './root/index.js';
@@ -0,0 +1,136 @@
1
+ import type { HTMLInputAttributes } from 'svelte/elements';
2
+
3
+ import { getRoot } from '../root/context.js';
4
+ import type { RootState } from '../root/createRoot.svelte.js';
5
+
6
+ export interface InputState {
7
+ props: HTMLInputAttributes;
8
+ }
9
+
10
+ type Control = HTMLInputElement;
11
+
12
+ function isCheckboxOrRadio(
13
+ control: Control,
14
+ ): control is HTMLInputElement & { type: 'checkbox' | 'radio' } {
15
+ return control.type === 'checkbox' || control.type === 'radio';
16
+ }
17
+
18
+ function isFilled(control: Control) {
19
+ if (isCheckboxOrRadio(control)) {
20
+ return control.checked;
21
+ }
22
+ return control.value !== '';
23
+ }
24
+
25
+ function syncValidity(root: RootState, control: Control) {
26
+ // If the control doesn't participate in constraint validation, don't force
27
+ // validity state changes.
28
+ if (!control.willValidate) {
29
+ return;
30
+ }
31
+
32
+ const { valid } = control.validity;
33
+ root.isValid = valid;
34
+ root.isInvalid = !valid;
35
+ }
36
+
37
+ export function createInput(): InputState {
38
+ const root = getRoot();
39
+
40
+ return {
41
+ props: {
42
+ get id() {
43
+ return root.controlId;
44
+ },
45
+ get disabled() {
46
+ return root.isDisabled;
47
+ },
48
+ get 'aria-invalid'() {
49
+ return root.isInvalid ? true : undefined;
50
+ },
51
+ get 'aria-describedby'() {
52
+ return root.isInvalid ? root.errorId : undefined;
53
+ },
54
+ get 'data-disabled'() {
55
+ return root.isDisabled ? '' : undefined;
56
+ },
57
+ get 'data-valid'() {
58
+ return root.isValid ? '' : undefined;
59
+ },
60
+ get 'data-invalid'() {
61
+ return root.isInvalid ? '' : undefined;
62
+ },
63
+ get 'data-dirty'() {
64
+ return root.isDirty ? '' : undefined;
65
+ },
66
+ get 'data-touched'() {
67
+ return root.isTouched ? '' : undefined;
68
+ },
69
+ get 'data-filled'() {
70
+ return root.isFilled ? '' : undefined;
71
+ },
72
+ get 'data-focused'() {
73
+ return root.isFocused ? '' : undefined;
74
+ },
75
+ onchange(event) {
76
+ if (root.isDisabled) {
77
+ return;
78
+ }
79
+
80
+ const input = event.currentTarget;
81
+
82
+ root.isDirty = true;
83
+ root.isFilled = isFilled(input);
84
+ syncValidity(root, input);
85
+ },
86
+ oninput(event) {
87
+ if (root.isDisabled) {
88
+ return;
89
+ }
90
+
91
+ const input = event.currentTarget;
92
+
93
+ root.isDirty = true;
94
+ root.isFilled = isFilled(input);
95
+ syncValidity(root, input);
96
+ },
97
+ onfocus(event) {
98
+ if (root.isDisabled) {
99
+ return;
100
+ }
101
+
102
+ const input = event.currentTarget;
103
+
104
+ root.isFocused = true;
105
+ root.isFilled = isFilled(input);
106
+ syncValidity(root, input);
107
+ },
108
+ onblur(event) {
109
+ if (root.isDisabled) {
110
+ return;
111
+ }
112
+
113
+ const input = event.currentTarget;
114
+
115
+ root.isFocused = false;
116
+ root.isTouched = true;
117
+ root.isFilled = isFilled(input);
118
+ syncValidity(root, input);
119
+ },
120
+ onkeydown(event) {
121
+ if (root.isDisabled) {
122
+ return;
123
+ }
124
+ if (event.key !== 'Enter') {
125
+ return;
126
+ }
127
+
128
+ const input = event.currentTarget;
129
+
130
+ root.isTouched = true;
131
+ root.isFilled = isFilled(input);
132
+ syncValidity(root, input);
133
+ },
134
+ },
135
+ };
136
+ }
@@ -0,0 +1 @@
1
+ export * from './createInput.svelte.js';
@@ -0,0 +1,24 @@
1
+ import type { HTMLLabelAttributes } from 'svelte/elements';
2
+
3
+ import { getRoot } from '../root/context.js';
4
+
5
+ export interface LabelState {
6
+ props: HTMLLabelAttributes;
7
+ }
8
+
9
+ export function createLabel(): LabelState {
10
+ const root = getRoot();
11
+
12
+ const label: LabelState = {
13
+ props: {
14
+ get for() {
15
+ return root.controlId;
16
+ },
17
+ get id() {
18
+ return root.labelId;
19
+ },
20
+ },
21
+ };
22
+
23
+ return label;
24
+ }
@@ -0,0 +1 @@
1
+ export * from './createLabel.svelte.js';
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'svelte';
2
+
3
+ import type { PasswordState } from './createPassword.svelte.js';
4
+
5
+ export const [getPassword, setPassword] = createContext<PasswordState>();
@@ -0,0 +1,43 @@
1
+ import { mergeProps } from '@svelte-thing/component-utils';
2
+ import type { Exact } from '@svelte-thing/type-utils';
3
+
4
+ import { type InputState, createInput } from '../input/createInput.svelte.js';
5
+ import { setPassword } from './context.js';
6
+
7
+ export interface CreatePasswordProps {
8
+ isVisible: boolean | null | undefined;
9
+ type: 'password' | null | undefined;
10
+ }
11
+
12
+ export interface PasswordState extends InputState {
13
+ isVisible: boolean;
14
+ toggle: () => void;
15
+ }
16
+
17
+ export function createPassword<T extends CreatePasswordProps>(
18
+ props: Exact<CreatePasswordProps, T>,
19
+ ): PasswordState {
20
+ let isVisible = $derived(props.isVisible ?? false);
21
+
22
+ const input = createInput();
23
+ const password: PasswordState = mergeProps(input, {
24
+ get isVisible() {
25
+ return isVisible;
26
+ },
27
+ set isVisible(visible) {
28
+ isVisible = visible;
29
+ },
30
+ toggle() {
31
+ isVisible = !isVisible;
32
+ },
33
+ props: {
34
+ get type() {
35
+ return isVisible ? 'text' : 'password';
36
+ },
37
+ },
38
+ });
39
+
40
+ setPassword(password);
41
+
42
+ return password;
43
+ }
@@ -0,0 +1,47 @@
1
+ import type { HTMLButtonAttributes } from 'svelte/elements';
2
+
3
+ import { getRoot } from '../root/context.js';
4
+ import { getPassword } from './context.js';
5
+
6
+ export interface ShowState {
7
+ props: HTMLButtonAttributes;
8
+ }
9
+
10
+ export function createShow(): ShowState {
11
+ const root = getRoot();
12
+ const password = getPassword();
13
+ const show: ShowState = {
14
+ props: {
15
+ get disabled() {
16
+ return root.isDisabled;
17
+ },
18
+ get 'aria-controls'() {
19
+ return root.controlId;
20
+ },
21
+ get 'aria-pressed'() {
22
+ return password.isVisible;
23
+ },
24
+ get 'data-disabled'() {
25
+ return root.isDisabled ? '' : undefined;
26
+ },
27
+ get 'data-visible'() {
28
+ return password.isVisible ? '' : undefined;
29
+ },
30
+ type: 'button',
31
+ onmousedown(event) {
32
+ // Prevent losing focus on the input when clicking the toggle.
33
+ event.preventDefault();
34
+ },
35
+ onclick() {
36
+ if (root.isDisabled) {
37
+ return;
38
+ }
39
+
40
+ password.toggle();
41
+ document.getElementById(root.controlId)?.focus?.();
42
+ },
43
+ },
44
+ };
45
+
46
+ return show;
47
+ }
@@ -0,0 +1,3 @@
1
+ export * from './context.js';
2
+ export * from './createPassword.svelte.js';
3
+ export * from './createShow.svelte.js';
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'svelte';
2
+
3
+ import type { RootState } from './createRoot.svelte.js';
4
+
5
+ export const [getRoot, setRoot] = createContext<RootState>();