twintrinsic 0.0.1

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 (212) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +150 -0
  3. package/dist/App/App.svelte +54 -0
  4. package/dist/App/App.svelte.d.ts +65 -0
  5. package/dist/Section.svelte +25 -0
  6. package/dist/Section.svelte.d.ts +34 -0
  7. package/dist/actions/clickOutside.d.ts +9 -0
  8. package/dist/actions/clickOutside.js +19 -0
  9. package/dist/actions/index.d.ts +1 -0
  10. package/dist/actions/index.js +1 -0
  11. package/dist/components/Accordion/Accordion.svelte +75 -0
  12. package/dist/components/Accordion/Accordion.svelte.d.ts +39 -0
  13. package/dist/components/Accordion/AccordionItem.svelte +150 -0
  14. package/dist/components/Accordion/AccordionItem.svelte.d.ts +30 -0
  15. package/dist/components/App/App.story.md +8 -0
  16. package/dist/components/App/App.story.svelte +170 -0
  17. package/dist/components/App/App.story.svelte.d.ts +22 -0
  18. package/dist/components/App/App.svelte +77 -0
  19. package/dist/components/App/App.svelte.d.ts +66 -0
  20. package/dist/components/App/Split.svelte +346 -0
  21. package/dist/components/App/Split.svelte.d.ts +54 -0
  22. package/dist/components/App/index.d.ts +2 -0
  23. package/dist/components/App/index.js +3 -0
  24. package/dist/components/AppHeader/AppHeader.svelte +439 -0
  25. package/dist/components/AppHeader/AppHeader.svelte.d.ts +24 -0
  26. package/dist/components/Avatar/Avatar.svelte +300 -0
  27. package/dist/components/Avatar/Avatar.svelte.d.ts +48 -0
  28. package/dist/components/Avatar/AvatarGroup.svelte +185 -0
  29. package/dist/components/Avatar/AvatarGroup.svelte.d.ts +46 -0
  30. package/dist/components/Badge/Badge.svelte +186 -0
  31. package/dist/components/Badge/Badge.svelte.d.ts +51 -0
  32. package/dist/components/BottomBar/BottomBar.svelte +146 -0
  33. package/dist/components/BottomBar/BottomBar.svelte.d.ts +38 -0
  34. package/dist/components/Breadcrumb/Breadcrumb.svelte +77 -0
  35. package/dist/components/Breadcrumb/Breadcrumb.svelte.d.ts +42 -0
  36. package/dist/components/Breadcrumb/BreadcrumbItem.svelte +171 -0
  37. package/dist/components/Breadcrumb/BreadcrumbItem.svelte.d.ts +38 -0
  38. package/dist/components/Button/Button.svelte +252 -0
  39. package/dist/components/Button/Button.svelte.d.ts +80 -0
  40. package/dist/components/Button/ButtonGroup.svelte +127 -0
  41. package/dist/components/Button/ButtonGroup.svelte.d.ts +44 -0
  42. package/dist/components/Card/Card.svelte +152 -0
  43. package/dist/components/Card/Card.svelte.d.ts +55 -0
  44. package/dist/components/Carousel/Carousel.svelte +461 -0
  45. package/dist/components/Carousel/Carousel.svelte.d.ts +79 -0
  46. package/dist/components/Carousel/CarouselItem.svelte +149 -0
  47. package/dist/components/Carousel/CarouselItem.svelte.d.ts +35 -0
  48. package/dist/components/Chip/Chip.svelte +288 -0
  49. package/dist/components/Chip/Chip.svelte.d.ts +71 -0
  50. package/dist/components/Chip/ChipGroup.svelte +190 -0
  51. package/dist/components/Chip/ChipGroup.svelte.d.ts +71 -0
  52. package/dist/components/CodeBlock/CodeBlock.svelte +356 -0
  53. package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +44 -0
  54. package/dist/components/CodeBlock/index.d.ts +1 -0
  55. package/dist/components/CodeBlock/index.js +1 -0
  56. package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte +145 -0
  57. package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte.d.ts +44 -0
  58. package/dist/components/CodeEditor/CodeEditor.svelte +229 -0
  59. package/dist/components/CodeEditor/CodeEditor.svelte.d.ts +23 -0
  60. package/dist/components/Combobox/Combobox.svelte +279 -0
  61. package/dist/components/Combobox/Combobox.svelte.d.ts +34 -0
  62. package/dist/components/Container/Container.svelte +45 -0
  63. package/dist/components/Container/Container.svelte.d.ts +36 -0
  64. package/dist/components/DataTable/DataTable.svelte +879 -0
  65. package/dist/components/DataTable/DataTable.svelte.d.ts +102 -0
  66. package/dist/components/Form/AutoComplete.svelte +357 -0
  67. package/dist/components/Form/AutoComplete.svelte.d.ts +73 -0
  68. package/dist/components/Form/Calendar.svelte +429 -0
  69. package/dist/components/Form/Calendar.svelte.d.ts +53 -0
  70. package/dist/components/Form/Checkbox.svelte +196 -0
  71. package/dist/components/Form/Checkbox.svelte.d.ts +50 -0
  72. package/dist/components/Form/ColorPicker.svelte +396 -0
  73. package/dist/components/Form/ColorPicker.svelte.d.ts +43 -0
  74. package/dist/components/Form/Combobox.svelte +645 -0
  75. package/dist/components/Form/Combobox.svelte.d.ts +93 -0
  76. package/dist/components/Form/Dropdown.svelte +773 -0
  77. package/dist/components/Form/Dropdown.svelte.d.ts +81 -0
  78. package/dist/components/Form/FileUpload.svelte +796 -0
  79. package/dist/components/Form/FileUpload.svelte.d.ts +78 -0
  80. package/dist/components/Form/FloatLabel.svelte +245 -0
  81. package/dist/components/Form/FloatLabel.svelte.d.ts +44 -0
  82. package/dist/components/Form/Form.svelte +281 -0
  83. package/dist/components/Form/Form.svelte.d.ts +54 -0
  84. package/dist/components/Form/FormField.svelte +218 -0
  85. package/dist/components/Form/FormField.svelte.d.ts +47 -0
  86. package/dist/components/Form/Input.svelte +340 -0
  87. package/dist/components/Form/Input.svelte.d.ts +79 -0
  88. package/dist/components/Form/InputSwitch.svelte +189 -0
  89. package/dist/components/Form/InputSwitch.svelte.d.ts +46 -0
  90. package/dist/components/Form/InvalidState.svelte +97 -0
  91. package/dist/components/Form/InvalidState.svelte.d.ts +37 -0
  92. package/dist/components/Form/Knob.svelte +537 -0
  93. package/dist/components/Form/Knob.svelte.d.ts +78 -0
  94. package/dist/components/Form/ListInput.svelte +469 -0
  95. package/dist/components/Form/ListInput.svelte.d.ts +70 -0
  96. package/dist/components/Form/Listbox.svelte +513 -0
  97. package/dist/components/Form/Listbox.svelte.d.ts +74 -0
  98. package/dist/components/Form/NumberInput.svelte +452 -0
  99. package/dist/components/Form/NumberInput.svelte.d.ts +82 -0
  100. package/dist/components/Form/Radio.svelte +192 -0
  101. package/dist/components/Form/Radio.svelte.d.ts +53 -0
  102. package/dist/components/Form/RadioGroup.svelte +155 -0
  103. package/dist/components/Form/RadioGroup.svelte.d.ts +48 -0
  104. package/dist/components/Form/Rating.svelte +380 -0
  105. package/dist/components/Form/Rating.svelte.d.ts +64 -0
  106. package/dist/components/Form/Select.svelte +436 -0
  107. package/dist/components/Form/Select.svelte.d.ts +49 -0
  108. package/dist/components/Form/SelectGroup.svelte +34 -0
  109. package/dist/components/Form/SelectGroup.svelte.d.ts +33 -0
  110. package/dist/components/Form/Slider.svelte +622 -0
  111. package/dist/components/Form/Slider.svelte.d.ts +73 -0
  112. package/dist/components/Form/Switch.svelte +192 -0
  113. package/dist/components/Form/Switch.svelte.d.ts +46 -0
  114. package/dist/components/Form/TextInput.svelte +274 -0
  115. package/dist/components/Form/TextInput.svelte.d.ts +74 -0
  116. package/dist/components/Form/Textarea.svelte +207 -0
  117. package/dist/components/Form/Textarea.svelte.d.ts +62 -0
  118. package/dist/components/Icon/Icon.svelte +140 -0
  119. package/dist/components/Icon/Icon.svelte.d.ts +25 -0
  120. package/dist/components/Icon/index.d.ts +1 -0
  121. package/dist/components/Icon/index.js +1 -0
  122. package/dist/components/Lazy/Lazy.svelte +158 -0
  123. package/dist/components/Lazy/Lazy.svelte.d.ts +42 -0
  124. package/dist/components/Masonry/Masonry.svelte +299 -0
  125. package/dist/components/Masonry/Masonry.svelte.d.ts +55 -0
  126. package/dist/components/Menu/Menu/Menu.svelte +65 -0
  127. package/dist/components/Menu/Menu/Menu.svelte.d.ts +17 -0
  128. package/dist/components/Menu/Menu/MenuItem.svelte +90 -0
  129. package/dist/components/Menu/Menu/MenuItem.svelte.d.ts +27 -0
  130. package/dist/components/Modal/Modal.svelte +334 -0
  131. package/dist/components/Modal/Modal.svelte.d.ts +55 -0
  132. package/dist/components/Panel/Card.svelte +141 -0
  133. package/dist/components/Panel/Card.svelte.d.ts +52 -0
  134. package/dist/components/Panel/Hero/Hero.story.md +9 -0
  135. package/dist/components/Panel/Hero/Hero.story.svelte +49 -0
  136. package/dist/components/Panel/Hero/Hero.story.svelte.d.ts +21 -0
  137. package/dist/components/Panel/Hero/Hero.svelte +24 -0
  138. package/dist/components/Panel/Hero/Hero.svelte.d.ts +32 -0
  139. package/dist/components/Panel/LazyPanel.svelte +110 -0
  140. package/dist/components/Panel/LazyPanel.svelte.d.ts +46 -0
  141. package/dist/components/Panel/Panel.svelte +205 -0
  142. package/dist/components/Panel/Panel.svelte.d.ts +23 -0
  143. package/dist/components/Progress/Progress.svelte +220 -0
  144. package/dist/components/Progress/Progress.svelte.d.ts +61 -0
  145. package/dist/components/Separator/Separator.svelte +109 -0
  146. package/dist/components/Separator/Separator.svelte.d.ts +35 -0
  147. package/dist/components/Sidebar/Sidebar.svelte +213 -0
  148. package/dist/components/Sidebar/Sidebar.svelte.d.ts +60 -0
  149. package/dist/components/Skeleton/Skeleton.svelte +170 -0
  150. package/dist/components/Skeleton/Skeleton.svelte.d.ts +48 -0
  151. package/dist/components/Stepper/Stepper.svelte +111 -0
  152. package/dist/components/Stepper/Stepper.svelte.d.ts +54 -0
  153. package/dist/components/Stepper/StepperStep.svelte +369 -0
  154. package/dist/components/Stepper/StepperStep.svelte.d.ts +63 -0
  155. package/dist/components/Table/Table.svelte +167 -0
  156. package/dist/components/Table/Table.svelte.d.ts +56 -0
  157. package/dist/components/Table/TableBody.svelte +41 -0
  158. package/dist/components/Table/TableBody.svelte.d.ts +33 -0
  159. package/dist/components/Table/TableCell.svelte +76 -0
  160. package/dist/components/Table/TableCell.svelte.d.ts +36 -0
  161. package/dist/components/Table/TableHead.svelte +41 -0
  162. package/dist/components/Table/TableHead.svelte.d.ts +32 -0
  163. package/dist/components/Table/TableHeader.svelte +148 -0
  164. package/dist/components/Table/TableHeader.svelte.d.ts +42 -0
  165. package/dist/components/Table/TableRow.svelte +99 -0
  166. package/dist/components/Table/TableRow.svelte.d.ts +40 -0
  167. package/dist/components/Tabs/Tab.svelte +145 -0
  168. package/dist/components/Tabs/Tab.svelte.d.ts +36 -0
  169. package/dist/components/Tabs/TabList.svelte +60 -0
  170. package/dist/components/Tabs/TabList.svelte.d.ts +32 -0
  171. package/dist/components/Tabs/TabPanel.svelte +118 -0
  172. package/dist/components/Tabs/TabPanel.svelte.d.ts +38 -0
  173. package/dist/components/Tabs/Tabs.svelte +287 -0
  174. package/dist/components/Tabs/Tabs.svelte.d.ts +50 -0
  175. package/dist/components/Tag/Tag.svelte +260 -0
  176. package/dist/components/Tag/Tag.svelte.d.ts +54 -0
  177. package/dist/components/Tag/TagGroup.svelte +147 -0
  178. package/dist/components/Tag/TagGroup.svelte.d.ts +62 -0
  179. package/dist/components/ThemeToggle/ThemeToggle.svelte +93 -0
  180. package/dist/components/ThemeToggle/ThemeToggle.svelte.d.ts +12 -0
  181. package/dist/components/Timeline/Timeline.svelte +144 -0
  182. package/dist/components/Timeline/Timeline.svelte.d.ts +48 -0
  183. package/dist/components/Timeline/TimelineItem.svelte +391 -0
  184. package/dist/components/Timeline/TimelineItem.svelte.d.ts +63 -0
  185. package/dist/components/Toast/Toast.svelte +313 -0
  186. package/dist/components/Toast/Toast.svelte.d.ts +44 -0
  187. package/dist/components/Toast/toastStore.d.ts +40 -0
  188. package/dist/components/Toast/toastStore.js +293 -0
  189. package/dist/components/Tooltip/Tooltip.svelte +282 -0
  190. package/dist/components/Tooltip/Tooltip.svelte.d.ts +55 -0
  191. package/dist/components/Tree/Tree.svelte +129 -0
  192. package/dist/components/Tree/Tree.svelte.d.ts +61 -0
  193. package/dist/components/Tree/TreeNode.svelte +332 -0
  194. package/dist/components/Tree/TreeNode.svelte.d.ts +55 -0
  195. package/dist/components/icons/TwintrinsicLogo.svelte +73 -0
  196. package/dist/components/icons/TwintrinsicLogo.svelte.d.ts +17 -0
  197. package/dist/components/icons/twintrinsic-source.svg +73 -0
  198. package/dist/components/icons/twintrinsic.svg +38 -0
  199. package/dist/docs/EventsTable.svelte +86 -0
  200. package/dist/docs/EventsTable.svelte.d.ts +27 -0
  201. package/dist/docs/PropsTable.svelte +103 -0
  202. package/dist/docs/PropsTable.svelte.d.ts +28 -0
  203. package/dist/docs/index.d.ts +2 -0
  204. package/dist/docs/index.js +2 -0
  205. package/dist/helpers/detectLanguage.d.ts +6 -0
  206. package/dist/helpers/detectLanguage.js +60 -0
  207. package/dist/helpers/index.d.ts +1 -0
  208. package/dist/helpers/index.js +1 -0
  209. package/dist/index.d.ts +86 -0
  210. package/dist/index.js +94 -0
  211. package/dist/twintrinsic.css +347 -0
  212. package/package.json +98 -0
