@warkypublic/svelix 0.1.46 → 0.2.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 (129) hide show
  1. package/README.md +93 -33
  2. package/dist/components/BetterMenu/BetterMenu.svelte +21 -37
  3. package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte +21 -31
  4. package/dist/components/BetterMenu/BetterMenuPreview.svelte +27 -29
  5. package/dist/components/BetterMenu/MenuRenderer.svelte +40 -51
  6. package/dist/components/Boxer/Boxer.svelte +492 -602
  7. package/dist/components/Boxer/BoxerTarget.svelte +6 -46
  8. package/dist/components/Boxer/BoxerTarget.svelte.d.ts +1 -0
  9. package/dist/components/Boxer/types.d.ts +0 -1
  10. package/dist/components/Button.svelte +19 -43
  11. package/dist/components/ButtonPreview.svelte +2 -11
  12. package/dist/components/CardGrid/CardGrid.svelte +489 -614
  13. package/dist/components/CardGrid/CardGrid.svelte.d.ts +4 -0
  14. package/dist/components/CardGrid/CardGridFilterPanel.svelte +111 -90
  15. package/dist/components/CardGrid/DefaultCard.svelte +86 -97
  16. package/dist/components/CardGrid/DefaultCard.svelte.d.ts +1 -0
  17. package/dist/components/CardGrid/ImageCardStory.svelte +87 -36
  18. package/dist/components/CardGrid/cardGrid.d.ts +24 -0
  19. package/dist/components/CardGrid/cardGrid.js +20 -0
  20. package/dist/components/ContentEditor/CollaboraInsertTextDemo.svelte +5 -10
  21. package/dist/components/ContentEditor/ContentEditor.svelte +24 -50
  22. package/dist/components/ContentEditor/subcomponents/AudioPlayer.svelte +17 -17
  23. package/dist/components/ContentEditor/subcomponents/CollaboraEditor.svelte +244 -309
  24. package/dist/components/ContentEditor/subcomponents/EmailViewer.svelte +2 -3
  25. package/dist/components/ContentEditor/subcomponents/ImageViewer.svelte +14 -15
  26. package/dist/components/ContentEditor/subcomponents/MarkdownViewer.svelte +74 -90
  27. package/dist/components/ContentEditor/subcomponents/MonacoEditor.svelte +75 -103
  28. package/dist/components/ContentEditor/subcomponents/Office365Editor.svelte +234 -297
  29. package/dist/components/ContentEditor/subcomponents/PdfViewer.svelte +14 -20
  30. package/dist/components/ContentEditor/subcomponents/TextEditor.svelte +122 -150
  31. package/dist/components/ContentEditor/subcomponents/UnknownFile.svelte +105 -126
  32. package/dist/components/ContentEditor/subcomponents/VideoPlayer.svelte +17 -17
  33. package/dist/components/ContentEditor/subcomponents/ZipViewer.svelte +2 -3
  34. package/dist/components/ErrorBoundary/ErrorBoundary.svelte +41 -58
  35. package/dist/components/ErrorBoundary/ErrorBoundaryPreview.svelte +8 -16
  36. package/dist/components/Former/Former.svelte +306 -424
  37. package/dist/components/Former/FormerButtonArea.svelte +17 -68
  38. package/dist/components/Former/FormerDrawer.svelte +16 -80
  39. package/dist/components/Former/FormerDrawerPreview.svelte +99 -89
  40. package/dist/components/Former/FormerModal.svelte +16 -74
  41. package/dist/components/Former/FormerModalPreview.svelte +99 -89
  42. package/dist/components/Former/FormerPreview.svelte +76 -78
  43. package/dist/components/Former/FormerRestApiPreview.svelte +55 -48
  44. package/dist/components/Former/formerOverlayHelpers.svelte.d.ts +11 -0
  45. package/dist/components/Former/formerOverlayHelpers.svelte.js +38 -0
  46. package/dist/components/Former/index.d.ts +1 -0
  47. package/dist/components/Former/index.js +1 -0
  48. package/dist/components/FormerControllers/ButtonCtrl.svelte +13 -49
  49. package/dist/components/FormerControllers/CtrlFieldShell.svelte +15 -0
  50. package/dist/components/FormerControllers/CtrlFieldShell.svelte.d.ts +12 -0
  51. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.svelte +285 -457
  52. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlCalendar.svelte +95 -136
  53. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlPickerPanel.svelte +3 -62
  54. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlTimeFields.svelte +143 -217
  55. package/dist/components/FormerControllers/IconButtonCtrl.svelte +13 -47
  56. package/dist/components/FormerControllers/InlineWrapper.svelte +12 -41
  57. package/dist/components/FormerControllers/InlineWrapperPreview.svelte +4 -26
  58. package/dist/components/FormerControllers/NativeSelectCtrl.svelte +7 -39
  59. package/dist/components/FormerControllers/NumberInputCtrl.svelte +21 -43
  60. package/dist/components/FormerControllers/PasswordInputCtrl.svelte +8 -33
  61. package/dist/components/FormerControllers/SwitchCtrl.svelte +4 -20
  62. package/dist/components/FormerControllers/TextAreaCtrl.svelte +7 -34
  63. package/dist/components/FormerControllers/TextInputCtrl.svelte +7 -34
  64. package/dist/components/FormerControllers/ctrlLoading.svelte.d.ts +8 -0
  65. package/dist/components/FormerControllers/ctrlLoading.svelte.js +43 -0
  66. package/dist/components/FormerControllers/index.d.ts +2 -0
  67. package/dist/components/FormerControllers/index.js +2 -0
  68. package/dist/components/FormerControllers/utils.d.ts +1 -0
  69. package/dist/components/FormerControllers/utils.js +3 -0
  70. package/dist/components/GlobalStateStore/GlobalStateStoreProvider.svelte +73 -120
  71. package/dist/components/Gridler/components/Gridler.svelte +344 -442
  72. package/dist/components/Gridler/components/GridlerCanvas.svelte +720 -1115
  73. package/dist/components/Gridler/components/GridlerEditor.svelte +2 -15
  74. package/dist/components/Gridler/components/GridlerFull.svelte +521 -841
  75. package/dist/components/Gridler/components/GridlerFull.svelte.d.ts +1 -1
  76. package/dist/components/Gridler/components/GridlerFullWithFormerPreview.svelte +194 -147
  77. package/dist/components/Gridler/components/GridlerSearch.svelte +7 -16
  78. package/dist/components/Gridler/components/GridlerSearchToggle.svelte +7 -19
  79. package/dist/components/Gridler/types.d.ts +1 -1
  80. package/dist/components/Gridler/utils/serverPaging.d.ts +1 -0
  81. package/dist/components/Gridler/utils/serverPaging.js +7 -0
  82. package/dist/components/Icons/IconAdd.svelte +1 -3
  83. package/dist/components/Icons/IconAlertCircle.svelte +1 -3
  84. package/dist/components/Icons/IconAlertTriangle.svelte +1 -3
  85. package/dist/components/Icons/IconCamera.svelte +1 -3
  86. package/dist/components/Icons/IconClose.svelte +1 -3
  87. package/dist/components/Icons/IconEdit.svelte +1 -3
  88. package/dist/components/Icons/IconFilter.svelte +1 -3
  89. package/dist/components/Icons/IconSearch.svelte +1 -3
  90. package/dist/components/Icons/IconSort.svelte +1 -3
  91. package/dist/components/Icons/IconTrash.svelte +1 -3
  92. package/dist/components/Portal/Portal.svelte +14 -38
  93. package/dist/components/Screenshot/Screenshot.svelte +7 -13
  94. package/dist/components/Svark/Svark.svelte +680 -852
  95. package/dist/components/Svark/SvarkContextMenu.svelte +44 -63
  96. package/dist/components/Svark/SvarkInfiniteLoader.svelte +2 -6
  97. package/dist/components/Svark/SvarkPager.svelte +2 -28
  98. package/dist/components/Svark/SvarkSelectionDemo.svelte +4 -8
  99. package/dist/components/Svark/SvarkTopBar.svelte +9 -74
  100. package/dist/components/SvarkGrid/SvarkGrid.svelte +877 -1123
  101. package/dist/components/SvarkGrid/components/SvarkColumnFilterForm.svelte +45 -58
  102. package/dist/components/SvarkGrid/components/SvarkContextMenu.svelte +44 -63
  103. package/dist/components/SvarkGrid/components/SvarkHeaderFilterCell.svelte +41 -75
  104. package/dist/components/SvarkGrid/components/SvarkInfiniteLoader.svelte +2 -6
  105. package/dist/components/SvarkGrid/components/SvarkPager.svelte +2 -28
  106. package/dist/components/SvarkGrid/components/SvarkSearchPopover.svelte +8 -16
  107. package/dist/components/SvarkGrid/components/SvarkTopBar.svelte +6 -62
  108. package/dist/components/SvarkGrid/internal/SvarkGridView.svelte +345 -507
  109. package/dist/components/VTree/VTree.svelte +454 -431
  110. package/dist/components/VTree/VTree.utils.d.ts +23 -0
  111. package/dist/components/VTree/VTree.utils.js +73 -0
  112. package/dist/components/VTree/VTreeContextMenu.svelte +21 -33
  113. package/dist/components/VTree/VTreeControlledSelectionDemo.svelte +20 -0
  114. package/dist/components/VTree/VTreeControlledSelectionDemo.svelte.d.ts +18 -0
  115. package/dist/components/VTree/VTreeCustomizationDemo.svelte +23 -0
  116. package/dist/components/VTree/VTreeCustomizationDemo.svelte.d.ts +18 -0
  117. package/dist/components/VTree/VTreeEventsDemo.svelte +48 -58
  118. package/dist/components/VTree/VTreeInteractionDemo.svelte +29 -0
  119. package/dist/components/VTree/VTreeInteractionDemo.svelte.d.ts +18 -0
  120. package/dist/components/VTree/VTreeMultiSelectDemo.svelte +27 -0
  121. package/dist/components/VTree/VTreeMultiSelectDemo.svelte.d.ts +18 -0
  122. package/dist/components/VTree/VTreeRow.svelte +77 -115
  123. package/dist/components/VTree/VTreeRow.svelte.d.ts +34 -18
  124. package/dist/components/VTree/VTreeSearch.svelte +6 -13
  125. package/dist/components/VTree/VTreeVirtualViewport.svelte +54 -143
  126. package/dist/components/VTree/VTreeVirtualViewport.svelte.d.ts +35 -18
  127. package/dist/components/VTree/types.d.ts +39 -1
  128. package/llm/COMPONENT_GUIDE.md +25 -0
  129. package/package.json +51 -50
