svelte-comp 1.2.7 → 1.3.5

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 (139) hide show
  1. package/README.md +12 -11
  2. package/dist/App.svelte +497 -2
  3. package/dist/app.css +2 -3
  4. package/dist/app.d.ts +10 -0
  5. package/dist/lang.d.ts +3 -3
  6. package/dist/lang.js +3 -3
  7. package/dist/lib/Accordion.svelte +14 -14
  8. package/dist/lib/Badge.svelte +44 -0
  9. package/dist/lib/Badge.svelte.d.ts +10 -0
  10. package/dist/lib/Button.svelte +23 -8
  11. package/dist/lib/Calendar.svelte +384 -377
  12. package/dist/lib/Card.svelte +6 -6
  13. package/dist/lib/Carousel.svelte +16 -16
  14. package/dist/lib/Carousel.svelte.d.ts +1 -1
  15. package/dist/lib/CheckBox.svelte +2 -2
  16. package/dist/lib/CodeView.svelte +6 -5
  17. package/dist/lib/ColorPicker.svelte +6 -6
  18. package/dist/lib/ContextMenu.svelte +328 -0
  19. package/dist/lib/ContextMenu.svelte.d.ts +14 -0
  20. package/dist/lib/DatePicker.svelte +161 -161
  21. package/dist/lib/Dialog.svelte +10 -10
  22. package/dist/lib/Field.svelte +1 -1
  23. package/dist/lib/FilePicker.svelte +127 -74
  24. package/dist/lib/FilePicker.svelte.d.ts +6 -3
  25. package/dist/lib/Hamburger.svelte +27 -21
  26. package/dist/lib/InstallPWA.svelte +94 -0
  27. package/dist/lib/InstallPWA.svelte.d.ts +8 -0
  28. package/dist/lib/Menu.svelte +18 -18
  29. package/dist/lib/NoticeBase.svelte +140 -0
  30. package/dist/lib/NoticeBase.svelte.d.ts +43 -0
  31. package/dist/lib/PrimaryColorSelect.svelte +6 -6
  32. package/dist/lib/ProgressCircle.svelte +7 -9
  33. package/dist/lib/ProgressCircle.svelte.d.ts +7 -9
  34. package/dist/lib/SearchInput.svelte +6 -6
  35. package/dist/lib/Select.svelte +2 -2
  36. package/dist/lib/Slider.svelte +1 -1
  37. package/dist/lib/Splitter.svelte +15 -6
  38. package/dist/lib/Switch.svelte +5 -4
  39. package/dist/lib/Tabs.svelte +6 -6
  40. package/dist/lib/ThemeToggle.svelte +1 -0
  41. package/dist/lib/TimePicker.svelte +103 -95
  42. package/dist/lib/TimePickerNew.svelte +634 -0
  43. package/dist/lib/TimePickerNew.svelte.d.ts +49 -0
  44. package/dist/lib/Toast.svelte +17 -120
  45. package/dist/lib/Tooltip.svelte +7 -7
  46. package/dist/lib/Topbar.svelte +112 -0
  47. package/dist/lib/Topbar.svelte.d.ts +44 -0
  48. package/dist/lib/__tests__/Accordion.test.d.ts +1 -0
  49. package/dist/lib/__tests__/Accordion.test.js +171 -0
  50. package/dist/lib/__tests__/Badge.test.d.ts +1 -0
  51. package/dist/lib/__tests__/Badge.test.js +41 -0
  52. package/dist/lib/__tests__/Button.test.d.ts +1 -0
  53. package/dist/lib/__tests__/Button.test.js +269 -0
  54. package/dist/lib/__tests__/Calendar.test.d.ts +1 -0
  55. package/dist/lib/__tests__/Calendar.test.js +171 -0
  56. package/dist/lib/__tests__/Card.test.d.ts +1 -0
  57. package/dist/lib/__tests__/Card.test.js +148 -0
  58. package/dist/lib/__tests__/Carousel.test.d.ts +1 -0
  59. package/dist/lib/__tests__/Carousel.test.js +439 -0
  60. package/dist/lib/__tests__/CheckBox.test.d.ts +1 -0
  61. package/dist/lib/__tests__/CheckBox.test.js +152 -0
  62. package/dist/lib/__tests__/CodeView.test.d.ts +1 -0
  63. package/dist/lib/__tests__/CodeView.test.js +157 -0
  64. package/dist/lib/__tests__/ColorPicker.test.d.ts +1 -0
  65. package/dist/lib/__tests__/ColorPicker.test.js +93 -0
  66. package/dist/lib/__tests__/ContextMenu.test.d.ts +1 -0
  67. package/dist/lib/__tests__/ContextMenu.test.js +67 -0
  68. package/dist/lib/__tests__/DatePicker.test.d.ts +1 -0
  69. package/dist/lib/__tests__/DatePicker.test.js +108 -0
  70. package/dist/lib/__tests__/Dialog.test.d.ts +1 -0
  71. package/dist/lib/__tests__/Dialog.test.js +183 -0
  72. package/dist/lib/__tests__/Field.test.d.ts +1 -0
  73. package/dist/lib/__tests__/Field.test.js +190 -0
  74. package/dist/lib/__tests__/FilePicker.test.d.ts +1 -0
  75. package/dist/lib/__tests__/FilePicker.test.js +179 -0
  76. package/dist/lib/__tests__/Form.integration.test.d.ts +1 -0
  77. package/dist/lib/__tests__/Form.integration.test.js +158 -0
  78. package/dist/lib/__tests__/Form.test.d.ts +1 -0
  79. package/dist/lib/__tests__/Form.test.js +463 -0
  80. package/dist/lib/__tests__/Hamburger.test.d.ts +1 -0
  81. package/dist/lib/__tests__/Hamburger.test.js +161 -0
  82. package/dist/lib/__tests__/InstallPWA.test.d.ts +1 -0
  83. package/dist/lib/__tests__/InstallPWA.test.js +15 -0
  84. package/dist/lib/__tests__/Menu.test.d.ts +1 -0
  85. package/dist/lib/__tests__/Menu.test.js +285 -0
  86. package/dist/lib/__tests__/NoticeBase.test.d.ts +1 -0
  87. package/dist/lib/__tests__/NoticeBase.test.js +60 -0
  88. package/dist/lib/__tests__/PaginatedCard.test.d.ts +1 -0
  89. package/dist/lib/__tests__/PaginatedCard.test.js +89 -0
  90. package/dist/lib/__tests__/Pagination.test.d.ts +1 -0
  91. package/dist/lib/__tests__/Pagination.test.js +168 -0
  92. package/dist/lib/__tests__/PrimaryColorSelect.test.d.ts +1 -0
  93. package/dist/lib/__tests__/PrimaryColorSelect.test.js +92 -0
  94. package/dist/lib/__tests__/ProgressBar.test.d.ts +1 -0
  95. package/dist/lib/__tests__/ProgressBar.test.js +69 -0
  96. package/dist/lib/__tests__/ProgressCircle.test.d.ts +1 -0
  97. package/dist/lib/__tests__/ProgressCircle.test.js +71 -0
  98. package/dist/lib/__tests__/Radio.test.d.ts +1 -0
  99. package/dist/lib/__tests__/Radio.test.js +127 -0
  100. package/dist/lib/__tests__/SearchInput.test.d.ts +1 -0
  101. package/dist/lib/__tests__/SearchInput.test.js +80 -0
  102. package/dist/lib/__tests__/Select.test.d.ts +1 -0
  103. package/dist/lib/__tests__/Select.test.js +408 -0
  104. package/dist/lib/__tests__/Slider.test.d.ts +1 -0
  105. package/dist/lib/__tests__/Slider.test.js +213 -0
  106. package/dist/lib/__tests__/Splitter.test.d.ts +1 -0
  107. package/dist/lib/__tests__/Splitter.test.js +87 -0
  108. package/dist/lib/__tests__/Switch.test.d.ts +1 -0
  109. package/dist/lib/__tests__/Switch.test.js +97 -0
  110. package/dist/lib/__tests__/Table.test.d.ts +1 -0
  111. package/dist/lib/__tests__/Table.test.js +349 -0
  112. package/dist/lib/__tests__/Tabs.test.d.ts +1 -0
  113. package/dist/lib/__tests__/Tabs.test.js +262 -0
  114. package/dist/lib/__tests__/ThemeToggle.test.d.ts +1 -0
  115. package/dist/lib/__tests__/ThemeToggle.test.js +84 -0
  116. package/dist/lib/__tests__/TimePicker.test.d.ts +1 -0
  117. package/dist/lib/__tests__/TimePicker.test.js +146 -0
  118. package/dist/lib/__tests__/TimePickerNew.test.d.ts +1 -0
  119. package/dist/lib/__tests__/TimePickerNew.test.js +322 -0
  120. package/dist/lib/__tests__/Toast.test.d.ts +1 -0
  121. package/dist/lib/__tests__/Toast.test.js +135 -0
  122. package/dist/lib/__tests__/Tooltip.test.d.ts +1 -0
  123. package/dist/lib/__tests__/Tooltip.test.js +171 -0
  124. package/dist/lib/__tests__/Topbar.test.d.ts +1 -0
  125. package/dist/lib/__tests__/Topbar.test.js +25 -0
  126. package/dist/lib/__tests__/setupLangContext.d.ts +1 -0
  127. package/dist/lib/__tests__/setupLangContext.js +65 -0
  128. package/dist/lib/__tests__/storage.test.d.ts +1 -0
  129. package/dist/lib/__tests__/storage.test.js +124 -0
  130. package/dist/lib/__tests__/utils.test.d.ts +1 -0
  131. package/dist/lib/__tests__/utils.test.js +11 -0
  132. package/dist/lib/index.d.ts +5 -0
  133. package/dist/lib/index.js +5 -0
  134. package/dist/lib/lang.d.ts +64 -0
  135. package/dist/lib/lang.js +64 -0
  136. package/dist/lib/types/index.d.ts +1 -0
  137. package/dist/styles.css +2 -0
  138. package/dist/utils/index.js +15 -4
  139. package/package.json +12 -12
