@celestia-island/hikari 0.4.4

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 (187) hide show
  1. package/README.md +54 -0
  2. package/package.json +63 -0
  3. package/src/DemoApp.vue +400 -0
  4. package/src/components/HkActionBar.tsx +15 -0
  5. package/src/components/HkAlert.scss +121 -0
  6. package/src/components/HkAlert.tsx +85 -0
  7. package/src/components/HkAvatar.tsx +29 -0
  8. package/src/components/HkBadge.scss +117 -0
  9. package/src/components/HkBadge.tsx +50 -0
  10. package/src/components/HkBreadcrumb.tsx +39 -0
  11. package/src/components/HkButton.scss +128 -0
  12. package/src/components/HkButton.tsx +74 -0
  13. package/src/components/HkCard.scss +49 -0
  14. package/src/components/HkCard.tsx +38 -0
  15. package/src/components/HkCheckbox.scss +102 -0
  16. package/src/components/HkCheckbox.tsx +85 -0
  17. package/src/components/HkCollapse.tsx +48 -0
  18. package/src/components/HkColorPicker.scss +148 -0
  19. package/src/components/HkColorPicker.tsx +204 -0
  20. package/src/components/HkConfirmDialog.scss +12 -0
  21. package/src/components/HkConfirmDialog.tsx +75 -0
  22. package/src/components/HkDateTimePicker.scss +361 -0
  23. package/src/components/HkDateTimePicker.tsx +424 -0
  24. package/src/components/HkDivider.scss +85 -0
  25. package/src/components/HkDivider.tsx +51 -0
  26. package/src/components/HkDraggableGrid.scss +132 -0
  27. package/src/components/HkDraggableGrid.tsx +291 -0
  28. package/src/components/HkDraggableList.scss +110 -0
  29. package/src/components/HkDraggableList.tsx +238 -0
  30. package/src/components/HkDrawer.scss +175 -0
  31. package/src/components/HkDrawer.tsx +171 -0
  32. package/src/components/HkEmptyState.scss +42 -0
  33. package/src/components/HkEmptyState.tsx +41 -0
  34. package/src/components/HkErrorBoundary.scss +64 -0
  35. package/src/components/HkErrorBoundary.tsx +82 -0
  36. package/src/components/HkGaugeRing.scss +4 -0
  37. package/src/components/HkGaugeRing.tsx +130 -0
  38. package/src/components/HkHoverRevealAction.scss +66 -0
  39. package/src/components/HkHoverRevealAction.tsx +77 -0
  40. package/src/components/HkIcon.tsx +43 -0
  41. package/src/components/HkIconButton.tsx +42 -0
  42. package/src/components/HkImageViewer.scss +33 -0
  43. package/src/components/HkImageViewer.tsx +250 -0
  44. package/src/components/HkInput.scss +172 -0
  45. package/src/components/HkInput.tsx +175 -0
  46. package/src/components/HkKbd.tsx +26 -0
  47. package/src/components/HkKeywordSearchModal.scss +148 -0
  48. package/src/components/HkKeywordSearchModal.tsx +308 -0
  49. package/src/components/HkListTransition.scss +131 -0
  50. package/src/components/HkListTransition.tsx +29 -0
  51. package/src/components/HkLocalePickerPopup.tsx +42 -0
  52. package/src/components/HkLogo.scss +36 -0
  53. package/src/components/HkLogo.tsx +93 -0
  54. package/src/components/HkMarkdownRenderer.scss +141 -0
  55. package/src/components/HkMarkdownRenderer.tsx +123 -0
  56. package/src/components/HkMediaControlBar.scss +65 -0
  57. package/src/components/HkMediaControlBar.tsx +115 -0
  58. package/src/components/HkMediaPlayer.scss +29 -0
  59. package/src/components/HkMediaPlayer.tsx +210 -0
  60. package/src/components/HkMediaSlider.scss +54 -0
  61. package/src/components/HkMediaSlider.tsx +81 -0
  62. package/src/components/HkMediaVisualizer.scss +7 -0
  63. package/src/components/HkMediaVisualizer.tsx +119 -0
  64. package/src/components/HkMinimap.scss +76 -0
  65. package/src/components/HkMinimap.tsx +255 -0
  66. package/src/components/HkModal.scss +318 -0
  67. package/src/components/HkModal.tsx +481 -0
  68. package/src/components/HkModalBreadcrumb.scss +55 -0
  69. package/src/components/HkModalBreadcrumb.tsx +113 -0
  70. package/src/components/HkMorphingTabs.scss +141 -0
  71. package/src/components/HkMorphingTabs.tsx +113 -0
  72. package/src/components/HkNavItem.scss +81 -0
  73. package/src/components/HkNavItem.tsx +157 -0
  74. package/src/components/HkNumberInput.scss +154 -0
  75. package/src/components/HkNumberInput.tsx +161 -0
  76. package/src/components/HkPasswordInput.scss +289 -0
  77. package/src/components/HkPasswordInput.tsx +533 -0
  78. package/src/components/HkPhaseTransition.scss +25 -0
  79. package/src/components/HkPhaseTransition.tsx +40 -0
  80. package/src/components/HkPopover.scss +82 -0
  81. package/src/components/HkPopover.tsx +410 -0
  82. package/src/components/HkPopupSelect.scss +136 -0
  83. package/src/components/HkPopupSelect.tsx +199 -0
  84. package/src/components/HkProgressBar.scss +106 -0
  85. package/src/components/HkProgressBar.tsx +61 -0
  86. package/src/components/HkProgressDialog.tsx +67 -0
  87. package/src/components/HkProgressRing.scss +56 -0
  88. package/src/components/HkProgressRing.tsx +82 -0
  89. package/src/components/HkRadio.scss +119 -0
  90. package/src/components/HkRadio.tsx +75 -0
  91. package/src/components/HkRollingNumber.scss +37 -0
  92. package/src/components/HkRollingNumber.tsx +97 -0
  93. package/src/components/HkScrollContainer.scss +101 -0
  94. package/src/components/HkScrollContainer.tsx +362 -0
  95. package/src/components/HkSearchInput.scss +132 -0
  96. package/src/components/HkSearchInput.tsx +117 -0
  97. package/src/components/HkSelect.scss +143 -0
  98. package/src/components/HkSelect.tsx +230 -0
  99. package/src/components/HkSelectionGrid.scss +177 -0
  100. package/src/components/HkSelectionGrid.tsx +99 -0
  101. package/src/components/HkSelectionWaterfall.scss +93 -0
  102. package/src/components/HkSelectionWaterfall.tsx +90 -0
  103. package/src/components/HkSidebar.scss +81 -0
  104. package/src/components/HkSidebar.tsx +45 -0
  105. package/src/components/HkSkeleton.scss +44 -0
  106. package/src/components/HkSkeleton.tsx +30 -0
  107. package/src/components/HkSkeletonList.tsx +35 -0
  108. package/src/components/HkSpinner.scss +67 -0
  109. package/src/components/HkSpinner.tsx +41 -0
  110. package/src/components/HkSplash.scss +60 -0
  111. package/src/components/HkSplash.tsx +40 -0
  112. package/src/components/HkSwitch.scss +157 -0
  113. package/src/components/HkSwitch.tsx +72 -0
  114. package/src/components/HkTable.scss +198 -0
  115. package/src/components/HkTable.tsx +246 -0
  116. package/src/components/HkTabs.scss +109 -0
  117. package/src/components/HkTabs.tsx +111 -0
  118. package/src/components/HkTag.scss +88 -0
  119. package/src/components/HkTag.tsx +44 -0
  120. package/src/components/HkTextarea.scss +72 -0
  121. package/src/components/HkTextarea.tsx +104 -0
  122. package/src/components/HkTimeline.scss +139 -0
  123. package/src/components/HkTimeline.tsx +95 -0
  124. package/src/components/HkToast.scss +168 -0
  125. package/src/components/HkToast.tsx +175 -0
  126. package/src/components/HkTooltip.scss +47 -0
  127. package/src/components/HkTooltip.tsx +108 -0
  128. package/src/components/HkTree.scss +188 -0
  129. package/src/components/HkTree.tsx +217 -0
  130. package/src/components/HkTrendChart.tsx +180 -0
  131. package/src/components/HkWindowedItem.scss +17 -0
  132. package/src/components/HkWindowedItem.tsx +107 -0
  133. package/src/components/HkZoomToolbar.scss +35 -0
  134. package/src/components/HkZoomToolbar.tsx +69 -0
  135. package/src/composables/useBreakpoint.ts +41 -0
  136. package/src/composables/useClipboard.ts +37 -0
  137. package/src/composables/useConfirm.ts +35 -0
  138. package/src/composables/useProgressDialog.ts +52 -0
  139. package/src/composables/useReportedTransition.ts +69 -0
  140. package/src/composables/useScrollWindow.ts +21 -0
  141. package/src/composables/useToast.ts +2 -0
  142. package/src/demo.scss +24 -0
  143. package/src/demo.ts +22 -0
  144. package/src/env.d.ts +6 -0
  145. package/src/i18n/context.ts +89 -0
  146. package/src/i18n/locales/ar/components.json +43 -0
  147. package/src/i18n/locales/ar/components.toml +40 -0
  148. package/src/i18n/locales/de/components.json +43 -0
  149. package/src/i18n/locales/de/components.toml +40 -0
  150. package/src/i18n/locales/en/components.json +43 -0
  151. package/src/i18n/locales/en/components.toml +40 -0
  152. package/src/i18n/locales/es/components.json +43 -0
  153. package/src/i18n/locales/es/components.toml +40 -0
  154. package/src/i18n/locales/fr/components.json +43 -0
  155. package/src/i18n/locales/fr/components.toml +40 -0
  156. package/src/i18n/locales/ja/components.json +43 -0
  157. package/src/i18n/locales/ja/components.toml +40 -0
  158. package/src/i18n/locales/ko/components.json +43 -0
  159. package/src/i18n/locales/ko/components.toml +40 -0
  160. package/src/i18n/locales/pt/components.json +43 -0
  161. package/src/i18n/locales/pt/components.toml +40 -0
  162. package/src/i18n/locales/ru/components.json +43 -0
  163. package/src/i18n/locales/ru/components.toml +40 -0
  164. package/src/i18n/locales/zh-Hans/components.json +43 -0
  165. package/src/i18n/locales/zh-Hans/components.toml +40 -0
  166. package/src/i18n/locales/zh-Hant/components.json +43 -0
  167. package/src/i18n/locales/zh-Hant/components.toml +40 -0
  168. package/src/index.ts +137 -0
  169. package/src/render.ts +18 -0
  170. package/src/runtime/animationBus.ts +278 -0
  171. package/src/runtime/cronBus.ts +25 -0
  172. package/src/runtime/index.ts +12 -0
  173. package/src/runtime/useAsyncData.ts +30 -0
  174. package/src/runtime/useBreakpoint.ts +62 -0
  175. package/src/runtime/useClipboard.ts +37 -0
  176. package/src/runtime/useConfirm.ts +35 -0
  177. package/src/runtime/useOverlay.ts +82 -0
  178. package/src/runtime/usePopupManager.ts +89 -0
  179. package/src/runtime/useToast.ts +140 -0
  180. package/src/styles/index.scss +10 -0
  181. package/src/theme/index.ts +5 -0
  182. package/src/theme/presets.ts +307 -0
  183. package/src/theme/theme.scss +17 -0
  184. package/src/theme/useBackgroundLuminance.ts +145 -0
  185. package/src/theme/useSolarTime.ts +101 -0
  186. package/src/theme/useTheme.ts +141 -0
  187. package/src/tokens.scss +26 -0