@@ -1,139 +1,98 @@
1
- <script lang="ts">
2
- import { WEEKDAY_LABELS, type CalendarCell } from './DateTimeCtrl.utils';
3
-
4
- export interface Props {
5
- cells: CalendarCell[];
6
- isDateSelectable?: (isoDate: string) => boolean;
7
- monthLabel: string;
8
- onNext?: () => void;
9
- onPrev?: () => void;
10
- onSelect?: (isoDate: string) => void;
11
- selectedIso?: string;
12
- }
13
-
14
- let {
15
- cells,
16
- isDateSelectable,
17
- monthLabel,
18
- onNext,
19
- onPrev,
20
- onSelect,
21
- selectedIso,
22
- }: Props = $props();
23
-
24
- function isCellDisabled(cell: CalendarCell): boolean {
25
- if (!cell.inCurrentMonth) {
26
- return true;
27
- }
28
-
29
- if (!isDateSelectable) {
30
- return false;
31
- }
32
-
33
- return !isDateSelectable(cell.isoDate);
34
- }
35
-
36
- function focusFirstAvailable(): void {
37
- if (typeof document === 'undefined') {
38
- return;
39
- }
40
-
41
- const first = cells.find((cell) => !isCellDisabled(cell));
42
- if (!first) {
43
- return;
44
- }
45
-
46
- const target = document.querySelector<HTMLButtonElement>(`button[data-iso="${first.isoDate}"]`);
47
- target?.focus();
48
- }
49
-
50
- function focusFromIndex(startIndex: number, step: number): void {
51
- if (typeof document === 'undefined') {
52
- return;
53
- }
54
-
55
- let index = startIndex + step;
56
- while (index >= 0 && index < cells.length) {
57
- const nextCell = cells[index];
58
- if (!isCellDisabled(nextCell)) {
59
- const target = document.querySelector<HTMLButtonElement>(
60
- `button[data-iso="${nextCell.isoDate}"]`,
61
- );
62
- target?.focus();
63
- return;
64
- }
65
- index += step;
66
- }
67
- }
68
-
69
- function handleDayKeydown(event: KeyboardEvent, index: number, cell: CalendarCell): void {
70
- if (isCellDisabled(cell)) {
71
- return;
72
- }
73
-
74
- if (event.key === 'Enter' || event.key === ' ') {
75
- event.preventDefault();
76
- onSelect?.(cell.isoDate);
77
- return;
78
- }
79
-
80
- if (event.key === 'ArrowRight') {
81
- event.preventDefault();
82
- focusFromIndex(index, 1);
83
- return;
84
- }
85
-
86
- if (event.key === 'ArrowLeft') {
87
- event.preventDefault();
88
- focusFromIndex(index, -1);
89
- return;
90
- }
91
-
92
- if (event.key === 'ArrowDown') {
93
- event.preventDefault();
94
- focusFromIndex(index, 7);
95
- return;
96
- }
97
-
98
- if (event.key === 'ArrowUp') {
99
- event.preventDefault();
100
- focusFromIndex(index, -7);
101
- return;
102
- }
103
-
104
- if (event.key === 'Home') {
105
- event.preventDefault();
106
- focusFirstAvailable();
107
- return;
108
- }
109
-
110
- if (event.altKey && event.key === 'PageUp') {
111
- event.preventDefault();
112
- for (let i = 0; i < 12; i += 1) {
113
- onPrev?.();
114
- }
115
- return;
116
- }
117
-
118
- if (event.altKey && event.key === 'PageDown') {
119
- event.preventDefault();
120
- for (let i = 0; i < 12; i += 1) {
121
- onNext?.();
122
- }
123
- return;
124
- }
125
-
126
- if (event.key === 'PageUp') {
127
- event.preventDefault();
128
- onPrev?.();
129
- return;
130
- }
131
-
132
- if (event.key === 'PageDown') {
133
- event.preventDefault();
134
- onNext?.();
135
- }
136
- }
1
+ <script lang="ts">import { WEEKDAY_LABELS } from "./DateTimeCtrl.utils";
2
+ let { cells, isDateSelectable, monthLabel, onNext, onPrev, onSelect, selectedIso } = $props();
3
+ function isCellDisabled(cell) {
4
+ if (!cell.inCurrentMonth) {
5
+ return true;
6
+ }
7
+ if (!isDateSelectable) {
8
+ return false;
9
+ }
10
+ return !isDateSelectable(cell.isoDate);
11
+ }
12
+ function focusFirstAvailable() {
13
+ if (typeof document === "undefined") {
14
+ return;
15
+ }
16
+ const first = cells.find((cell) => !isCellDisabled(cell));
17
+ if (!first) {
18
+ return;
19
+ }
20
+ const target = document.querySelector(`button[data-iso="${first.isoDate}"]`);
21
+ target?.focus();
22
+ }
23
+ function focusFromIndex(startIndex, step) {
24
+ if (typeof document === "undefined") {
25
+ return;
26
+ }
27
+ let index = startIndex + step;
28
+ while (index >= 0 && index < cells.length) {
29
+ const nextCell = cells[index];
30
+ if (!isCellDisabled(nextCell)) {
31
+ const target = document.querySelector(`button[data-iso="${nextCell.isoDate}"]`);
32
+ target?.focus();
33
+ return;
34
+ }
35
+ index += step;
36
+ }
37
+ }
38
+ function handleDayKeydown(event, index, cell) {
39
+ if (isCellDisabled(cell)) {
40
+ return;
41
+ }
42
+ if (event.key === "Enter" || event.key === " ") {
43
+ event.preventDefault();
44
+ onSelect?.(cell.isoDate);
45
+ return;
46
+ }
47
+ if (event.key === "ArrowRight") {
48
+ event.preventDefault();
49
+ focusFromIndex(index, 1);
50
+ return;
51
+ }
52
+ if (event.key === "ArrowLeft") {
53
+ event.preventDefault();
54
+ focusFromIndex(index, -1);
55
+ return;
56
+ }
57
+ if (event.key === "ArrowDown") {
58
+ event.preventDefault();
59
+ focusFromIndex(index, 7);
60
+ return;
61
+ }
62
+ if (event.key === "ArrowUp") {
63
+ event.preventDefault();
64
+ focusFromIndex(index, -7);
65
+ return;
66
+ }
67
+ if (event.key === "Home") {
68
+ event.preventDefault();
69
+ focusFirstAvailable();
70
+ return;
71
+ }
72
+ if (event.altKey && event.key === "PageUp") {
73
+ event.preventDefault();
74
+ for (let i = 0; i < 12; i += 1) {
75
+ onPrev?.();
76
+ }
77
+ return;
78
+ }
79
+ if (event.altKey && event.key === "PageDown") {
80
+ event.preventDefault();
81
+ for (let i = 0; i < 12; i += 1) {
82
+ onNext?.();
83
+ }
84
+ return;
85
+ }
86
+ if (event.key === "PageUp") {
87
+ event.preventDefault();
88
+ onPrev?.();
89
+ return;
90
+ }
91
+ if (event.key === "PageDown") {
92
+ event.preventDefault();
93
+ onNext?.();
94
+ }
95
+ }
137
96
  </script>
