@rkosafo/cai.components 0.0.75 → 0.0.78

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 (127) hide show
  1. package/README.md +8 -8
  2. package/dist/baseEditor/index.svelte +32 -32
  3. package/dist/builders/filters/FilterBuilder.svelte +641 -641
  4. package/dist/forms/FormCheckbox/FormCheckbox.svelte +53 -53
  5. package/dist/forms/FormClEditor/ClEdito.svelte +68 -68
  6. package/dist/forms/FormDatepicker/FormDatepicker.svelte +159 -159
  7. package/dist/forms/FormFileUpload/FormFileUplad.svelte +134 -134
  8. package/dist/forms/FormInput/FormInput.svelte +87 -87
  9. package/dist/forms/FormRadio/FormRadio.svelte +53 -53
  10. package/dist/forms/FormSelect/FormSelect.svelte +88 -88
  11. package/dist/forms/FormTextarea/FormTextarea.svelte +78 -78
  12. package/dist/forms/button-toggle/ButtonToggle.svelte +119 -0
  13. package/dist/forms/button-toggle/ButtonToggle.svelte.d.ts +139 -0
  14. package/dist/forms/button-toggle/ButtonToggleGroup.svelte +0 -0
  15. package/dist/forms/button-toggle/ButtonToggleGroup.svelte.d.ts +26 -0
  16. package/dist/forms/button-toggle/CheckIcon.svelte +28 -0
  17. package/dist/forms/button-toggle/CheckIcon.svelte.d.ts +4 -0
  18. package/dist/forms/button-toggle/index.d.ts +4 -0
  19. package/dist/forms/button-toggle/index.js +4 -0
  20. package/dist/forms/button-toggle/theme.d.ts +347 -0
  21. package/dist/forms/button-toggle/theme.js +129 -0
  22. package/dist/forms/checkbox/Checkbox.svelte +82 -82
  23. package/dist/forms/checkbox/CheckboxButton.svelte +92 -92
  24. package/dist/forms/datepicker/Datepicker.svelte +707 -707
  25. package/dist/forms/form/Form.svelte +69 -69
  26. package/dist/forms/input/Input.svelte +363 -363
  27. package/dist/forms/label/Label.svelte +38 -38
  28. package/dist/forms/radio/Radio.svelte +48 -48
  29. package/dist/forms/radio/RadioButton.svelte +22 -22
  30. package/dist/forms/select/Select.svelte +56 -56
  31. package/dist/forms/textarea/Textarea.svelte +165 -165
  32. package/dist/forms/toggle/Toggle.svelte +70 -0
  33. package/dist/forms/toggle/Toggle.svelte.d.ts +3 -0
  34. package/dist/forms/toggle/index.d.ts +2 -0
  35. package/dist/forms/toggle/index.js +2 -0
  36. package/dist/forms/toggle/theme.d.ts +280 -0
  37. package/dist/forms/toggle/theme.js +97 -0
  38. package/dist/index.d.ts +3 -0
  39. package/dist/index.js +3 -0
  40. package/dist/layout/Chat/CategorySelector.svelte +52 -52
  41. package/dist/layout/Chat/ChatEntry.svelte +246 -246
  42. package/dist/layout/Chat/ChatEntrySkeleton.svelte +81 -81
  43. package/dist/layout/Chat/ChatHeader.svelte +172 -172
  44. package/dist/layout/Chat/ChatInput.svelte +207 -207
  45. package/dist/layout/Chat/DraggableWindow.svelte +230 -230
  46. package/dist/layout/Chat/PreviewPage.svelte +182 -182
  47. package/dist/layout/Chat/RichText.svelte +216 -216
  48. package/dist/layout/ComponentCanvas/Canvas.svelte +40 -40
  49. package/dist/layout/ComponentCanvas/ComponentRenderer.svelte +85 -85
  50. package/dist/layout/TF/Content/Content.svelte +21 -21
  51. package/dist/layout/TF/Header/Header.svelte +166 -166
  52. package/dist/layout/TF/Sidebar/Sidebar.svelte +148 -148
  53. package/dist/layout/TF/Wrapper/Wrapper.svelte +17 -17
  54. package/dist/layout/mailing/MailPaginator.svelte +36 -36
  55. package/dist/layout/mailing/MailSidebar.svelte +39 -39
  56. package/dist/layout/mailing/MailToolBar.svelte +174 -174
  57. package/dist/layout/mailing/MailingContent.svelte +10 -10
  58. package/dist/layout/mailing/MailingHeader.svelte +55 -55
  59. package/dist/layout/mailing/MailingMessageCard.svelte +112 -112
  60. package/dist/layout/mailing/MailingMessageViewer.svelte +87 -87
  61. package/dist/layout/mailing/MailingModule.svelte +448 -448
  62. package/dist/styles/docs.css +615 -615
  63. package/dist/styles/tf-layout.css +185 -185
  64. package/dist/themes/ThemeProvider.svelte +20 -20
  65. package/dist/themes/themes.d.ts +3 -0
  66. package/dist/themes/themes.js +3 -0
  67. package/dist/types/index.d.ts +57 -1
  68. package/dist/typography/heading/Heading.svelte +35 -35
  69. package/dist/ui/accordion/Accordion.svelte +49 -49
  70. package/dist/ui/accordion/AccordionItem.svelte +173 -173
  71. package/dist/ui/alert/Alert.svelte +83 -83
  72. package/dist/ui/alertDialog/AlertDialog.svelte +40 -40
  73. package/dist/ui/avatar/Avatar.svelte +77 -77
  74. package/dist/ui/box/Box.svelte +28 -28
  75. package/dist/ui/breadcrumb/Breadcrumb.svelte +39 -39
  76. package/dist/ui/buttons/ActionButton.svelte +234 -234
  77. package/dist/ui/buttons/Button.svelte +102 -102
  78. package/dist/ui/buttons/GradientButton.svelte +59 -59
  79. package/dist/ui/datatable/Datatable.svelte +525 -525
  80. package/dist/ui/drawer/Drawer.svelte +300 -300
  81. package/dist/ui/dropdown/Dropdown.svelte +36 -36
  82. package/dist/ui/dropdown/DropdownDivider.svelte +11 -11
  83. package/dist/ui/dropdown/DropdownGroup.svelte +14 -14
  84. package/dist/ui/dropdown/DropdownHeader.svelte +14 -14
  85. package/dist/ui/dropdown/DropdownItem.svelte +52 -52
  86. package/dist/ui/footer/Footer.svelte +15 -15
  87. package/dist/ui/footer/FooterBrand.svelte +37 -37
  88. package/dist/ui/footer/FooterCopyright.svelte +45 -45
  89. package/dist/ui/footer/FooterIcon.svelte +22 -22
  90. package/dist/ui/footer/FooterLink.svelte +33 -33
  91. package/dist/ui/footer/FooterLinkGroup.svelte +13 -13
  92. package/dist/ui/icons/IconifyIcon.svelte +7 -7
  93. package/dist/ui/indicator/Indicator.svelte +42 -42
  94. package/dist/ui/modal/Modal.svelte +265 -265
  95. package/dist/ui/modal/theme.d.ts +26 -26
  96. package/dist/ui/modal/theme.js +25 -25
  97. package/dist/ui/notificationList/NotificationList.svelte +123 -123
  98. package/dist/ui/pageLoader/PageLoader.svelte +14 -14
  99. package/dist/ui/paginate/Paginate.svelte +96 -96
  100. package/dist/ui/speedDial/SpeedDial.svelte +77 -0
  101. package/dist/ui/speedDial/SpeedDial.svelte.d.ts +21 -0
  102. package/dist/ui/speedDial/SpeedDialButton.svelte +75 -0
  103. package/dist/ui/speedDial/SpeedDialButton.svelte.d.ts +20 -0
  104. package/dist/ui/speedDial/SpeedDialTrigger.svelte +79 -0
  105. package/dist/ui/speedDial/SpeedDialTrigger.svelte.d.ts +18 -0
  106. package/dist/ui/speedDial/index.d.ts +4 -0
  107. package/dist/ui/speedDial/index.js +4 -0
  108. package/dist/ui/speedDial/theme.d.ts +75 -0
  109. package/dist/ui/speedDial/theme.js +35 -0
  110. package/dist/ui/tab/Tab.svelte +67 -67
  111. package/dist/ui/table/Table.svelte +396 -396
  112. package/dist/ui/tableLoader/TableLoader.svelte +24 -24
  113. package/dist/ui/toast/Toast.svelte +337 -337
  114. package/dist/ui/toast/Toast.svelte.d.ts +10 -10
  115. package/dist/ui/toast/index.d.ts +1 -2
  116. package/dist/ui/toast/index.js +3 -1
  117. package/dist/ui/toolbar/Toolbar.svelte +59 -59
  118. package/dist/ui/toolbar/ToolbarButton.svelte +56 -56
  119. package/dist/ui/toolbar/ToolbarGroup.svelte +43 -43
  120. package/dist/ui/tooltip/Tooltip.svelte +51 -51
  121. package/dist/utils/Popper.svelte +257 -257
  122. package/dist/utils/closeButton/CloseButton.svelte +88 -88
  123. package/dist/utils/index.d.ts +3 -2
  124. package/dist/utils/index.js +13 -3
  125. package/dist/utils/singleSelection.svelte.js +48 -48
  126. package/dist/youtube/index.svelte +12 -12
  127. package/package.json +2 -1