@@ -172,7 +172,7 @@
172
172
  if (disabled) return;
173
173
  const span = max - min;
174
174
  const big = Math.max(step || 1, Math.round(span / 10));
175
- let v = value;
175
+ let v: number;
176
176
 
177
177
  switch (e.key) {
178
178
  case "ArrowLeft":
@@ -83,7 +83,7 @@
83
83
  }
84
84
 
85
85
  function onDrag(e: PointerEvent): void {
86
- if (!isDragging) return;
86
+ if (!isDragging || containerSize <= 0) return;
87
87
 
88
88
  const currentPos = direction === "horizontal" ? e.clientX : e.clientY;
89
89
  const delta = currentPos - startPos;
@@ -124,8 +124,11 @@
124
124
  </div>
125
125
 
126
126
  <div
127
- class="touch-none select-none z-10 cursor-col-resize bg-[var(--color-bg-muted)] hover:bg-[var(--color-bg-hover)] transition-colors"
128
- style="width: {dividerSize}px"
127
+ role="separator"
128
+ aria-orientation="vertical"
129
+ aria-label="Resize handle"
130
+ class="touch-none select-none z-10 cursor-col-resize bg-[var(--color-bg-muted)] hover:bg-[var(--color-bg-hover)] transition-colors [@media(pointer:coarse)]:min-w-11"
131
+ style="width: {dividerSize}px; min-width: {dividerSize}px"
129
132
  onpointerdown={startDrag}
130
133
  ></div>
131
134
 
@@ -138,12 +141,18 @@
138
141
  </div>
139
142
 
140
143
  <div
141
- class="touch-none select-none z-10 cursor-row-resize bg-[var(--color-bg-muted)] hover:bg-[var(--color-bg-hover)] transition-colors"
142
- style="height: {dividerSize}px"
144
+ role="separator"
145
+ aria-orientation="horizontal"
146
+ aria-label="Resize handle"
147
+ class="touch-none select-none z-10 cursor-row-resize bg-[var(--color-bg-muted)] hover:bg-[var(--color-bg-hover)] transition-colors [@media(pointer:coarse)]:min-h-11"
148
+ style="height: {dividerSize}px; min-height: {dividerSize}px"
143
149
  onpointerdown={startDrag}
144
150
  ></div>
145
151
 
146
- <div class="overflow-auto min-w-0 min-h-0" style="height: calc(100% - {size}% - {dividerSize}px)">
152
+ <div
153
+ class="overflow-auto min-w-0 min-h-0"
154
+ style="height: calc(100% - {size}% - {dividerSize}px)"
155
+ >
147
156
  {@render second?.()}
148
157
  </div>
149
158
  {/if}
@@ -103,6 +103,7 @@
103
103
  isDisabled
104
104
  ? "opacity-[var(--opacity-disabled)] cursor-not-allowed"
105
105
  : "cursor-pointer",
106
+ "[@media(pointer:coarse)]:min-h-11 [@media(pointer:coarse)]:min-w-11",
106
107
  justifyClass
107
108
  )