138
97
 
139
98
  <div class="w-full min-w-[16.5rem] max-w-[22rem] rounded border border-surface-300-700 bg-surface-100-900 p-2">
@@ -1,65 +1,6 @@
1
- <script lang="ts">
2
- import DateTimeCtrlCalendar from './DateTimeCtrlCalendar.svelte';
3
- import DateTimeCtrlTimeFields from './DateTimeCtrlTimeFields.svelte';
4
- import type { CalendarCell } from './DateTimeCtrl.utils';
5
-
6
- export interface Props {
7
- amLabel?: string;
8
- calendarCells?: CalendarCell[];
9
- calendarMonthLabel?: string;
10
- hour?: number;
11
- hoursStep?: number;
12
- isDateSelectable?: (isoDate: string) => boolean;
13
- maxDate?: string;
14
- maxTime?: string;
15
- minDate?: string;
16
- minTime?: string;
17
- minute?: number;
18
- minutesStep?: number;
19
- onNow?: () => void;
20
- onClose?: () => void;
21
- onSelectCalendarDate?: (isoDate: string) => void;
22
- onShiftMonth?: (delta: number) => void;
23
- onTimeChange?: (value: { hour: number; minute: number; second: number }) => void;
24
- pmLabel?: string;
25
- presets?: Array<string | { label: string; value: string }>;
26
- second?: number;
27
- secondsStep?: number;
28
- selectedDateIso?: string;
29
- showDatePicker?: boolean;
30
- showTimePicker?: boolean;
31
- use12Hour?: boolean;
32
- withTimeDropdown?: boolean;
33
- }
34
-
35
- let {
36
- amLabel = 'AM',
37
- calendarCells = [],
38
- calendarMonthLabel = '',
39
- hour = 0,
40
- hoursStep = 1,
41
- isDateSelectable,
42
- maxDate,
43
- maxTime,
44
- minDate,
45
- minTime,
46
- minute = 0,
47
- minutesStep = 1,
48
- onNow,
49
- onClose,
50
- onSelectCalendarDate,
51
- onShiftMonth,
52
- onTimeChange,
53
- pmLabel = 'PM',
54
- presets = [],
55
- second = 0,
56
- secondsStep = 1,
57
- selectedDateIso,
58
- showDatePicker = false,
59
- showTimePicker = false,
60
- use12Hour = false,
61
- withTimeDropdown = false,
62
- }: Props = $props();
1
+ <script lang="ts">import DateTimeCtrlCalendar from "./DateTimeCtrlCalendar.svelte";
2
+ import DateTimeCtrlTimeFields from "./DateTimeCtrlTimeFields.svelte";
3
+ let { amLabel = "AM", calendarCells = [], calendarMonthLabel = "", hour = 0, hoursStep = 1, isDateSelectable, maxDate, maxTime, minDate, minTime, minute = 0, minutesStep = 1, onNow, onClose, onSelectCalendarDate, onShiftMonth, onTimeChange, pmLabel = "PM", presets = [], second = 0, secondsStep = 1, selectedDateIso, showDatePicker = false, showTimePicker = false, use12Hour = false, withTimeDropdown = false } = $props();
63
4
  </script>