@@ -1,53 +1,53 @@
1
- <script lang="ts">
2
- import { Checkbox, key, Label } from '../../index.js';
3
- import type { FormCheckboxProps, FormSelectProps } from '../../types/index.js';
4
- import { getContext } from 'svelte';
5
-
6
- let {
7
- label = '',
8
- required,
9
- name,
10
- disabled,
11
- contextKey = null,
12
- placeholder,
13
- multiple = false,
14
- onChange,
15
- ...otherProps
16
- }: FormCheckboxProps = $props();
17
- const { touched, errors, data, setData }: any = getContext(contextKey || key);
18
-
19
- const hasError = $derived($touched[name] && $errors[name]?.length);
20
- const error = $derived($errors[name]?.join(', '));
21
- const value = $derived($data[name]);
22
-
23
- function handleChange(e: Event) {
24
- const value = (e.target as HTMLInputElement).checked;
25
- setData({ ...$data, [name]: value });
26
- if (onChange) onChange(e);
27
- }
28
- </script>
29
-
30
- <div class="relative space-y-1">
31
- <Checkbox {disabled} onchange={handleChange} {...otherProps} checked={value}
32
- >{label}
33
- {#if required}
34
- <span class="pt-1 pl-1 text-red-500">*</span>
35
- {/if}
36
- </Checkbox>
37
-
38
- {#if hasError}
39
- <Label
40
- class="v-error-container absolute top-8 right-2 flex items-center gap-1 text-sm {hasError &&
41
- 'text-red-600'}"
42
- >
43
- <span class="v-error-message hidden backdrop-blur-sm">
44
- {error}
45
- </span>
46
- <iconify-icon
47
- icon="solar:danger-circle-bold-duotone"
48
- class="v-error-svg ml-auto cursor-pointer text-red-500 select-none hover:text-red-600"
49
- style="font-size: 18px;"
50
- ></iconify-icon>
51
- </Label>
52
- {/if}
53
- </div>
1
+ <script lang="ts">
2
+ import { Checkbox, key, Label } from '../../index.js';
3
+ import type { FormCheckboxProps, FormSelectProps } from '../../types/index.js';
4
+ import { getContext } from 'svelte';
5
+
6
+ let {
7
+ label = '',
8
+ required,
9
+ name,
10
+ disabled,
11
+ contextKey = null,
12
+ placeholder,
13
+ multiple = false,
14
+ onChange,
15
+ ...otherProps
16
+ }: FormCheckboxProps = $props();
17
+ const { touched, errors, data, setData }: any = getContext(contextKey || key);
18
+
19
+ const hasError = $derived($touched[name] && $errors[name]?.length);
20
+ const error = $derived($errors[name]?.join(', '));
21
+ const value = $derived($data[name]);
22
+
23
+ function handleChange(e: Event) {
24
+ const value = (e.target as HTMLInputElement).checked;
25
+ setData({ ...$data, [name]: value });
26
+ if (onChange) onChange(e);
27
+ }
28
+ </script>
29
+
30
+ <div class="relative space-y-1">
31
+ <Checkbox {disabled} onchange={handleChange} {...otherProps} checked={value}
32
+ >{label}
33
+ {#if required}
34
+ <span class="pt-1 pl-1 text-red-500">*</span>
35
+ {/if}
36
+ </Checkbox>
37
+
38
+ {#if hasError}
39
+ <Label
40
+ class="v-error-container absolute top-8 right-2 flex items-center gap-1 text-sm {hasError &&
41
+ 'text-red-600'}"
42
+ >
43
+ <span class="v-error-message hidden backdrop-blur-sm">
44
+ {error}
45
+ </span>
46
+ <iconify-icon
47
+ icon="solar:danger-circle-bold-duotone"
48
+ class="v-error-svg ml-auto cursor-pointer text-red-500 select-none hover:text-red-600"
49
+ style="font-size: 18px;"
50
+ ></iconify-icon>
51
+ </Label>
52
+ {/if}
53
+ </div>
@@ -1,68 +1,68 @@
1
- <script lang="ts">
2
- import { IconifyIcon, key, Label } from '../../index.js';
3
- import type { FormClEditorProps } from '../../types/index.js';
4
- import Editor from 'cl-editor/src/Editor.svelte';
5
- import { nanoid } from 'nanoid';
6
- import { getContext, onMount } from 'svelte';
7
-
8
- let {
9
- name = '',
10
- label = '',
11
- required,
12
- readonly,
13
- contextKey = null,
14
- type = 'text',
15
- pattern = null,
16
- placeholder,
17
- value,
18
- height,
19
- ...otherProps
20
- }: FormClEditorProps = $props();
21
- const { touched, errors, data, setData }: any = getContext(contextKey || key);
22
- const hasError = $derived($touched[name] && $errors[name]?.length);
23
- const error = $derived($errors[name]?.join(', '));
24
- const isSuccess = $derived(!readonly && !hasError && $touched[name]);
25
- let editorValue = $derived($data[name] || value || '');
26
- let id = nanoid();
27
-
28
- function onChange({ detail: e }: CustomEvent) {
29
- setData({ ...$data, [name]: e });
30
- }
31
-
32
- function onBlur({ detail: e }: CustomEvent) {
33
- console.log({ e });
34
- // setData({ ...$data, [name]: e });
35
- }
36
- // $effect(() => {
37
- // if (value !== undefined && value !== $data[name]) {
38
- // setData({ ...$data, [name]: value });
39
- // }
40
- // });
41
- </script>
42
-
43
- <div class="relative space-y-1">
44
- <Label
45
- >{label}
46
- {#if required}
47
- <span class="pl-1 text-red-500">*</span>
48
- {/if}
49
- </Label>
50
-
51
- <Editor contentId={id} on:change={onChange} bind:html={editorValue} {height} />
52
-
53
- {#if hasError}
54
- <Label
55
- class="v-error-container absolute top-9 right-2 flex items-center gap-1 text-sm {hasError &&
56
- 'text-red-600'}"
57
- >
58
- <span class="v-error-message hidden backdrop-blur-sm">
59
- {error}
60
- </span>
61
- <IconifyIcon
62
- icon="solar:danger-circle-bold-duotone"
63
- class="v-error-svg ml-auto cursor-pointer text-red-500 select-none hover:text-red-600"
64
- style="font-size: 18px;"
65
- />
66
- </Label>
67
- {/if}
68
- </div>
1
+ <script lang="ts">
2
+ import { IconifyIcon, key, Label } from '../../index.js';
3
+ import type { FormClEditorProps } from '../../types/index.js';
4
+ import Editor from 'cl-editor/src/Editor.svelte';
5
+ import { nanoid } from 'nanoid';
6
+ import { getContext, onMount } from 'svelte';
7
+
8
+ let {
9
+ name = '',
10
+ label = '',
11
+ required,
12
+ readonly,
13
+ contextKey = null,
14
+ type = 'text',
15
+ pattern = null,
16
+ placeholder,
17
+ value,
18
+ height,
19
+ ...otherProps
20
+ }: FormClEditorProps = $props();
21
+ const { touched, errors, data, setData }: any = getContext(contextKey || key);
22
+ const hasError = $derived($touched[name] && $errors[name]?.length);
23
+ const error = $derived($errors[name]?.join(', '));
24
+ const isSuccess = $derived(!readonly && !hasError && $touched[name]);
25
+ let editorValue = $derived($data[name] || value || '');
26
+ let id = nanoid();
27
+
28
+ function onChange({ detail: e }: CustomEvent) {
29
+ setData({ ...$data, [name]: e });
30
+ }
31
+
32
+ function onBlur({ detail: e }: CustomEvent) {
33
+ console.log({ e });
34
+ // setData({ ...$data, [name]: e });
35
+ }
36
+ // $effect(() => {
37
+ // if (value !== undefined && value !== $data[name]) {
38
+ // setData({ ...$data, [name]: value });
39
+ // }
40
+ // });
41
+ </script>
42
+
43
+ <div class="relative space-y-1">
44
+ <Label
45
+ >{label}
46
+ {#if required}
47
+ <span class="pl-1 text-red-500">*</span>
48
+ {/if}
49
+ </Label>
50
+
51
+ <Editor contentId={id} on:change={onChange} bind:html={editorValue} {height} />
52
+
53
+ {#if hasError}
54
+ <Label
55
+ class="v-error-container absolute top-9 right-2 flex items-center gap-1 text-sm {hasError &&
56
+ 'text-red-600'}"
57
+ >
58
+ <span class="v-error-message hidden backdrop-blur-sm">
59
+ {error}
60
+ </span>
61
+ <IconifyIcon
62
+ icon="solar:danger-circle-bold-duotone"
63
+ class="v-error-svg ml-auto cursor-pointer text-red-500 select-none hover:text-red-600"
64
+ style="font-size: 18px;"
65
+ />
66
+ </Label>
67
+ {/if}
68
+ </div>
@@ -1,159 +1,159 @@
1
- <script lang="ts" module>
2
- /**
3
- * Converts a string to a Date object, handling multiple common formats
4
- * @param dateString - The string to convert to a date
5
- * @returns Date object or null if parsing fails
6
- */
7
- export function stringToDate(dateString: string): Date | undefined {
8
- if (!dateString) return undefined;
9
-
10
- // Try ISO format first (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss)
11
- let date = new Date(dateString);
12
- if (!isNaN(date.getTime())) return date;
13
-
14
- // Try common formats with different separators
15
- const formats = [
16
- // DD/MM/YYYY or MM/DD/YYYY
17
- /(\d{1,2})[\/\-\.](\d{1,2})[\/\-\.](\d{4})/,
18
- // YYYY/MM/DD
19
- /(\d{4})[\/\-\.](\d{1,2})[\/\-\.](\d{1,2})/,
20
- // Month name formats (MMM DD, YYYY)
21
- /([A-Za-z]+)\s(\d{1,2}),?\s(\d{4})/,
22
- // Unix timestamp (as string)
23
- /^\d{10,13}$/
24
- ];
25
-
26
- for (const regex of formats) {
27
- const match = dateString.match(regex);
28
- if (!match) continue;
29
-
30
- if (regex === formats[3]) {
31
- // Unix timestamp
32
- const timestamp = parseInt(dateString);
33
- return new Date(timestamp * (dateString.length === 10 ? 1000 : 1));
34
- }
35
-
36
- let day, month, year;
37
- if (regex === formats[0]) {
38
- // DD/MM/YYYY or MM/DD/YYYY
39
- const first = parseInt(match[1]);
40
- const second = parseInt(match[2]);
41
-
42
- // Determine if format is DD/MM or MM/DD
43
- if (first > 12) {
44
- day = first;
45
- month = second - 1;
46
- } else if (second > 12) {
47
- day = second;
48
- month = first - 1;
49
- } else {
50
- // Ambiguous case, default to DD/MM
51
- day = second;
52
- month = first - 1;
53
- }
54
- year = parseInt(match[3]);
55
- } else if (regex === formats[1]) {
56
- // YYYY/MM/DD
57
- year = parseInt(match[1]);
58
- month = parseInt(match[2]) - 1;
59
- day = parseInt(match[3]);
60
- } else if (regex === formats[2]) {
61
- // Month name
62
- month = new Date(`${match[1]} 1, 2000`).getMonth();
63
- day = parseInt(match[2]);
64
- year = parseInt(match[3]);
65
- }
66
-
67
- date = new Date(year, month, day);
68
- if (!isNaN(date.getTime())) return date;
69
- }
70
-
71
- // Try the Date constructor one more time in case of locale-specific formats
72
- date = new Date(dateString);
73
- return isNaN(date.getTime()) ? undefined : date;
74
- }
75
- </script>
76
-
77
- <script lang="ts">
78
- import { key, type DateOrRange, type FormDatepickerProps } from '../../index.js';
79
- import { getContext } from 'svelte';
80
- import Label from '../label/Label.svelte';
81
- import Datepicker from '../datepicker/Datepicker.svelte';
82
-
83
- let {
84
- label = '',
85
- required,
86
- name,
87
- disabled,
88
- contextKey = null,
89
- placeholder,
90
- range,
91
- locale,
92
- dateFormat,
93
- onchange,
94
- ...otherProps
95
- // onchange,
96
- }: FormDatepickerProps & { onchange?: (value: DateOrRange) => void } = $props();
97
- const { touched, errors, data, setData }: any = getContext(contextKey || key);
98
-
99
- const hasError = $derived($touched[name] && $errors[name]?.length);
100
- const error = $derived($errors[name]?.join(', '));
101
- const formatDate = (date?: Date): string => date?.toLocaleDateString(locale, dateFormat) ?? '';
102
- const value = $derived($data[name] ? stringToDate($data[name]) : undefined);
103
- const rangeDate = $derived(getRange());
104
-
105
- function getRange() {
106
- if (!range) return { from: undefined, to: undefined };
107
- const splits = $data[name].split(' - ');
108
- return {
109
- from: stringToDate(splits[0]),
110
- to: stringToDate(splits[1])
111
- };
112
- }
113
-
114
- function handleChange(e: DateOrRange) {
115
- if (!range) {
116
- setData({ ...$data, [name]: formatDate(e as Date) });
117
- } else if (typeof e === 'object' && 'from' in e && 'to' in e) {
118
- const d = `${formatDate(e.from)} - ${formatDate(e.to)}`;
119
- setData({ ...$data, [name]: d });
120
- }
121
- if (onchange) onchange(e);
122
- }
123
- </script>
124
-
125
- <div class="relative space-y-1">
126
- <Label
127
- >{label}
128
- {#if required}
129
- <span class="pl-1 text-red-500">*</span>
130
- {/if}
131
- </Label>
132
-
133
- <Datepicker
134
- {disabled}
135
- {range}
136
- {value}
137
- onselect={handleChange}
138
- rangeFrom={rangeDate.from}
139
- rangeTo={rangeDate.to}
140
- {name}
141
- {...otherProps}
142
- />
143
-
144
- {#if hasError}
145
- <Label
146
- class="v-error-container absolute top-8 right-2 flex items-center gap-1 text-sm {hasError &&
147
- 'text-red-600'}"
148
- >
149
- <span class="v-error-message hidden backdrop-blur-sm">
150
- {error}
151
- </span>
152
- <iconify-icon
153
- icon="solar:danger-circle-bold-duotone"
154
- class="v-error-svg ml-auto cursor-pointer text-red-500 select-none hover:text-red-600"
155
- style="font-size: 18px;"
156
- ></iconify-icon>
157
- </Label>
158
- {/if}
159
- </div>
1
+ <script lang="ts" module>
2
+ /**
3
+ * Converts a string to a Date object, handling multiple common formats
4
+ * @param dateString - The string to convert to a date
5
+ * @returns Date object or null if parsing fails
6
+ */
7
+ export function stringToDate(dateString: string): Date | undefined {
8
+ if (!dateString) return undefined;
9
+
10
+ // Try ISO format first (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss)
11
+ let date = new Date(dateString);
12
+ if (!isNaN(date.getTime())) return date;
13
+
14
+ // Try common formats with different separators
15
+ const formats = [
16
+ // DD/MM/YYYY or MM/DD/YYYY
17
+ /(\d{1,2})[\/\-\.](\d{1,2})[\/\-\.](\d{4})/,
18
+ // YYYY/MM/DD
19
+ /(\d{4})[\/\-\.](\d{1,2})[\/\-\.](\d{1,2})/,
20
+ // Month name formats (MMM DD, YYYY)
21
+ /([A-Za-z]+)\s(\d{1,2}),?\s(\d{4})/,
22
+ // Unix timestamp (as string)
23
+ /^\d{10,13}$/
24
+ ];
25
+
26
+ for (const regex of formats) {
27
+ const match = dateString.match(regex);
28
+ if (!match) continue;
29
+
30
+ if (regex === formats[3]) {
31
+ // Unix timestamp
32
+ const timestamp = parseInt(dateString);
33
+ return new Date(timestamp * (dateString.length === 10 ? 1000 : 1));
34
+ }
35
+
36
+ let day, month, year;
37
+ if (regex === formats[0]) {
38
+ // DD/MM/YYYY or MM/DD/YYYY
39
+ const first = parseInt(match[1]);
40
+ const second = parseInt(match[2]);
41
+
42
+ // Determine if format is DD/MM or MM/DD
43
+ if (first > 12) {
44
+ day = first;
45
+ month = second - 1;
46
+ } else if (second > 12) {
47
+ day = second;
48
+ month = first - 1;
49
+ } else {
50
+ // Ambiguous case, default to DD/MM
51
+ day = second;
52
+ month = first - 1;
53
+ }
54
+ year = parseInt(match[3]);
55
+ } else if (regex === formats[1]) {
56
+ // YYYY/MM/DD
57
+ year = parseInt(match[1]);
58
+ month = parseInt(match[2]) - 1;
59
+ day = parseInt(match[3]);
60
+ } else if (regex === formats[2]) {
61
+ // Month name
62
+ month = new Date(`${match[1]} 1, 2000`).getMonth();
63
+ day = parseInt(match[2]);
64
+ year = parseInt(match[3]);
65
+ }
66
+
67
+ date = new Date(year, month, day);
68
+ if (!isNaN(date.getTime())) return date;
69
+ }
70
+
71
+ // Try the Date constructor one more time in case of locale-specific formats
72
+ date = new Date(dateString);
73
+ return isNaN(date.getTime()) ? undefined : date;
74
+ }
75
+ </script>
76
+
77
+ <script lang="ts">
78
+ import { key, type DateOrRange, type FormDatepickerProps } from '../../index.js';
79
+ import { getContext } from 'svelte';
80
+ import Label from '../label/Label.svelte';
81
+ import Datepicker from '../datepicker/Datepicker.svelte';
82
+
83
+ let {
84
+ label = '',
85
+ required,
86
+ name,
87
+ disabled,
88
+ contextKey = null,
89
+ placeholder,
90
+ range,
91
+ locale,
92
+ dateFormat,
93
+ onchange,
94
+ ...otherProps
95
+ // onchange,
96
+ }: FormDatepickerProps & { onchange?: (value: DateOrRange) => void } = $props();
97
+ const { touched, errors, data, setData }: any = getContext(contextKey || key);
98
+
99
+ const hasError = $derived($touched[name] && $errors[name]?.length);
100
+ const error = $derived($errors[name]?.join(', '));
101
+ const formatDate = (date?: Date): string => date?.toLocaleDateString(locale, dateFormat) ?? '';
102
+ const value = $derived($data[name] ? stringToDate($data[name]) : undefined);
103
+ const rangeDate = $derived(getRange());
104
+
105
+ function getRange() {
106
+ if (!range) return { from: undefined, to: undefined };
107
+ const splits = $data[name].split(' - ');
108
+ return {
109
+ from: stringToDate(splits[0]),
110
+ to: stringToDate(splits[1])
111
+ };
112
+ }
113
+
114
+ function handleChange(e: DateOrRange) {
115
+ if (!range) {
116
+ setData({ ...$data, [name]: formatDate(e as Date) });
117
+ } else if (typeof e === 'object' && 'from' in e && 'to' in e) {
118
+ const d = `${formatDate(e.from)} - ${formatDate(e.to)}`;
119
+ setData({ ...$data, [name]: d });
120
+ }
121
+ if (onchange) onchange(e);
122
+ }
123
+ </script>
124
+
125
+ <div class="relative space-y-1">
126
+ <Label
127
+ >{label}
128
+ {#if required}
129
+ <span class="pl-1 text-red-500">*</span>
130
+ {/if}
131
+ </Label>
132
+
133
+ <Datepicker
134
+ {disabled}
135
+ {range}
136
+ {value}
137
+ onselect={handleChange}
138
+ rangeFrom={rangeDate.from}
139
+ rangeTo={rangeDate.to}
140
+ {name}
141
+ {...otherProps}
142
+ />
143
+
144
+ {#if hasError}
145
+ <Label
146
+ class="v-error-container absolute top-8 right-2 flex items-center gap-1 text-sm {hasError &&
147
+ 'text-red-600'}"
148
+ >
149
+ <span class="v-error-message hidden backdrop-blur-sm">
150
+ {error}
151
+ </span>
152
+ <iconify-icon
153
+ icon="solar:danger-circle-bold-duotone"
154
+ class="v-error-svg ml-auto cursor-pointer text-red-500 select-none hover:text-red-600"
155
+ style="font-size: 18px;"
156
+ ></iconify-icon>
157
+ </Label>
158
+ {/if}
159
+ </div>