@@ -0,0 +1,53 @@
1
+ export default Radio;
2
+ type Radio = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * Radio - A styled radio button component.
8
+ * Provides consistent styling, accessibility features, and integration with the Form component.
9
+ *
10
+ * Usage:
11
+ * ```svelte
12
+ * <Radio
13
+ * name="theme"
14
+ * value="light"
15
+ * label="Light theme"
16
+ * checked={theme === 'light'}
17
+ * />
18
+ *
19
+ * <FormField label="Select theme">
20
+ * <div class="flex gap-4">
21
+ * <Radio name="theme" value="light" label="Light" />
22
+ * <Radio name="theme" value="dark" label="Dark" />
23
+ * <Radio name="theme" value="system" label="System" />
24
+ * </div>
25
+ * </FormField>
26
+ * ```
27
+ */
28
+ declare const Radio: import("svelte").Component<{
29
+ class?: string;
30
+ id?: any;
31
+ name: any;
32
+ value: any;
33
+ label: any;
34
+ checked?: boolean;
35
+ required?: boolean;
36
+ disabled?: boolean;
37
+ size?: string;
38
+ ariaLabel: any;
39
+ onchange: any;
40
+ } & Record<string, any>, {}, "">;
41
+ type $$ComponentProps = {
42
+ class?: string;
43
+ id?: any;
44
+ name: any;
45
+ value: any;
46
+ label: any;
47
+ checked?: boolean;
48
+ required?: boolean;
49
+ disabled?: boolean;
50
+ size?: string;
51
+ ariaLabel: any;
52
+ onchange: any;
53
+ } & Record<string, any>;
@@ -0,0 +1,155 @@
1
+ <!--
2
+ @component
3
+ RadioGroup - A component for grouping related radio buttons.
4
+ Provides consistent styling, accessibility features, and integration with the Form component.
5
+
6
+ Usage:
7
+ ```svelte
8
+ <RadioGroup
9
+ name="theme"
10
+ value="light"
11
+ legend="Select theme"
12
+ >
13
+ <Radio value="light" label="Light" />
14
+ <Radio value="dark" label="Dark" />
15
+ <Radio value="system" label="System" />
16
+ </RadioGroup>
17
+ ```
18
+ -->
19
+ <script>
20
+ import { getContext, setContext } from "svelte"
21
+
22
+ const {
23
+ /** @type {string} - Additional CSS classes */
24
+ class: className = "",
25
+
26
+ /** @type {string} - HTML id for accessibility */
27
+ id = crypto.randomUUID(),
28
+
29
+ /** @type {string} - Radio group name */
30
+ name,
31
+
32
+ /** @type {string} - Currently selected value */
33
+ value = "",
34
+
35
+ /** @type {string} - Legend text for the fieldset */
36
+ legend,
37
+
38
+ /** @type {boolean} - Whether the radio group is required */
39
+ required = false,
40
+
41
+ /** @type {boolean} - Whether the radio group is disabled */
42
+ disabled = false,
43
+
44
+ /** @type {string} - Layout direction (horizontal or vertical) */
45
+ layout = "vertical",
46
+
47
+ /** @type {string} - Size of the radio buttons (sm, md, lg) */
48
+ size = "md",
49
+
50
+ /** @type {(event: CustomEvent) => void} - Change event handler */
51
+ onchange,
52
+
53
+ children,
54
+ } = $props()
55
+
56
+ // Get form context if available
57
+ const formContext = getContext("form")
58
+
59
+ // Radio group state
60
+ let selectedValue = $state(value)
61
+
62
+ // Update selected value when prop changes
63
+ $effect(() => {
64
+ selectedValue = value
65
+ })
66
+
67
+ // Register with form if available
68
+ let fieldApi = $state()
69
+
70
+ $effect(() => {
71
+ if (formContext && name) {
72
+ fieldApi = formContext.registerField(name, value)
73
+ }
74
+ })
75
+
76
+ // Update value when form field changes
77
+ $effect(() => {
78
+ if (fieldApi) {
79
+ const formValue = fieldApi.getValue()
80
+ if (formValue !== undefined && formValue !== selectedValue) {
81
+ selectedValue = formValue
82
+ }
83
+ }
84
+ })
85
+
86
+ /**
87
+ * Handles radio selection
88
+ * @param {CustomEvent} event - Change event from Radio component
89
+ */
90
+ function handleRadioChange(event) {
91
+ const { value: radioValue } = event.detail
92
+ selectedValue = radioValue
93
+
94
+ // Update form field if available
95
+ if (fieldApi) {
96
+ fieldApi.setValue(radioValue)
97
+ }
98
+
99
+ onchange?.(new CustomEvent("change", { detail: { value: radioValue } }))
100
+ }
101
+
102
+ // Provide context for child Radio components
103
+ $effect(() => {
104
+ setContext("radioGroup", {
105
+ name,
106
+ selectedValue: () => selectedValue,
107
+ required,
108
+ disabled: () => disabled || (fieldApi && fieldApi.isDisabled()),
109
+ size,
110
+ onChange: handleRadioChange,
111
+ })
112
+ })
113
+ </script>
114
+
115
+ <fieldset
116
+ {id}
117
+ class="radio-group {layout === 'horizontal' ? 'radio-group-horizontal' : 'radio-group-vertical'} {className}"
118
+ {disabled}
119
+ >
120
+ {#if legend}
121
+ <legend class="radio-group-legend">{legend}</legend>
122
+ {/if}
123
+
124
+ <div class="radio-group-items">
125
+ {@render children?.()}
126
+ </div>
127
+ </fieldset>
128
+
129
+ <style>
130
+ @reference "../../twintrinsic.css";
131
+
132
+ .radio-group {
133
+ @apply border-0 p-0 m-0;
134
+ }
135
+
136
+ .radio-group-legend {
137
+ @apply text-sm font-medium text-text dark:text-text mb-2;
138
+ }
139
+
140
+ .radio-group-items {
141
+ @apply flex;
142
+ }
143
+
144
+ .radio-group-vertical .radio-group-items {
145
+ @apply flex-col gap-2;
146
+ }
147
+
148
+ .radio-group-horizontal .radio-group-items {
149
+ @apply flex-row flex-wrap gap-4;
150
+ }
151
+
152
+ .radio-group[disabled] {
153
+ @apply opacity-50 cursor-not-allowed;
154
+ }
155
+ </style>
@@ -0,0 +1,48 @@
1
+ export default RadioGroup;
2
+ type RadioGroup = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * RadioGroup - A component for grouping related radio buttons.
8
+ * Provides consistent styling, accessibility features, and integration with the Form component.
9
+ *
10
+ * Usage:
11
+ * ```svelte
12
+ * <RadioGroup
13
+ * name="theme"
14
+ * value="light"
15
+ * legend="Select theme"
16
+ * >
17
+ * <Radio value="light" label="Light" />
18
+ * <Radio value="dark" label="Dark" />
19
+ * <Radio value="system" label="System" />
20
+ * </RadioGroup>
21
+ * ```
22
+ */
23
+ declare const RadioGroup: import("svelte").Component<{
24
+ class?: string;
25
+ id?: any;
26
+ name: any;
27
+ value?: string;
28
+ legend: any;
29
+ required?: boolean;
30
+ disabled?: boolean;
31
+ layout?: string;
32
+ size?: string;
33
+ onchange: any;
34
+ children: any;
35
+ }, {}, "">;
36
+ type $$ComponentProps = {
37
+ class?: string;
38
+ id?: any;
39
+ name: any;
40
+ value?: string;
41
+ legend: any;
42
+ required?: boolean;
43
+ disabled?: boolean;
44
+ layout?: string;
45
+ size?: string;
46
+ onchange: any;
47
+ children: any;
48
+ };
@@ -0,0 +1,380 @@
1
+ <!--
2
+ @component
3
+ Rating - A component for collecting user ratings through stars or other symbols.
4
+ Provides consistent styling, accessibility features, and interactive options.
5
+
6
+ Usage:
7
+ ```svelte
8
+ <Rating value={3} />
9
+
10
+ <Rating
11
+ value={4.5}
12
+ max={5}
13
+ precision={0.5}
14
+ size="lg"
15
+ readonly={false}
16
+ onchange={(e) => console.log(e.detail.value)}
17
+ />
18
+
19
+ <Rating
20
+ value={2}
21
+ icon="<svg>...</svg>"
22
+ emptyIcon="<svg>...</svg>"
23
+ variant="warning"
24
+ />
25
+ ```
26
+ -->
27
+ <script>
28
+ const {
29
+ /** @type {string} - Additional CSS classes */
30
+ class: className = "",
31
+
32
+ /** @type {string} - HTML id for accessibility */
33
+ id = crypto.randomUUID(),
34
+
35
+ /** @type {number} - Current rating value */
36
+ value = 0,
37
+
38
+ /** @type {number} - Maximum rating value */
39
+ max = 5,
40
+
41
+ /** @type {number} - Step size for ratings (0.5 for half stars, 1 for whole stars) */
42
+ precision = 1,
43
+
44
+ /** @type {string} - Size of the rating icons (sm, md, lg) */
45
+ size = "md",
46
+
47
+ /** @type {string} - Visual style variant */
48
+ variant = "warning",
49
+
50
+ /** @type {boolean} - Whether the rating is readonly */
51
+ readonly = false,
52
+
53
+ /** @type {boolean} - Whether the rating is disabled */
54
+ disabled = false,
55
+
56
+ /** @type {boolean} - Whether to show the numeric value */
57
+ showValue = false,
58
+
59
+ /** @type {string} - Custom icon for filled state (HTML or SVG string) */
60
+ icon,
61
+
62
+ /** @type {string} - Custom icon for empty state (HTML or SVG string) */
63
+ emptyIcon,
64
+
65
+ /** @type {string} - Name attribute for form submission */
66
+ name,
67
+
68
+ /** @type {string} - ARIA label for accessibility */
69
+ ariaLabel = "Rating",
70
+
71
+ /** @type {(event: CustomEvent) => void} - Change event handler */
72
+ onchange,
73
+ } = $props()
74
+
75
+ // Component state
76
+ let currentValue = $state(value)
77
+ let hoverValue = $state(-1)
78
+ let isDragging = $state(false)
79
+ let ratingElement = $state()
80
+
81
+ // Update internal value when prop changes
82
+ $effect(() => {
83
+ currentValue = value
84
+ })
85
+
86
+ // Computed values
87
+ const displayValue = $derived(hoverValue >= 0 ? hoverValue : currentValue)
88
+ const isInteractive = $derived(!readonly && !disabled)
89
+
90
+ // Determine size classes
91
+ const sizeClasses = $derived(
92
+ {
93
+ sm: "text-sm gap-0.5",
94
+ md: "text-base gap-1",
95
+ lg: "text-lg gap-1.5",
96
+ }[size] || "text-base gap-1"
97
+ )
98
+
99
+ // Determine icon size classes
100
+ const iconSizeClasses = $derived(
101
+ {
102
+ sm: "w-4 h-4",
103
+ md: "w-5 h-5",
104
+ lg: "w-6 h-6",
105
+ }[size] || "w-5 h-5"
106
+ )
107
+
108
+ // Determine variant classes
109
+ const variantClasses = $derived(
110
+ {
111
+ default: "text-muted dark:text-muted",
112
+ primary: "text-primary-500 dark:text-primary-500",
113
+ secondary: "text-secondary-500 dark:text-secondary-500",
114
+ success: "text-success-500 dark:text-success-500",
115
+ warning: "text-warning-500 dark:text-warning-500",
116
+ error: "text-error-500 dark:text-error-500",
117
+ info: "text-info-500 dark:text-info-500",
118
+ }[variant] || "text-warning-500 dark:text-warning-500"
119
+ )
120
+
121
+ // Generate items array based on max and precision
122
+ const items = $derived(Array.from({ length: max / precision }, (_, i) => (i + 1) * precision))
123
+
124
+ /**
125
+ * Calculates the value based on mouse position
126
+ * @param {MouseEvent|TouchEvent} event - Mouse or touch event
127
+ * @returns {number} - Calculated value
128
+ */
129
+ function calculateValue(event) {
130
+ if (!ratingElement) return 0
131
+
132
+ const rect = ratingElement.getBoundingClientRect()
133
+ const clientX = event.type.startsWith("touch") ? event.touches[0].clientX : event.clientX
134
+
135
+ // Calculate percentage of width
136
+ const percent = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width))
137
+
138
+ // Calculate value based on percentage, max, and precision
139
+ const rawValue = percent * max
140
+
141
+ // Round to nearest precision step
142
+ return Math.max(precision, Math.round(rawValue / precision) * precision)
143
+ }
144
+
145
+ /**
146
+ * Handles mouse move or touch move events
147
+ * @param {MouseEvent|TouchEvent} event - Mouse or touch event
148
+ */
149
+ function handleMove(event) {
150
+ if (!isInteractive) return
151
+
152
+ if (isDragging || event.type === "mousemove") {
153
+ hoverValue = calculateValue(event)
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Handles mouse down or touch start events
159
+ * @param {MouseEvent|TouchEvent} event - Mouse or touch event
160
+ */
161
+ function handleStart(event) {
162
+ if (!isInteractive) return
163
+
164
+ isDragging = true
165
+ hoverValue = calculateValue(event)
166
+
167
+ // Add document event listeners for drag
168
+ if (event.type === "mousedown") {
169
+ document.addEventListener("mousemove", handleMove)
170
+ document.addEventListener("mouseup", handleEnd)
171
+ } else if (event.type === "touchstart") {
172
+ document.addEventListener("touchmove", handleMove, { passive: true })
173
+ document.addEventListener("touchend", handleEnd)
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Handles mouse up or touch end events
179
+ */
180
+ function handleEnd() {
181
+ if (!isInteractive || !isDragging) return
182
+
183
+ // Update value and dispatch change event
184
+ if (hoverValue >= 0) {
185
+ currentValue = hoverValue
186
+ onchange?.(new CustomEvent("change", { detail: { value: currentValue } }))
187
+ }
188
+
189
+ isDragging = false
190
+
191
+ // Remove document event listeners
192
+ document.removeEventListener("mousemove", handleMove)
193
+ document.removeEventListener("mouseup", handleEnd)
194
+ document.removeEventListener("touchmove", handleMove)
195
+ document.removeEventListener("touchend", handleEnd)
196
+ }
197
+
198
+ /**
199
+ * Handles mouse enter events
200
+ */
201
+ function handleEnter() {
202
+ if (!isInteractive) return
203
+ hoverValue = currentValue
204
+ }
205
+
206
+ /**
207
+ * Handles mouse leave events
208
+ */
209
+ function handleLeave() {
210
+ if (!isInteractive || isDragging) return
211
+ hoverValue = -1
212
+ }
213
+
214
+ /**
215
+ * Handles click events on individual items
216
+ * @param {number} itemValue - Value of the clicked item
217
+ */
218
+ function handleItemClick(itemValue) {
219
+ if (!isInteractive) return
220
+
221
+ // Toggle off if clicking the same value
222
+ if (currentValue === itemValue && precision === 1) {
223
+ currentValue = 0
224
+ } else {
225
+ currentValue = itemValue
226
+ }
227
+
228
+ hoverValue = currentValue
229
+ onchange?.(new CustomEvent("change", { detail: { value: currentValue } }))
230
+ }
231
+
232
+ /**
233
+ * Handles keyboard navigation
234
+ * @param {KeyboardEvent} event - Keydown event
235
+ */
236
+ function handleKeydown(event) {
237
+ if (!isInteractive) return
238
+
239
+ let newValue = currentValue
240
+
241
+ switch (event.key) {
242
+ case "ArrowRight":
243
+ case "ArrowUp":
244
+ newValue = Math.min(max, currentValue + precision)
245
+ break
246
+ case "ArrowLeft":
247
+ case "ArrowDown":
248
+ newValue = Math.max(0, currentValue - precision)
249
+ break
250
+ case "Home":
251
+ newValue = precision
252
+ break
253
+ case "End":
254
+ newValue = max
255
+ break
256
+ default:
257
+ return
258
+ }
259
+
260
+ if (newValue !== currentValue) {
261
+ currentValue = newValue
262
+ hoverValue = newValue
263
+ dispatch("change", { value: currentValue })
264
+ event.preventDefault()
265
+ }
266
+ }
267
+ </script>
268
+
269
+ <div
270
+ {id}
271
+ class="
272
+ rating
273
+ {sizeClasses}
274
+ {isInteractive ? 'rating-interactive' : ''}
275
+ {disabled ? 'rating-disabled' : ''}
276
+ {className}
277
+ "
278
+ role={isInteractive ? 'slider' : 'img'}
279
+ aria-label={ariaLabel}
280
+ aria-valuemin={isInteractive ? 0 : undefined}
281
+ aria-valuemax={isInteractive ? max : undefined}
282
+ aria-valuenow={isInteractive ? currentValue : undefined}
283
+ aria-valuetext={isInteractive ? `${currentValue} out of ${max}` : undefined}
284
+ aria-readonly={readonly ? true : undefined}
285
+ aria-disabled={disabled ? true : undefined}
286
+ tabindex={isInteractive ? 0 : undefined}
287
+ onmousedown={handleStart}
288
+ ontouchstart={handleStart}
289
+ onmouseenter={handleEnter}
290
+ onmouseleave={handleLeave}
291
+ onkeydown={handleKeydown}
292
+ bind:this={ratingElement}
293
+ >
294
+ {#if name && isInteractive}
295
+ <input type="hidden" {name} value={currentValue} />
296
+ {/if}
297
+
298
+ <div class="rating-items">
299
+ {#each items as item}
300
+ <span
301
+ class="
302
+ rating-item
303
+ {item <= displayValue ? 'rating-item-filled' : 'rating-item-empty'}
304
+ {variantClasses}
305
+ "
306
+ role={isInteractive ? 'presentation' : undefined}
307
+ onclick={() => handleItemClick(item)}
308
+ >
309
+ {#if item <= displayValue}
310
+ {#if icon}
311
+ <span class="rating-icon {iconSizeClasses}">
312
+ {@html icon}
313
+ </span>
314
+ {:else}
315
+ <svg class="{iconSizeClasses}" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
316
+ <path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path>
317
+ </svg>
318
+ {/if}
319
+ {:else}
320
+ {#if emptyIcon}
321
+ <span class="rating-icon {iconSizeClasses}">
322
+ {@html emptyIcon}
323
+ </span>
324
+ {:else}
325
+ <svg class="{iconSizeClasses}" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
326
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path>
327
+ </svg>
328
+ {/if}
329
+ {/if}
330
+ </span>
331
+ {/each}
332
+ </div>
333
+
334
+ {#if showValue}
335
+ <span class="rating-value">
336
+ {currentValue}
337
+ </span>
338
+ {/if}
339
+ </div>
340
+
341
+ <style>
342
+ @reference "../../twintrinsic.css";
343
+
344
+ .rating {
345
+ @apply inline-flex items-center;
346
+ }
347
+
348
+ .rating-interactive {
349
+ @apply cursor-pointer;
350
+ @apply focus:outline-none focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400 focus:ring-offset-2 rounded;
351
+ }
352
+
353
+ .rating-disabled {
354
+ @apply opacity-50 cursor-not-allowed;
355
+ @apply pointer-events-none;
356
+ }
357
+
358
+ .rating-items {
359
+ @apply inline-flex;
360
+ }
361
+
362
+ .rating-item {
363
+ @apply inline-flex items-center justify-center;
364
+ @apply transition-colors duration-150;
365
+ }
366
+
367
+ .rating-item-empty {
368
+ @apply text-muted/30 dark:text-muted/30;
369
+ }
370
+
371
+ .rating-interactive .rating-item {
372
+ @apply hover:scale-110;
373
+ @apply transition-transform duration-150;
374
+ }
375
+
376
+ .rating-value {
377
+ @apply ml-2 font-medium;
378
+ @apply text-text dark:text-text;
379
+ }
380
+ </style>
@@ -0,0 +1,64 @@
1
+ export default Rating;
2
+ type Rating = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * Rating - A component for collecting user ratings through stars or other symbols.
8
+ * Provides consistent styling, accessibility features, and interactive options.
9
+ *
10
+ * Usage:
11
+ * ```svelte
12
+ * <Rating value={3} />
13
+ *
14
+ * <Rating
15
+ * value={4.5}
16
+ * max={5}
17
+ * precision={0.5}
18
+ * size="lg"
19
+ * readonly={false}
20
+ * onchange={(e) => console.log(e.detail.value)}
21
+ * />
22
+ *
23
+ * <Rating
24
+ * value={2}
25
+ * icon="<svg>...</svg>"
26
+ * emptyIcon="<svg>...</svg>"
27
+ * variant="warning"
28
+ * />
29
+ * ```
30
+ */
31
+ declare const Rating: import("svelte").Component<{
32
+ class?: string;
33
+ id?: any;
34
+ value?: number;
35
+ max?: number;
36
+ precision?: number;
37
+ size?: string;
38
+ variant?: string;
39
+ readonly?: boolean;
40
+ disabled?: boolean;
41
+ showValue?: boolean;
42
+ icon: any;
43
+ emptyIcon: any;
44
+ name: any;
45
+ ariaLabel?: string;
46
+ onchange: any;
47
+ }, {}, "">;
48
+ type $$ComponentProps = {
49
+ class?: string;
50
+ id?: any;
51
+ value?: number;
52
+ max?: number;
53
+ precision?: number;
54
+ size?: string;
55
+ variant?: string;
56
+ readonly?: boolean;
57
+ disabled?: boolean;
58
+ showValue?: boolean;
59
+ icon: any;
60
+ emptyIcon: any;
61
+ name: any;
62
+ ariaLabel?: string;
63
+ onchange: any;
64
+ };