64
5
 
65
6
  <div class="flex flex-col gap-3">
@@ -1,220 +1,146 @@
1
- <script lang="ts">
2
- interface TimePresetOption {
3
- label: string;
4
- value: string;
5
- }
6
-
7
- export interface Props {
8
- amLabel?: string;
9
- hour?: number;
10
- hoursStep?: number;
11
- maxTime?: string;
12
- minTime?: string;
13
- minute?: number;
14
- minutesStep?: number;
15
- onChange?: (value: { hour: number; minute: number; second: number }) => void;
16
- pmLabel?: string;
17
- presets?: Array<string | TimePresetOption>;
18
- second?: number;
19
- secondsStep?: number;
20
- use12Hour?: boolean;
21
- withDropdown?: boolean;
22
- }
23
-
24
- let {
25
- amLabel = 'AM',
26
- hour = 0,
27
- hoursStep = 1,
28
- maxTime,
29
- minTime,
30
- minute = 0,
31
- minutesStep = 1,
32
- onChange,
33
- pmLabel = 'PM',
34
- presets = [],
35
- second = 0,
36
- secondsStep = 1,
37
- use12Hour = false,
38
- withDropdown = false,
39
- }: Props = $props();
40
-
41
- let h = $state('0');
42
- let m = $state('0');
43
- let s = $state('0');
44
- let meridian = $state<'am' | 'pm'>('am');
45
-
46
- const safeHoursStep = $derived(Math.max(1, Math.trunc(hoursStep || 1)));
47
- const safeMinutesStep = $derived(Math.max(1, Math.trunc(minutesStep || 1)));
48
- const safeSecondsStep = $derived(Math.max(1, Math.trunc(secondsStep || 1)));
49
-
50
- const hourOptions = $derived.by(() => {
51
- const options: number[] = [];
52
- if (use12Hour) {
53
- for (let i = 1; i <= 12; i += safeHoursStep) {
54
- options.push(i);
55
- }
56
- if (!options.includes(12)) {
57
- options.push(12);
58
- }
59
- return options;
60
- }
61
-
62
- for (let i = 0; i <= 23; i += safeHoursStep) {
63
- options.push(i);
64
- }
65
- if (!options.includes(23)) {
66
- options.push(23);
67
- }
68
-
69
- return options;
70
- });
71
-
72
- const minuteOptions = $derived.by(() => {
73
- const options: number[] = [];
74
- for (let i = 0; i <= 59; i += safeMinutesStep) {
75
- options.push(i);
76
- }
77
- if (!options.includes(59)) {
78
- options.push(59);
79
- }
80
- return options;
81
- });
82
-
83
- const secondOptions = $derived.by(() => {
84
- const options: number[] = [];
85
- for (let i = 0; i <= 59; i += safeSecondsStep) {
86
- options.push(i);
87
- }
88
- if (!options.includes(59)) {
89
- options.push(59);
90
- }
91
- return options;
92
- });
93
-
94
- const normalizedPresets = $derived.by(() => {
95
- return presets
96
- .map((preset) => {
97
- if (typeof preset === 'string') {
98
- return { label: preset, value: preset };
99
- }
100
-
101
- return preset;
102
- })
103
- .filter((preset) => preset.value && preset.value.trim() !== '');
104
- });
105
-
106
- function pad2(value: number): string {
107
- return String(value).padStart(2, '0');
108
- }
109
-
110
- function clamp(value: number, min: number, max: number): number {
111
- return Math.max(min, Math.min(max, value));
112
- }
113
-
114
- function to12Hour(inputHour: number): { displayHour: number; meridian: 'am' | 'pm' } {
115
- const isPm = inputHour >= 12;
116
- const displayHour = inputHour % 12 === 0 ? 12 : inputHour % 12;
117
- return { displayHour, meridian: isPm ? 'pm' : 'am' };
118
- }
119
-
120
- function from12Hour(displayHour: number, nextMeridian: 'am' | 'pm'): number {
121
- const normalized = clamp(displayHour, 1, 12) % 12;
122
- if (nextMeridian === 'pm') {
123
- return normalized + 12;
124
- }
125
- return normalized;
126
- }
127
-
128
- function parsePreset(value: string): { hour: number; minute: number; second: number } | null {
129
- const matched = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/.exec(value.trim());
130
- if (!matched) {
131
- return null;
132
- }
133
-
134
- const parsedHour = Number(matched[1]);
135
- const parsedMinute = Number(matched[2]);
136
- const parsedSecond = Number(matched[3] ?? '0');
137
-
138
- if (
139
- !Number.isInteger(parsedHour) ||
140
- !Number.isInteger(parsedMinute) ||
141
- !Number.isInteger(parsedSecond) ||
142
- parsedHour < 0 ||
143
- parsedHour > 23 ||
144
- parsedMinute < 0 ||
145
- parsedMinute > 59 ||
146
- parsedSecond < 0 ||
147
- parsedSecond > 59
148
- ) {
149
- return null;
150
- }
151
-
152
- return {
153
- hour: parsedHour,
154
- minute: parsedMinute,
155
- second: parsedSecond,
156
- };
157
- }
158
-
159
- function emit(): void {
160
- const parsedHour = Number(h);
161
- const parsedMinute = Number(m);
162
- const parsedSecond = Number(s);
163
-
164
- if (
165
- !Number.isFinite(parsedHour) ||
166
- !Number.isFinite(parsedMinute) ||
167
- !Number.isFinite(parsedSecond)
168
- ) {
169
- return;
170
- }
171
-
172
- const minuteValue = clamp(Math.trunc(parsedMinute), 0, 59);
173
- const secondValue = clamp(Math.trunc(parsedSecond), 0, 59);
174
-
175
- let hourValue = clamp(Math.trunc(parsedHour), 0, 23);
176
- if (use12Hour) {
177
- hourValue = from12Hour(parsedHour, meridian);
178
- }
179
-
180
- onChange?.({
181
- hour: hourValue,
182
- minute: minuteValue,
183
- second: secondValue,
184
- });
185
- }
186
-
187
- function applyPreset(preset: string): void {
188
- const parsed = parsePreset(preset);
189
- if (!parsed) {
190
- return;
191
- }
192
-
193
- if (use12Hour) {
194
- const converted = to12Hour(parsed.hour);
195
- h = String(converted.displayHour);
196
- meridian = converted.meridian;
197
- } else {
198
- h = String(parsed.hour);
199
- }
200
-
201
- m = String(parsed.minute);
202
- s = String(parsed.second);
203
- emit();
204
- }
205
-
206
- $effect(() => {
207
- if (use12Hour) {
208
- const converted = to12Hour(hour);
209
- h = String(converted.displayHour);
210
- meridian = converted.meridian;
211
- } else {
212
- h = String(hour);
213
- }
214
-
215
- m = String(minute);
216
- s = String(second);
217
- });
1
+ <script lang="ts">let { amLabel = "AM", hour = 0, hoursStep = 1, maxTime, minTime, minute = 0, minutesStep = 1, onChange, pmLabel = "PM", presets = [], second = 0, secondsStep = 1, use12Hour = false, withDropdown = false } = $props();
2
+ let h = $state("0");
3
+ let m = $state("0");
4
+ let s = $state("0");
5
+ let meridian = $state("am");
6
+ const safeHoursStep = $derived(Math.max(1, Math.trunc(hoursStep || 1)));
7
+ const safeMinutesStep = $derived(Math.max(1, Math.trunc(minutesStep || 1)));
8
+ const safeSecondsStep = $derived(Math.max(1, Math.trunc(secondsStep || 1)));
9
+ const hourOptions = $derived.by(() => {
10
+ const options = [];
11
+ if (use12Hour) {
12
+ for (let i = 1; i <= 12; i += safeHoursStep) {
13
+ options.push(i);
14
+ }
15
+ if (!options.includes(12)) {
16
+ options.push(12);
17
+ }
18
+ return options;
19
+ }
20
+ for (let i = 0; i <= 23; i += safeHoursStep) {
21
+ options.push(i);
22
+ }
23
+ if (!options.includes(23)) {
24
+ options.push(23);
25
+ }
26
+ return options;
27
+ });
28
+ const minuteOptions = $derived.by(() => {
29
+ const options = [];
30
+ for (let i = 0; i <= 59; i += safeMinutesStep) {
31
+ options.push(i);
32
+ }
33
+ if (!options.includes(59)) {
34
+ options.push(59);
35
+ }
36
+ return options;
37
+ });
38
+ const secondOptions = $derived.by(() => {
39
+ const options = [];
40
+ for (let i = 0; i <= 59; i += safeSecondsStep) {
41
+ options.push(i);
42
+ }
43
+ if (!options.includes(59)) {
44
+ options.push(59);
45
+ }
46
+ return options;
47
+ });
48
+ const normalizedPresets = $derived.by(() => {
49
+ return presets.map((preset) => {
50
+ if (typeof preset === "string") {
51
+ return {
52
+ label: preset,
53
+ value: preset
54
+ };
55
+ }
56
+ return preset;
57
+ }).filter((preset) => preset.value && preset.value.trim() !== "");
58
+ });
59
+ function pad2(value) {
60
+ return String(value).padStart(2, "0");
61
+ }
62
+ function clamp(value, min, max) {
63
+ return Math.max(min, Math.min(max, value));
64
+ }
65
+ function to12Hour(inputHour) {
66
+ const isPm = inputHour >= 12;
67
+ const displayHour = inputHour % 12 === 0 ? 12 : inputHour % 12;
68
+ return {
69
+ displayHour,
70
+ meridian: isPm ? "pm" : "am"
71
+ };
72
+ }
73
+ function from12Hour(displayHour, nextMeridian) {
74
+ const normalized = clamp(displayHour, 1, 12) % 12;
75
+ if (nextMeridian === "pm") {
76
+ return normalized + 12;
77
+ }
78
+ return normalized;
79
+ }
80
+ function parsePreset(value) {
81
+ const matched = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/.exec(value.trim());
82
+ if (!matched) {
83
+ return null;
84
+ }
85
+ const parsedHour = Number(matched[1]);
86
+ const parsedMinute = Number(matched[2]);
87
+ const parsedSecond = Number(matched[3] ?? "0");
88
+ if (!Number.isInteger(parsedHour) || !Number.isInteger(parsedMinute) || !Number.isInteger(parsedSecond) || parsedHour < 0 || parsedHour > 23 || parsedMinute < 0 || parsedMinute > 59 || parsedSecond < 0 || parsedSecond > 59) {
89
+ return null;
90
+ }
91
+ return {
92
+ hour: parsedHour,
93
+ minute: parsedMinute,
94
+ second: parsedSecond
95
+ };
96
+ }
97
+ function emit() {
98
+ const parsedHour = Number(h);
99
+ const parsedMinute = Number(m);
100
+ const parsedSecond = Number(s);
101
+ if (!Number.isFinite(parsedHour) || !Number.isFinite(parsedMinute) || !Number.isFinite(parsedSecond)) {
102
+ return;
103
+ }
104
+ const minuteValue = clamp(Math.trunc(parsedMinute), 0, 59);
105
+ const secondValue = clamp(Math.trunc(parsedSecond), 0, 59);
106
+ let hourValue = clamp(Math.trunc(parsedHour), 0, 23);
107
+ if (use12Hour) {
108
+ hourValue = from12Hour(parsedHour, meridian);
109
+ }
110
+ onChange?.({
111
+ hour: hourValue,
112
+ minute: minuteValue,
113
+ second: secondValue
114
+ });
115
+ }
116
+ function applyPreset(preset) {
117
+ const parsed = parsePreset(preset);
118
+ if (!parsed) {
119
+ return;
120
+ }
121
+ if (use12Hour) {
122
+ const converted = to12Hour(parsed.hour);
123
+ h = String(converted.displayHour);
124
+ meridian = converted.meridian;
125
+ } else {
126
+ h = String(parsed.hour);
127
+ }
128
+ m = String(parsed.minute);
129
+ s = String(parsed.second);
130
+ emit();
131
+ }
132
+ $effect(() => {
133
+ if (use12Hour) {
134
+ const converted = to12Hour(hour);
135
+ h = String(converted.displayHour);
136
+ meridian = converted.meridian;
137
+ } else {
138
+ h = String(hour);
139
+ }
140
+ m = String(minute);
141
+ s = String(second);
142
+ });
143
+ export {};
218
144
  </script>
219
145
 
220
146
  <div class="rounded border border-surface-300-700 bg-surface-100-900 p-2">