@@ -0,0 +1,533 @@
1
+ import {
2
+ computed,
3
+ defineComponent,
4
+ onMounted,
5
+ onUnmounted,
6
+ ref,
7
+ watch,
8
+ } from "vue";
9
+
10
+ import HListTransition from "./HkListTransition";
11
+ import "./HkPasswordInput.scss";
12
+
13
+ interface Ripple {
14
+ radius: number;
15
+ peak: number;
16
+ }
17
+
18
+ export default defineComponent({
19
+ name: "HkPasswordInput",
20
+ props: {
21
+ modelValue: { type: String, default: "" },
22
+ placeholder: { type: String, default: "" },
23
+ label: { type: String, default: undefined },
24
+ error: { type: String, default: undefined },
25
+ hint: { type: String, default: undefined },
26
+ disabled: { type: Boolean, default: false },
27
+ readonly: { type: Boolean, default: false },
28
+ required: { type: Boolean, default: false },
29
+ name: { type: String, default: undefined },
30
+ autocomplete: { type: String, default: undefined },
31
+ strength: { type: Boolean, default: false },
32
+ passwordEnteredText: { type: String, default: "Password entered" },
33
+ allSelectedText: { type: String, default: "All selected" },
34
+ capsLockText: { type: String, default: "Caps Lock is on" },
35
+ fullWidthWarningText: { type: String, default: "Full-width characters not allowed" },
36
+ },
37
+ emits: {
38
+ "update:modelValue": (_value: string) => true,
39
+ focus: (_e: FocusEvent) => true,
40
+ blur: (_e: FocusEvent) => true,
41
+ keydown: (_e: KeyboardEvent) => true,
42
+ },
43
+ setup(props, { emit }) {
44
+ const inputRef = ref<HTMLInputElement>();
45
+ const dotCanvasRef = ref<HTMLCanvasElement>();
46
+ const boxRef = ref<HTMLElement>();
47
+ const focused = ref(false);
48
+ const capsLock = ref(false);
49
+ const fullWidthPaused = ref(false);
50
+ const allSelected = ref(false);
51
+ const composing = ref(false);
52
+ const preComposeValue = ref("");
53
+ const revealing = ref(false);
54
+
55
+ const level = computed(() => {
56
+ if (!props.strength || !props.modelValue) return null;
57
+ const v = props.modelValue;
58
+ let score = 0;
59
+ if (v.length >= 8) score++;
60
+ if (/[a-z]/.test(v) && /[A-Z]/.test(v)) score++;
61
+ if (/\d/.test(v)) score++;
62
+ if (/[^a-zA-Z0-9]/.test(v)) score++;
63
+ if (v.length >= 14) score++;
64
+ if (score <= 1) return "weak";
65
+ if (score <= 2) return "fair";
66
+ if (score <= 3) return "strong";
67
+ return "strong";
68
+ });
69
+
70
+ const levelLabel = computed(() => {
71
+ const lv = level.value;
72
+ if (!lv) return "";
73
+ return lv.charAt(0).toUpperCase() + lv.slice(1);
74
+ });
75
+
76
+ function startReveal() {
77
+ if (!props.modelValue || props.disabled) return;
78
+ revealing.value = true;
79
+ document.addEventListener("pointerup", endReveal, { once: true });
80
+ document.addEventListener("pointercancel", endReveal, { once: true });
81
+ }
82
+
83
+ function endReveal() {
84
+ revealing.value = false;
85
+ document.removeEventListener("pointerup", endReveal);
86
+ document.removeEventListener("pointercancel", endReveal);
87
+ }
88
+
89
+ const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
90
+ const ROWS = 3;
91
+ const GAP = 8;
92
+ const DOT_R = 2.2;
93
+ const SIGMA = 2.8;
94
+ const R_SPEED = 0.22;
95
+ const R_WIDTH = 1.3;
96
+ const R_BOOST = 0.7;
97
+ const PEAK_SPEED = 0.02;
98
+
99
+ let COLS = 11;
100
+ let dists: number[][] = [];
101
+ let MAX_D = 1;
102
+ let rgb: [number, number, number] = [88, 166, 255];
103
+
104
+ function rebuildGrid(cols: number) {
105
+ if (cols < 3) cols = 3;
106
+ if (cols % 2 === 0) cols--;
107
+ COLS = cols;
108
+ const cc = (COLS - 1) / 2;
109
+ const cr = (ROWS - 1) / 2;
110
+ dists = [];
111
+ for (let r = 0; r < ROWS; r++) {
112
+ dists[r] = [];
113
+ for (let c = 0; c < COLS; c++) {
114
+ const dx = c - cc,
115
+ dy = r - cr;
116
+ dists[r][c] = Math.sqrt(dx * dx + dy * dy);
117
+ }
118
+ }
119
+ MAX_D = Math.sqrt(cc * cc + cr * cr);
120
+ }
121
+
122
+ rebuildGrid(11);
123
+
124
+ const ripples: Ripple[] = [];
125
+ let rafId: number | null = null;
126
+ let ro: ResizeObserver | null = null;
127
+
128
+ function syncColor() {
129
+ try {
130
+ const raw = getComputedStyle(document.documentElement)
131
+ .getPropertyValue("--hi-color-primary-rgb")
132
+ .trim();
133
+ if (!raw) {
134
+ const hex = getComputedStyle(document.documentElement)
135
+ .getPropertyValue("--hi-color-primary")
136
+ .trim();
137
+ if (hex.startsWith("#")) {
138
+ rgb = [
139
+ parseInt(hex.slice(1, 3), 16),
140
+ parseInt(hex.slice(3, 5), 16),
141
+ parseInt(hex.slice(5, 7), 16),
142
+ ];
143
+ return;
144
+ }
145
+ const ns = hex.split(/[\s,\(\)]+/).map(Number).filter((n) => !isNaN(n));
146
+ if (ns.length >= 3) rgb = [ns[0], ns[1], ns[2]];
147
+ return;
148
+ }
149
+ const ns = raw.split(/\s+/).map(Number);
150
+ if (ns.length >= 3 && ns.every((n) => !isNaN(n)))
151
+ rgb = [ns[0], ns[1], ns[2]];
152
+ } catch {
153
+ // ignore
154
+ }
155
+ }
156
+
157
+ function resize() {
158
+ const cv = dotCanvasRef.value;
159
+ const bx = boxRef.value;
160
+ if (!cv || !bx) return;
161
+ const { width, height } = bx.getBoundingClientRect();
162
+ cv.width = width * dpr;
163
+ cv.height = height * dpr;
164
+ const usable = width * 0.8;
165
+ const cols = Math.max(3, Math.floor(usable / GAP) + 1);
166
+ rebuildGrid(cols);
167
+ }
168
+
169
+ function draw() {
170
+ const cv = dotCanvasRef.value;
171
+ if (!cv) return;
172
+ const ctx = cv.getContext("2d");
173
+ if (!ctx) return;
174
+ const W = cv.width,
175
+ H = cv.height;
176
+ ctx.clearRect(0, 0, W, H);
177
+
178
+ if (revealing.value) return;
179
+
180
+ const [pr, pg, pb] = rgb;
181
+ const hasVal = !!props.modelValue;
182
+ const foc = focused.value;
183
+
184
+ const gW = (COLS - 1) * GAP;
185
+ const gH = (ROWS - 1) * GAP;
186
+ const aW = W / dpr;
187
+ const aH = H / dpr;
188
+ const ox = (aW - gW) / 2;
189
+ const oy = (aH - gH) / 2;
190
+
191
+ const emptyBase = foc ? 0.18 : 0.08;
192
+ const filledResting = foc ? 0.55 : 0.35;
193
+
194
+ const totalPeak = ripples.reduce((s, rp) => s + rp.peak, 0);
195
+
196
+ for (let r = 0; r < ROWS; r++) {
197
+ for (let c = 0; c < COLS; c++) {
198
+ const d = dists[r][c];
199
+ let a: number;
200
+ if (!hasVal) {
201
+ a = emptyBase;
202
+ } else {
203
+ const radial = Math.exp(-(d * d) / (2 * SIGMA * SIGMA));
204
+ const rest = radial * filledResting;
205
+ const peak = radial * totalPeak;
206
+ a = Math.min(1, rest + peak);
207
+ }
208
+ for (let ri = 0; ri < ripples.length; ri++) {
209
+ const rr = ripples[ri].radius;
210
+ a = Math.min(
211
+ 1,
212
+ a + Math.max(0, 1 - Math.abs(d - rr) / R_WIDTH) * R_BOOST,
213
+ );
214
+ }
215
+ ctx.beginPath();
216
+ ctx.arc(
217
+ (ox + c * GAP) * dpr,
218
+ (oy + r * GAP) * dpr,
219
+ Math.max(0.5, DOT_R * dpr),
220
+ 0,
221
+ Math.PI * 2,
222
+ );
223
+ ctx.fillStyle = `rgba(${pr},${pg},${pb},${a.toFixed(3)})`;
224
+ ctx.fill();
225
+ }
226
+ }
227
+
228
+ for (let i = ripples.length - 1; i >= 0; i--) {
229
+ const rp = ripples[i];
230
+ rp.radius += R_SPEED;
231
+ rp.peak = Math.max(0, rp.peak - PEAK_SPEED);
232
+ if (rp.radius > MAX_D + R_WIDTH + 0.5 && rp.peak <= 0) {
233
+ ripples.splice(i, 1);
234
+ }
235
+ }
236
+ }
237
+
238
+ let running = false;
239
+
240
+ function loop() {
241
+ draw();
242
+ rafId = requestAnimationFrame(loop);
243
+ }
244
+
245
+ function startLoop() {
246
+ if (running) return;
247
+ running = true;
248
+ loop();
249
+ }
250
+
251
+ function stopLoop() {
252
+ running = false;
253
+ if (rafId != null) {
254
+ cancelAnimationFrame(rafId);
255
+ rafId = null;
256
+ }
257
+ }
258
+
259
+ function kickRipple() {
260
+ ripples.push({ radius: 0, peak: 1 });
261
+ }
262
+
263
+ function clearAndFocus() {
264
+ if (props.disabled || props.readonly) return;
265
+ emit("update:modelValue", "");
266
+ inputRef.value?.focus();
267
+ }
268
+
269
+ function flash() {
270
+ const el = boxRef.value;
271
+ if (!el) return;
272
+ el.removeAttribute("data-flash");
273
+ void el.offsetWidth;
274
+ el.setAttribute("data-flash", "");
275
+ setTimeout(() => el.removeAttribute("data-flash"), 320);
276
+ kickRipple();
277
+ }
278
+
279
+ function checkSelection() {
280
+ const el = inputRef.value;
281
+ if (!el || !el.value) {
282
+ allSelected.value = false;
283
+ return;
284
+ }
285
+ allSelected.value =
286
+ el.selectionStart === 0 && el.selectionEnd === el.value.length;
287
+ }
288
+
289
+ const FW_RE = /[\uFF01-\uFF5E\u3000]/;
290
+
291
+ function onInput(e: Event) {
292
+ const t = e.target as HTMLInputElement;
293
+ if (composing.value) return;
294
+ const v = t.value;
295
+ if (FW_RE.test(v)) {
296
+ const clean = v.replace(FW_RE, "");
297
+ t.value = clean;
298
+ emit("update:modelValue", clean);
299
+ fullWidthPaused.value = true;
300
+ allSelected.value = false;
301
+ return;
302
+ }
303
+ fullWidthPaused.value = false;
304
+ allSelected.value = false;
305
+ emit("update:modelValue", v);
306
+ flash();
307
+ }
308
+
309
+ function onKeydown(e: KeyboardEvent) {
310
+ if (e.getModifierState) capsLock.value = e.getModifierState("CapsLock");
311
+ if (e.ctrlKey || e.metaKey) {
312
+ requestAnimationFrame(() => checkSelection());
313
+ }
314
+ emit("keydown", e);
315
+ }
316
+
317
+ function onKeyup(e: KeyboardEvent) {
318
+ if (e.getModifierState) capsLock.value = e.getModifierState("CapsLock");
319
+ checkSelection();
320
+ }
321
+
322
+ function onFocus(e: FocusEvent) {
323
+ focused.value = true;
324
+ if (props.modelValue && !props.readonly) {
325
+ emit("update:modelValue", "");
326
+ if (inputRef.value) inputRef.value.value = "";
327
+ kickRipple();
328
+ } else {
329
+ checkAutofill();
330
+ }
331
+ emit("focus", e);
332
+ }
333
+
334
+ function onBlur(e: FocusEvent) {
335
+ focused.value = false;
336
+ capsLock.value = false;
337
+ fullWidthPaused.value = false;
338
+ allSelected.value = false;
339
+ checkAutofill();
340
+ emit("blur", e);
341
+ }
342
+
343
+ function checkAutofill() {
344
+ const el = inputRef.value;
345
+ if (!el) return;
346
+ if (el.value && !props.modelValue) {
347
+ emit("update:modelValue", el.value);
348
+ flash();
349
+ }
350
+ }
351
+
352
+ function onCompositionStart() {
353
+ composing.value = true;
354
+ preComposeValue.value = inputRef.value?.value ?? "";
355
+ fullWidthPaused.value = true;
356
+ }
357
+
358
+ function onCompositionEnd() {
359
+ composing.value = false;
360
+ const v = inputRef.value?.value ?? "";
361
+ if (FW_RE.test(v.slice(preComposeValue.value.length))) {
362
+ if (inputRef.value) inputRef.value.value = preComposeValue.value;
363
+ emit("update:modelValue", preComposeValue.value);
364
+ fullWidthPaused.value = true;
365
+ allSelected.value = false;
366
+ return;
367
+ }
368
+ fullWidthPaused.value = false;
369
+ allSelected.value = false;
370
+ emit("update:modelValue", v);
371
+ flash();
372
+ }
373
+
374
+ function onSelect() {
375
+ checkSelection();
376
+ }
377
+
378
+ function onAutofillAnim(_e: AnimationEvent) {
379
+ const el = inputRef.value;
380
+ if (!el) return;
381
+ if (el.value && el.value !== props.modelValue) {
382
+ emit("update:modelValue", el.value);
383
+ flash();
384
+ }
385
+ }
386
+
387
+ function onPointerup() {
388
+ requestAnimationFrame(() => checkSelection());
389
+ }
390
+
391
+ let autofillInterval: ReturnType<typeof setInterval> | null = null;
392
+
393
+ watch([() => props.modelValue, focused, revealing], () => {
394
+ // kick a draw on state change
395
+ });
396
+
397
+ onMounted(() => {
398
+ syncColor();
399
+ resize();
400
+ ro = new ResizeObserver(resize);
401
+ if (boxRef.value) ro.observe(boxRef.value);
402
+ startLoop();
403
+ autofillInterval = setInterval(() => {
404
+ if (!focused.value) checkAutofill();
405
+ }, 500);
406
+ });
407
+
408
+ onUnmounted(() => {
409
+ stopLoop();
410
+ if (autofillInterval) clearInterval(autofillInterval);
411
+ if (ro) ro.disconnect();
412
+ endReveal();
413
+ });
414
+
415
+ return () => (
416
+ <div class="hk-pwd-wrapper">
417
+ {props.label ? (
418
+ <label class="hk-pwd-label">
419
+ {props.label}
420
+ {props.required ? <span class="hk-pwd-required">*</span> : null}
421
+ </label>
422
+ ) : null}
423
+ <div
424
+ ref={boxRef}
425
+ class="hk-pwd-box"
426
+ data-focused={focused.value || undefined}
427
+ data-error={props.error || undefined}
428
+ data-disabled={props.disabled || undefined}
429
+ data-fw={fullWidthPaused.value || undefined}
430
+ >
431
+ <div
432
+ class={[
433
+ "hk-pwd-lock",
434
+ props.modelValue ? "hk-pwd-lock-filled" : "hk-pwd-lock-empty",
435
+ ]}
436
+ data-revealing={revealing.value || undefined}
437
+ onPointerdown={(e: PointerEvent) => {
438
+ e.preventDefault();
439
+ startReveal();
440
+ }}
441
+ >
442
+ <svg
443
+ viewBox="0 0 24 24"
444
+ fill="none"
445
+ stroke="currentColor"
446
+ stroke-width="2"
447
+ stroke-linecap="round"
448
+ stroke-linejoin="round"
449
+ width="16"
450
+ height="16"
451
+ >
452
+ <rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
453
+ <path d="M7 11V7a5 5 0 0 1 10 0v4" />
454
+ </svg>
455
+ </div>
456
+ <canvas ref={dotCanvasRef} class="hk-pwd-dots" />
457
+ {!props.modelValue && !revealing.value ? (
458
+ <span class="hk-pwd-placeholder">{props.placeholder}</span>
459
+ ) : null}
460
+ {props.modelValue && !focused.value && !revealing.value ? (
461
+ <span
462
+ class="hk-pwd-blur-hint"
463
+ onPointerdown={(e: PointerEvent) => {
464
+ e.preventDefault();
465
+ clearAndFocus();
466
+ }}
467
+ >
468
+ {props.passwordEnteredText}
469
+ </span>
470
+ ) : null}
471
+ {focused.value && allSelected.value ? (
472
+ <span class="hk-pwd-select-hint">{props.allSelectedText}</span>
473
+ ) : null}
474
+ {revealing.value ? (
475
+ <span class="hk-pwd-reveal-text">{props.modelValue}</span>
476
+ ) : null}
477
+ <input
478
+ ref={inputRef}
479
+ type="password"
480
+ value={props.modelValue}
481
+ name={props.name}
482
+ autocomplete={props.autocomplete ?? "off"}
483
+ data-1p-ignore
484
+ data-lpignore="true"
485
+ disabled={props.disabled}
486
+ readonly={props.readonly}
487
+ required={props.required}
488
+ class="hk-pwd-input"
489
+ onInput={onInput}
490
+ onFocus={onFocus}
491
+ onBlur={onBlur}
492
+ onKeydown={onKeydown}
493
+ onKeyup={onKeyup}
494
+ onSelect={onSelect}
495
+ onPointerup={onPointerup}
496
+ onCompositionstart={onCompositionStart}
497
+ onCompositionend={onCompositionEnd}
498
+ onAnimationstart={onAutofillAnim}
499
+ />
500
+ {level.value ? (
501
+ <span
502
+ class="hk-pwd-strength"
503
+ data-level={level.value}
504
+ title={levelLabel.value}
505
+ aria-label={levelLabel.value}
506
+ />
507
+ ) : null}
508
+ </div>
509
+ <div class="hk-pwd-hints">
510
+ <HListTransition tag="div">
511
+ {capsLock.value ? (
512
+ <span key="caps" class="hk-pwd-hint" data-variant="caps">
513
+ {props.capsLockText}
514
+ </span>
515
+ ) : null}
516
+ </HListTransition>
517
+ <HListTransition tag="div">
518
+ {fullWidthPaused.value ? (
519
+ <span key="fw" class="hk-pwd-hint" data-variant="fw">
520
+ {props.fullWidthWarningText}
521
+ </span>
522
+ ) : null}
523
+ </HListTransition>
524
+ </div>
525
+ {props.error ? (
526
+ <p class="hk-pwd-error">{props.error}</p>
527
+ ) : props.hint ? (
528
+ <p class="hk-pwd-hint-text">{props.hint}</p>
529
+ ) : null}
530
+ </div>
531
+ );
532
+ },
533
+ });
@@ -0,0 +1,25 @@
1
+ .hk-phase-enter-active {
2
+ transition:
3
+ opacity var(--hi-duration-fast, 0.15s) cubic-bezier(0.16, 1, 0.3, 1),
4
+ transform var(--hi-duration-fast, 0.15s) cubic-bezier(0.16, 1, 0.3, 1);
5
+ }
6
+
7
+ .hk-phase-leave-active {
8
+ transition:
9
+ opacity var(--hi-duration-fast, 0.15s) cubic-bezier(0.5, 0, 0.75, 0),
10
+ transform var(--hi-duration-fast, 0.15s) cubic-bezier(0.5, 0, 0.75, 0);
11
+ }
12
+
13
+ .hk-phase-enter-from {
14
+ opacity: 0;
15
+ transform: translateY(8px);
16
+ }
17
+
18
+ .hk-phase-leave-to {
19
+ opacity: 0;
20
+ transform: translateY(-8px);
21
+ }
22
+
23
+ .hk-phase-content {
24
+ width: 100%;
25
+ }
@@ -0,0 +1,40 @@
1
+ import { defineComponent, Transition, type PropType, type VNode } from "vue";
2
+
3
+ import "./HkPhaseTransition.scss";
4
+
5
+ export interface PhaseState {
6
+ type: string;
7
+ [key: string]: unknown;
8
+ }
9
+
10
+ export default defineComponent({
11
+ name: "HkPhaseTransition",
12
+ props: {
13
+ state: {
14
+ type: Object as PropType<PhaseState>,
15
+ required: true,
16
+ },
17
+ },
18
+ setup(props, { slots }) {
19
+ return () => {
20
+ const state = props.state;
21
+ const slotFn = slots[state.type];
22
+ if (!slotFn) return null;
23
+
24
+ const vnode = slotFn(state);
25
+ const key = state.type + JSON.stringify(
26
+ Object.entries(state)
27
+ .filter(([k]) => k !== "type")
28
+ .map(([k, v]) => `${k}:${String(v)}`),
29
+ );
30
+
31
+ return (
32
+ <Transition name="hk-phase" mode="out-in" appear>
33
+ <div key={key} class="hk-phase-content">
34
+ {vnode}
35
+ </div>
36
+ </Transition>
37
+ );
38
+ };
39
+ },
40
+ });
@@ -0,0 +1,82 @@
1
+ .hk-popover-backdrop {
2
+ position: fixed;
3
+ inset: 0;
4
+ pointer-events: none;
5
+ }
6
+
7
+ .hk-popover-panel {
8
+ min-width: 0;
9
+ max-height: min(70vh, calc(100vh - 2 * 8px));
10
+ }
11
+
12
+ .hk-popover-enter-active {
13
+ transition:
14
+ opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1),
15
+ transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
16
+ }
17
+
18
+ .hk-popover-leave-active {
19
+ transition:
20
+ opacity 0.15s cubic-bezier(0.4, 0, 1, 1),
21
+ transform 0.15s cubic-bezier(0.4, 0, 1, 1);
22
+ }
23
+
24
+ .hk-popover-enter-from {
25
+ opacity: 0;
26
+ transform: translateY(-4px) scale(0.97);
27
+ }
28
+
29
+ .hk-popover-leave-to {
30
+ opacity: 0;
31
+ transform: translateY(4px) scale(0.97);
32
+ }
33
+
34
+ /* Glass dropdown content — used when `glass` prop is true */
35
+ .hii-dropdown-content,
36
+ .hk-popover-panel.hii-dropdown-content {
37
+ background: rgb(var(--color-surface));
38
+ backdrop-filter: blur(var(--blur-lg)) saturate(1.2);
39
+ border: 1px solid rgb(var(--color-border) / 20%);
40
+ border-radius: var(--radius-sm);
41
+ box-shadow: var(--shadow-dropdown);
42
+ padding: var(--space-4, 12px);
43
+ }
44
+
45
+ /* Locale picker menu items */
46
+ .hk-popup-menu-item {
47
+ display: flex;
48
+ align-items: center;
49
+ gap: var(--space-8);
50
+ padding: var(--space-8) var(--space-14);
51
+ font-size: var(--text-sm);
52
+ font-weight: 500;
53
+ font-family: inherit;
54
+ color: rgb(var(--color-text));
55
+ cursor: pointer;
56
+ transition: background var(--duration-normal) ease;
57
+ border: none;
58
+ background: none;
59
+ width: 100%;
60
+ text-align: left;
61
+ outline: none;
62
+ border-radius: var(--radius-sm);
63
+ }
64
+
65
+ .hk-popup-menu-item:hover {
66
+ background: var(--c-primary-subtle);
67
+ }
68
+
69
+ .hk-popup-menu-item[data-active] {
70
+ color: rgb(var(--color-primary));
71
+ font-weight: 600;
72
+ }
73
+
74
+ .hk-locale-submenu {
75
+ min-width: 140px;
76
+ padding: var(--space-6);
77
+ }
78
+
79
+ .hk-locale-flag {
80
+ font-size: var(--text-base);
81
+ line-height: 1;
82
+ }