108
109
  );
@@ -114,21 +115,21 @@
114
115
  const knobClass = $derived(
115
116
  cx(
116
117
  knob[sz],
117
- "rounded-full bg-white border border-[var(--border-color-default)] shadow-sm"
118
+ "rounded-full bg-[var(--color-text-inverse,#fff)] border border-[var(--border-color-default)] shadow-[0_1px_2px_var(--shadow-color)]"
118
119
  )
119
120
  );
120
121
  </script>
121
122
 
122
123
  <label class={rootClass} for={inputId}>
123
124
  {#if topLabel}
124
- <span class="text-[var(--color-text-muted)] {TEXT[sz]}">
125
+ <span class={cx("text-[var(--color-text-muted)]", TEXT[sz])}>
125
126
  {topLabel}
126
127
  </span>
127
128
  {/if}
128
129
 
129
130
  <div class="inline-flex items-center gap-2">
130
131
  {#if leftLabel}
131
- <span class="text-[var(--color-text-muted)] {TEXT[sz]}">
132
+ <span class={cx("text-[var(--color-text-muted)]", TEXT[sz])}>
132
133
  {leftLabel}
133
134
  </span>
134
135
  {/if}
@@ -159,7 +160,7 @@
159
160
  </button>
160
161
 
161
162
  {#if rightLabel}
162
- <span class="text-[var(--color-text-muted)] {TEXT[sz]}">
163
+ <span class={cx("text-[var(--color-text-muted)]", TEXT[sz])}>
163
164
  {rightLabel}
164
165
  </span>
165
166
  {/if}
@@ -90,7 +90,7 @@
90
90
  0,
91
91
  enabled.findIndex((t) => t.id === activeTab)
92
92
  );
93
- let next = idx;
93
+ let next: number;
94
94
 
95
95
  if (e.key === "ArrowRight") next = (idx + 1) % enabled.length;
96
96
  else if (e.key === "ArrowLeft")
@@ -115,27 +115,27 @@
115
115
  };
116
116
 
117
117
  const base =
118
- "inline-flex items-center justify-center font-medium transition-colors duration-150 focus-visible:ring-inset focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] focus-visible:ring-offset-0 focus:outline-none disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed";
118
+ "inline-flex items-center justify-center font-medium transition-colors duration-[var(--transition-fast)] focus-visible:ring-inset focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] focus-visible:ring-offset-0 focus:outline-none disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed [@media(pointer:coarse)]:min-h-11";
119
119
 
120
120
  const variants = $derived({
121
121
  default: {
122
- base: "border-b-2 border-transparent text-[var(--color-text-muted)]",
122
+ base: "border-b-2 border-transparent text-[var(--color-text-default)]",
123
123
  active:
124
124
  "bg-[var(--color-bg-secondary)] !text-[var(--color-text-default)] border-[var(--border-color-strong)]",
125
125
  hover:
126
126
  "hover:text-[var(--color-text-default)] hover:bg-[var(--color-bg-muted)]",
127
127
  },
128
128
  underline: {
129
- base: "border-b-2 border-transparent text-[var(--color-text-muted)]",
129
+ base: "border-b-2 border-transparent text-[var(--color-text-default)]",
130
130
  active:
131
131
  "border-[var(--border-color-focus)] !text-[var(--color-text-default)]",
132
132
  hover:
133
133
  "hover:text-[var(--color-text-default)] hover:border-[var(--border-color-strong)]",
134
134
  },
135
135
  pills: {
136
- base: "text-[var(--color-text-muted)] border border-transparent font-medium",
136
+ base: "text-[var(--color-text-default)] border border-transparent font-medium",
137
137
  active:
138
- "bg-[var(--color-bg-primary)] text-white border-[var(--color-bg-primary)]",
138
+ "bg-[var(--color-bg-primary)] text-[var(--color-text-default)] border-[var(--color-bg-primary)] font-[var(--font-weight-semibold)]",
139
139
  hover:
140
140
  "hover:bg-[var(--color-bg-secondary)] hover:text-[var(--color-text-default)]",
141
141
  },
@@ -48,6 +48,7 @@
48
48
  border border-[var(--border-color-default)] bg-[var(--color-bg-secondary)]
49
49
  hover:bg-[var(--color-bg-hover)] focus-visible:outline-none focus-visible:ring-2
50
50
  focus-visible:ring-[var(--border-color-focus)] transition-colors
51
+ [@media(pointer:coarse)]:min-h-11 [@media(pointer:coarse)]:min-w-11
51
52
  disabled:opacity-[var(--opacity-disabled)]
52
53
  disabled:cursor-not-allowed
53
54
  disabled:brightness-100
@@ -34,10 +34,10 @@
34
34
  * @note No locale or date-formatting APIs are used internally
35
35
  */
36
36
  import type { HTMLAttributes } from "svelte/elements";
37
- import Button from "./Button.svelte";
38
- import Select from "./Select.svelte";
39
- import { cx } from "../utils";
40
- import { getComponentText, getLangContext, getLangKey } from "./lang-context";
37
+ import Button from "./Button.svelte";
38
+ import Select from "./Select.svelte";
39
+ import { cx } from "../utils";
40
+ import { getComponentText, getLangContext, getLangKey } from "./lang-context";
41
41
 
42
42
  type Props = HTMLAttributes<HTMLDivElement> & {
43
43
  value?: string | null;
@@ -50,6 +50,7 @@
50
50
  onChange?: (value: string | null) => void;
51
51
  class?: string;
52
52
  };
53
+ type Period = "AM" | "PM";
53
54
 
54
55
  let {
55
56
  value = $bindable<string | null>(null),
@@ -64,22 +65,23 @@
64
65
  ...rest
65
66
  }: Props = $props();
66
67
 
67
- const langCtx = getLangContext();
68
- const langKey = $derived(getLangKey(langCtx));
69
- const L = $derived(getComponentText("timePicker", langKey));
68
+ const langCtx = getLangContext();
69
+ const langKey = $derived(getLangKey(langCtx));
70
+ const L = $derived(getComponentText("timePicker", langKey));
70
71
 
71
72
  const labelFinal = $derived(label ?? L.text);
72
73
  const placeholderFinal = $derived(placeholder ?? L.placeholder);
73
74
 
74
75
  const pickerClass = $derived(cx("inline-block w-full", externalClass));
75
76
 
76
- let timeSystem = $state(initialSystem);
77
+ let timeSystem = $state<"iso" | "english">("iso");
78
+ let didInitSystem = $state(false);
77
79
 
78
80
  let hour = $state("00");
79
81
  let minute = $state("00");
80
- let period = $state<"AM" | "PM">("AM");
82
+ let period = $state<Period>("AM");
81
83
 
82
- const hasValue = $derived(value != null);
84
+ const hasValue = $derived(value != null);
83
85
 
84
86
  const isoHours = Array.from({ length: 24 }, (_, i) => {
85
87
  const h = i.toString().padStart(2, "0");
@@ -91,7 +93,7 @@
91
93
  return { value: h, label: h };
92
94
  });
93
95
 
94
- const periodOptions = [
96
+ const periodOptions: Array<{ value: Period; label: Period }> = [
95
97
  { value: "AM", label: "AM" },
96
98
  { value: "PM", label: "PM" },
97
99
  ];
@@ -109,35 +111,35 @@
109
111
  return arr;
110
112
  });
111
113
 
112
- function normalize(x: string) {
113
- return x.padStart(2, "0").slice(-2);
114
- }
115
-
116
- function toIsoHour(h: string, p: "AM" | "PM") {
117
- const numeric = Number.parseInt(h, 10);
118
- if (Number.isNaN(numeric)) return "00";
119
- const base = numeric % 12;
120
- const withPeriod = p === "PM" ? base + 12 : base;
121
- return normalize(String(withPeriod));
122
- }
123
-
124
- function toEnglishHour(isoHour: string) {
125
- const numeric = Number.parseInt(isoHour, 10);
126
- if (Number.isNaN(numeric)) {
127
- return { hour: "12", period: "AM" as const };
128
- }
129
- const periodValue = numeric >= 12 ? "PM" : "AM";
130
- const normalized = numeric % 12 || 12;
131
- return { hour: normalize(String(normalized)), period: periodValue };
132
- }
133
-
134
- function emit() {
135
- const isoHour =
136
- timeSystem === "english" ? toIsoHour(hour, period) : normalize(hour);
137
- const v = `${isoHour}:${normalize(minute)}`;
138
- value = v;
139
- onChange?.(v);
140
- }
114
+ function normalize(x: string) {
115
+ return x.padStart(2, "0").slice(-2);
116
+ }
117
+
118
+ function toIsoHour(h: string, p: "AM" | "PM") {
119
+ const numeric = Number.parseInt(h, 10);
120
+ if (Number.isNaN(numeric)) return "00";
121
+ const base = numeric % 12;
122
+ const withPeriod = p === "PM" ? base + 12 : base;
123
+ return normalize(String(withPeriod));
124
+ }
125
+
126
+ function toEnglishHour(isoHour: string): { hour: string; period: Period } {
127
+ const numeric = Number.parseInt(isoHour, 10);
128
+ if (Number.isNaN(numeric)) {
129
+ return { hour: "12", period: "AM" as const };
130
+ }
131
+ const periodValue: Period = numeric >= 12 ? "PM" : "AM";
132
+ const normalized = numeric % 12 || 12;
133
+ return { hour: normalize(String(normalized)), period: periodValue };
134
+ }
135
+
136
+ function emit() {
137
+ const isoHour =
138
+ timeSystem === "english" ? toIsoHour(hour, period) : normalize(hour);
139
+ const v = `${isoHour}:${normalize(minute)}`;
140
+ value = v;
141
+ onChange?.(v);
142
+ }
141
143
 
142
144
  function handleIsoHour(v: string) {
143
145
  hour = normalize(v);
@@ -159,22 +161,22 @@
159
161
  emit();
160
162
  }
161
163
 
162
- function toggleSystem() {
163
- if (disabled) return;
164
-
165
- if (timeSystem === "iso") {
166
- timeSystem = "english";
167
- const mapped = toEnglishHour(hour);
168
- hour = mapped.hour;
169
- period = mapped.period;
170
- } else {
171
- timeSystem = "iso";
172
- hour = toIsoHour(hour, period);
173
- period = "AM";
174
- }
175
-
176
- emit();
177
- }
164
+ function toggleSystem() {
165
+ if (disabled) return;
166
+
167
+ if (timeSystem === "iso") {
168
+ timeSystem = "english";
169
+ const mapped = toEnglishHour(hour);
170
+ hour = mapped.hour;
171
+ period = mapped.period;
172
+ } else {
173
+ timeSystem = "iso";
174
+ hour = toIsoHour(hour, period);
175
+ period = "AM";
176
+ }
177
+
178
+ emit();
179
+ }
178
180
 
179
181
  function clearSelection() {
180
182
  if (!clearable) return;
@@ -185,47 +187,53 @@
185
187
  onChange?.(null);
186
188
  }
187
189
 
188
- const displayValue = $derived.by(() => {
189
- if (!value) return "";
190
- const [isoH, isoM] = value.split(":");
191
- if (timeSystem === "english") {
192
- const { hour: h, period: p } = toEnglishHour(isoH);
193
- return `${h}:${normalize(isoM)} ${p}`;
194
- }
195
- return `${normalize(isoH)}:${normalize(isoM)}`;
196
- });
197
-
198
- $effect(() => {
199
- if (value == null) return;
200
-
201
- let raw = value;
202
- let parsedPeriod: "AM" | "PM" | null = null;
203
-
204
- if (raw.includes("AM") || raw.includes("PM")) {
205
- parsedPeriod = raw.includes("PM") ? "PM" : "AM";
206
- raw = raw.replace(" AM", "").replace(" PM", "");
207
- }
208
-
209
- const [h, m] = raw.split(":");
210
- const isoHour = normalize(h);
211
- const isoMinute = normalize(m);
212
-
213
- if (timeSystem === "english") {
214
- const mapped = parsedPeriod
215
- ? { hour: normalize(h), period: parsedPeriod }
216
- : toEnglishHour(isoHour);
217
- hour = mapped.hour;
218
- period = mapped.period;
219
- } else {
220
- hour = isoHour;
221
- period = toEnglishHour(isoHour).period;
222
- }
223
- minute = isoMinute;
224
- });
190
+ const displayValue = $derived.by(() => {
191
+ if (!value) return "";
192
+ const [isoH, isoM] = value.split(":");
193
+ if (timeSystem === "english") {
194
+ const { hour: h, period: p } = toEnglishHour(isoH);
195
+ return `${h}:${normalize(isoM)} ${p}`;
196
+ }
197
+ return `${normalize(isoH)}:${normalize(isoM)}`;
198
+ });
199
+
200
+ $effect(() => {
201
+ if (didInitSystem) return;
202
+ didInitSystem = true;
203
+ timeSystem = initialSystem;
204
+ });
205
+
206
+ $effect(() => {
207
+ if (value == null) return;
208
+
209
+ let raw = value;
210
+ let parsedPeriod: Period | null = null;
211
+
212
+ if (raw.includes("AM") || raw.includes("PM")) {
213
+ parsedPeriod = raw.includes("PM") ? "PM" : "AM";
214
+ raw = raw.replace(" AM", "").replace(" PM", "");
215
+ }
216
+
217
+ const [h, m] = raw.split(":");
218
+ const isoHour = normalize(h);
219
+ const isoMinute = normalize(m);
220
+
221
+ if (timeSystem === "english") {
222
+ const mapped = parsedPeriod
223
+ ? { hour: normalize(h), period: parsedPeriod }
224
+ : toEnglishHour(isoHour);
225
+ hour = mapped.hour;
226
+ period = mapped.period;
227
+ } else {
228
+ hour = isoHour;
229
+ period = toEnglishHour(isoHour).period;
230
+ }
231
+ minute = isoMinute;
232
+ });
225
233
  </script>
226
234
 
227
235
  <div class={pickerClass} {...rest}>
228
- <div class="text-md font-medium mb-2 [color:var(--color-text-default)]">
236
+ <div class="text-md font-medium mb-2 [color:var(--color-text-default)]">
229
237
  {labelFinal}
230
238
  </div>
231
239
 
@@ -295,7 +303,7 @@
295
303
 
296
304
  <p class="text-sm font-semibold mt-1 [color:var(--color-text-default)]">
297
305
  {#if hasValue}
298
- {displayValue}
306
+ {displayValue}
299
307
  {:else}
300
308
  {placeholderFinal}
301
309
  {/if}