@celestia-island/hikari 0.40.6 → 0.40.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celestia-island/hikari",
3
- "version": "0.40.6",
3
+ "version": "0.40.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Hikari Vue 3 component library — production-grade UI components based on shittim-chest design system",
package/src/DemoApp.tsx CHANGED
@@ -8,6 +8,8 @@ import {
8
8
  HButton, HIconButton, HTooltip, HBadge, HTag, HIcon, HSpinner,
9
9
  HProgressBar, HProgressRing, HGaugeRing,
10
10
  HInput, HSearchInput, HNumberInput, HPasswordInput, HTextarea,
11
+ HFileField,
12
+ type PickedFile, type RemoteFsAdapter,
11
13
  HCheckbox, HSwitch, HRadio, HSelect, HSelectPanel,
12
14
  HLocalizedInput,
13
15
  HSkeleton, HSkeletonList, HAvatar, HKbd, HDivider,
@@ -98,6 +100,28 @@ export default defineComponent({
98
100
  name: "DemoApp",
99
101
  setup() {
100
102
  const form = ref({ text: "", search: "", number: 0, password: "", textarea: "" });
103
+ const localFiles = ref<PickedFile[]>([]);
104
+ const remoteFiles = ref<PickedFile[]>([]);
105
+ // In-memory remote FS so the remote picker demo browses something real.
106
+ const demoRemoteFs: RemoteFsAdapter = (() => {
107
+ const tree: Record<string, { name: string; kind: "file" | "dir"; size?: number }[]> = {
108
+ "/": [
109
+ { name: "data", kind: "dir" },
110
+ { name: "reports", kind: "dir" },
111
+ { name: "readme.md", kind: "file", size: 1200 },
112
+ ],
113
+ "/data": [
114
+ { name: "stations.csv", kind: "file", size: 20480 },
115
+ { name: "sensors.json", kind: "file", size: 860 },
116
+ ],
117
+ "/reports": [{ name: "2026-Q3.pdf", kind: "file", size: 409600 }],
118
+ };
119
+ return {
120
+ async list(path: string) {
121
+ return { path, entries: tree[path] ?? [] };
122
+ },
123
+ };
124
+ })();
101
125
  const anyForm = computed(() =>
102
126
  Object.values(form.value).filter((v) => v !== "" && v !== 0).join(", ") || null,
103
127
  );
@@ -267,6 +291,32 @@ export default defineComponent({
267
291
  {anyForm.value ? <p class="result">Form: {anyForm.value}</p> : null}
268
292
  </section>
269
293
 
294
+ <section>
295
+ <h2>HFileField / HFileBrowserDialog</h2>
296
+ <div class="form-grid">
297
+ <HFileField
298
+ modelValue={localFiles.value}
299
+ onUpdate:modelValue={(v: PickedFile[]) => (localFiles.value = v)}
300
+ label="Local file"
301
+ multiple
302
+ accept=".csv,.json,.txt"
303
+ />
304
+ <HFileField
305
+ modelValue={remoteFiles.value}
306
+ onUpdate:modelValue={(v: PickedFile[]) => (remoteFiles.value = v)}
307
+ mode="remote"
308
+ label="Remote file"
309
+ adapter={demoRemoteFs}
310
+ quickLinks={[{ label: "Root", path: "/" }, { label: "Data", path: "/data" }]}
311
+ />
312
+ </div>
313
+ {localFiles.value.length + remoteFiles.value.length > 0 ? (
314
+ <p class="result">
315
+ Picked: {[...localFiles.value, ...remoteFiles.value].map((f) => f.name).join(", ")}
316
+ </p>
317
+ ) : null}
318
+ </section>
319
+
270
320
  <section>
271
321
  <h2>HCheckbox / HSwitch / HRadio</h2>
272
322
  <div class="row">
@@ -0,0 +1,530 @@
1
+ @use "../tokens";
2
+
3
+ // HkFileBrowserDialog.scss
4
+ // Remote file-browser picker dialog body (rendered inside an HModal):
5
+ // breadcrumb path bar, quick-link chips, clipboard/rename toolbar,
6
+ // list/grid entries area and the footer form/actions stack.
7
+ //
8
+ // Token-driven like the rest of the library — rgb(var(--color-*)) +
9
+ // the --c-*/--border-*/--space-*/--text-* aliases from tokens.scss — so
10
+ // the surface follows light/dark themes without literal colors
11
+ // (same tone as HkSelect.scss).
12
+
13
+ // ------
14
+ // Root — the HModal body content
15
+ // ------
16
+
17
+ .hk-file-browser {
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--space-12);
21
+ font-size: var(--text-base);
22
+ color: rgb(var(--color-text));
23
+ }
24
+
25
+ // ------
26
+ // Breadcrumb path bar + copy-path
27
+ // ------
28
+
29
+ .hk-file-browser-pathbar {
30
+ display: flex;
31
+ align-items: center;
32
+ gap: var(--space-8);
33
+ padding: var(--space-6) var(--space-8);
34
+ border: 1px solid var(--border-subtle);
35
+ border-radius: var(--radius-md);
36
+ background: color-mix(in srgb, rgb(var(--color-surface)) 55%, transparent);
37
+ }
38
+
39
+ .hk-file-browser-crumbs {
40
+ display: flex;
41
+ align-items: center;
42
+ flex: 1;
43
+ min-width: 0;
44
+ overflow-x: auto;
45
+ /* Overlay-scrollbar convention: native chrome hidden. */
46
+ scrollbar-width: none;
47
+
48
+ &::-webkit-scrollbar {
49
+ display: none;
50
+ }
51
+ }
52
+
53
+ .hk-file-browser-crumb {
54
+ flex-shrink: 0;
55
+ max-width: 12rem;
56
+ overflow: hidden;
57
+ text-overflow: ellipsis;
58
+ white-space: nowrap;
59
+ padding: var(--space-2) var(--space-6);
60
+ border: none;
61
+ border-radius: var(--radius-sm);
62
+ background: transparent;
63
+ font-family: inherit;
64
+ font-size: var(--text-sm);
65
+ line-height: 1.5;
66
+ color: rgb(var(--color-muted));
67
+ cursor: pointer;
68
+ transition:
69
+ background-color var(--duration-normal) var(--ease-standard),
70
+ color var(--duration-normal) var(--ease-standard);
71
+
72
+ /* "/" separators between segments (the root crumb renders its own). */
73
+ & + .hk-file-browser-crumb::before {
74
+ content: "/";
75
+ margin-right: var(--space-4);
76
+ color: color-mix(in srgb, rgb(var(--color-muted)) 60%, transparent);
77
+ }
78
+
79
+ &:hover:not([data-current]) {
80
+ background: var(--c-primary-subtle);
81
+ color: rgb(var(--color-text));
82
+ }
83
+
84
+ &:focus-visible {
85
+ outline: 2px solid rgb(var(--color-focused-border));
86
+ outline-offset: 1px;
87
+ }
88
+
89
+ &[data-current] {
90
+ color: rgb(var(--color-text));
91
+ font-weight: 600;
92
+ cursor: default;
93
+ }
94
+ }
95
+
96
+ .hk-file-browser-copy-path {
97
+ flex-shrink: 0;
98
+ display: inline-flex;
99
+ align-items: center;
100
+ justify-content: center;
101
+ width: 1.75rem;
102
+ height: 1.75rem;
103
+ padding: 0;
104
+ border: none;
105
+ border-radius: var(--radius-sm);
106
+ background: transparent;
107
+ color: rgb(var(--color-muted));
108
+ cursor: pointer;
109
+ transition:
110
+ background-color var(--duration-normal) var(--ease-standard),
111
+ color var(--duration-normal) var(--ease-standard);
112
+
113
+ &:hover {
114
+ background: var(--c-primary-subtle);
115
+ color: rgb(var(--color-text));
116
+ }
117
+
118
+ &:focus-visible {
119
+ outline: 2px solid rgb(var(--color-focused-border));
120
+ outline-offset: 1px;
121
+ }
122
+ }
123
+
124
+ // ------
125
+ // Quick-link chips
126
+ // ------
127
+
128
+ .hk-file-browser-chips {
129
+ display: flex;
130
+ align-items: center;
131
+ flex-wrap: wrap;
132
+ gap: var(--space-6);
133
+ }
134
+
135
+ .hk-file-browser-chips-label {
136
+ font-size: var(--text-xs);
137
+ font-weight: 600;
138
+ letter-spacing: 0.02em;
139
+ color: rgb(var(--color-muted));
140
+ }
141
+
142
+ .hk-file-browser-chip {
143
+ padding: var(--space-2) var(--space-10);
144
+ border: 1px solid var(--border-subtle);
145
+ border-radius: var(--radius-full, 9999px);
146
+ background: transparent;
147
+ font-family: inherit;
148
+ font-size: var(--text-xs);
149
+ line-height: 1.5;
150
+ color: rgb(var(--color-muted));
151
+ cursor: pointer;
152
+ transition:
153
+ background-color var(--duration-normal) var(--ease-standard),
154
+ border-color var(--duration-normal) var(--ease-standard),
155
+ color var(--duration-normal) var(--ease-standard);
156
+
157
+ &:hover {
158
+ border-color: var(--c-primary-strong);
159
+ color: rgb(var(--color-text));
160
+ }
161
+
162
+ &:focus-visible {
163
+ border-color: rgb(var(--color-focused-border));
164
+ box-shadow: var(--shadow-focus);
165
+ outline: none;
166
+ }
167
+
168
+ &[data-active] {
169
+ background: var(--c-primary-subtle);
170
+ border-color: var(--c-primary-medium);
171
+ color: rgb(var(--color-text));
172
+ }
173
+ }
174
+
175
+ // ------
176
+ // Toolbar — clipboard/rename ops + type filter + layout toggle
177
+ // ------
178
+
179
+ .hk-file-browser-toolbar {
180
+ display: flex;
181
+ align-items: center;
182
+ justify-content: space-between;
183
+ flex-wrap: wrap;
184
+ gap: var(--space-8);
185
+ }
186
+
187
+ .hk-file-browser-ops {
188
+ display: flex;
189
+ align-items: center;
190
+ gap: var(--space-4);
191
+ }
192
+
193
+ .hk-file-browser-tool {
194
+ display: inline-flex;
195
+ align-items: center;
196
+ justify-content: center;
197
+ width: 2rem;
198
+ height: 2rem;
199
+ padding: 0;
200
+ border: 1px solid var(--border-subtle);
201
+ border-radius: var(--radius-md);
202
+ background: color-mix(in srgb, rgb(var(--color-surface)) 55%, transparent);
203
+ color: rgb(var(--color-muted));
204
+ cursor: pointer;
205
+ transition:
206
+ background-color var(--duration-normal) var(--ease-standard),
207
+ border-color var(--duration-normal) var(--ease-standard),
208
+ color var(--duration-normal) var(--ease-standard),
209
+ opacity var(--duration-normal) var(--ease-standard);
210
+
211
+ &:hover:not(:disabled) {
212
+ border-color: var(--c-primary-strong);
213
+ color: rgb(var(--color-text));
214
+ }
215
+
216
+ &:focus-visible {
217
+ border-color: rgb(var(--color-focused-border));
218
+ box-shadow: var(--shadow-focus);
219
+ outline: none;
220
+ }
221
+
222
+ &:disabled {
223
+ opacity: 0.45;
224
+ cursor: not-allowed;
225
+ }
226
+ }
227
+
228
+ .hk-file-browser-toolbar-side {
229
+ display: flex;
230
+ align-items: center;
231
+ gap: var(--space-8);
232
+ margin-left: auto;
233
+ }
234
+
235
+ /* Compact type-filter select (HkSelect trigger inside). */
236
+ .hk-file-browser-filter {
237
+ width: 9rem;
238
+ min-width: 9rem;
239
+ }
240
+
241
+ .hk-file-browser-layout {
242
+ display: flex;
243
+ border: 1px solid var(--border-subtle);
244
+ border-radius: var(--radius-md);
245
+ overflow: hidden;
246
+ }
247
+
248
+ .hk-file-browser-layout-btn {
249
+ display: inline-flex;
250
+ align-items: center;
251
+ justify-content: center;
252
+ width: 2rem;
253
+ height: 2rem;
254
+ padding: 0;
255
+ border: none;
256
+ background: transparent;
257
+ color: rgb(var(--color-muted));
258
+ cursor: pointer;
259
+ transition:
260
+ background-color var(--duration-normal) var(--ease-standard),
261
+ color var(--duration-normal) var(--ease-standard);
262
+
263
+ & + .hk-file-browser-layout-btn {
264
+ border-left: 1px solid var(--border-subtle);
265
+ }
266
+
267
+ &:hover:not([data-active]) {
268
+ color: rgb(var(--color-text));
269
+ }
270
+
271
+ &:focus-visible {
272
+ box-shadow: var(--shadow-focus);
273
+ outline: none;
274
+ }
275
+
276
+ &[data-active] {
277
+ background: var(--c-primary-subtle);
278
+ color: rgb(var(--color-text));
279
+ }
280
+ }
281
+
282
+ // ------
283
+ // Inline rename row (opens under the toolbar — never window.prompt)
284
+ // ------
285
+
286
+ .hk-file-browser-rename {
287
+ display: flex;
288
+ align-items: center;
289
+ flex-wrap: wrap;
290
+ gap: var(--space-8);
291
+ }
292
+
293
+ .hk-file-browser-rename-label {
294
+ flex-shrink: 0;
295
+ font-size: var(--text-sm);
296
+ color: rgb(var(--color-muted));
297
+ }
298
+
299
+ .hk-file-browser-rename-input {
300
+ flex: 1;
301
+ min-width: 8rem;
302
+ padding: var(--space-8) var(--space-12);
303
+ border: 1px solid color-mix(in srgb, rgb(var(--color-text)) 14%, transparent);
304
+ border-radius: var(--radius-md);
305
+ background: color-mix(in srgb, rgb(var(--color-surface)) 55%, transparent);
306
+ font-family: inherit;
307
+ font-size: var(--text-base);
308
+ line-height: 1.5;
309
+ color: rgb(var(--color-text));
310
+ outline: none;
311
+ transition: border-color var(--duration-normal) var(--ease-standard);
312
+
313
+ &:focus {
314
+ border-color: rgb(var(--color-focused-border));
315
+ box-shadow: var(--shadow-focus);
316
+ }
317
+ }
318
+
319
+ .hk-file-browser-rename-error {
320
+ flex-basis: 100%;
321
+ font-size: var(--text-xs);
322
+ color: rgb(var(--color-error));
323
+ }
324
+
325
+ // ------
326
+ // Entries area — the list/grid body (state carries on data-layout)
327
+ // ------
328
+
329
+ .hk-file-browser-entries {
330
+ display: flex;
331
+ flex-direction: column;
332
+ min-height: 12rem;
333
+ max-height: 24rem;
334
+ overflow-y: auto;
335
+ border: 1px solid var(--border-subtle);
336
+ border-radius: var(--radius-md);
337
+ overscroll-behavior: contain;
338
+ }
339
+
340
+ .hk-file-browser-loading {
341
+ display: flex;
342
+ align-items: center;
343
+ justify-content: center;
344
+ padding: var(--space-24);
345
+ }
346
+
347
+ .hk-file-browser-empty {
348
+ display: flex;
349
+ align-items: center;
350
+ justify-content: center;
351
+ padding: var(--space-24);
352
+ font-size: var(--text-sm);
353
+ color: rgb(var(--color-muted));
354
+ }
355
+
356
+ .hk-file-browser-error {
357
+ display: flex;
358
+ align-items: center;
359
+ justify-content: space-between;
360
+ gap: var(--space-8);
361
+ margin: var(--space-8);
362
+ padding: var(--space-8) var(--space-12);
363
+ border: 1px solid var(--c-error-strong);
364
+ border-radius: var(--radius-md);
365
+ background: var(--c-error-dim);
366
+ color: rgb(var(--color-error));
367
+ font-size: var(--text-sm);
368
+ }
369
+
370
+ // List layout: table-like name/size/modified grid rows.
371
+
372
+ .hk-file-browser-list {
373
+ display: flex;
374
+ flex-direction: column;
375
+ }
376
+
377
+ .hk-file-browser-list-head,
378
+ .hk-file-browser-row {
379
+ display: grid;
380
+ grid-template-columns: minmax(0, 1fr) 6rem 10rem;
381
+ gap: var(--space-8);
382
+ align-items: center;
383
+ padding: var(--space-6) var(--space-12);
384
+ text-align: left;
385
+ }
386
+
387
+ .hk-file-browser-list-head {
388
+ position: sticky;
389
+ top: 0;
390
+ z-index: 1;
391
+ font-size: var(--text-xs);
392
+ font-weight: 600;
393
+ color: rgb(var(--color-muted));
394
+ background: rgb(var(--color-surface));
395
+ border-bottom: 1px solid var(--border-subtle);
396
+ }
397
+
398
+ .hk-file-browser-row {
399
+ width: 100%;
400
+ border: none;
401
+ border-bottom: 1px solid var(--border-faint);
402
+ background: transparent;
403
+ font-family: inherit;
404
+ font-size: var(--text-sm);
405
+ line-height: 1.5;
406
+ color: rgb(var(--color-text));
407
+ cursor: pointer;
408
+ transition: background-color var(--duration-normal) var(--ease-standard);
409
+
410
+ &:last-child {
411
+ border-bottom: none;
412
+ }
413
+
414
+ &:hover {
415
+ background: var(--c-primary-subtle);
416
+ }
417
+
418
+ &:focus-visible {
419
+ box-shadow: var(--shadow-focus);
420
+ outline: none;
421
+ }
422
+
423
+ &[data-selected] {
424
+ background: var(--c-primary-dim);
425
+ box-shadow: inset 2px 0 0 rgb(var(--color-primary));
426
+ }
427
+
428
+ &[data-kind="dir"] .hk-file-browser-col-name {
429
+ font-weight: 600;
430
+ }
431
+ }
432
+
433
+ .hk-file-browser-col-name {
434
+ overflow: hidden;
435
+ white-space: nowrap;
436
+ text-overflow: ellipsis;
437
+ }
438
+
439
+ .hk-file-browser-col-size,
440
+ .hk-file-browser-col-modified {
441
+ overflow: hidden;
442
+ white-space: nowrap;
443
+ text-overflow: ellipsis;
444
+ text-align: right;
445
+ font-size: var(--text-xs);
446
+ color: rgb(var(--color-muted));
447
+ }
448
+
449
+ // Grid layout: tile cards (the area root flips data-layout="grid").
450
+
451
+ .hk-file-browser-entries[data-layout="grid"] .hk-file-browser-grid {
452
+ display: grid;
453
+ grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
454
+ gap: var(--space-8);
455
+ padding: var(--space-8);
456
+ }
457
+
458
+ .hk-file-browser-tile {
459
+ display: flex;
460
+ flex-direction: column;
461
+ gap: var(--space-2);
462
+ min-width: 0;
463
+ padding: var(--space-8);
464
+ border: 1px solid var(--border-subtle);
465
+ border-radius: var(--radius-md);
466
+ background: transparent;
467
+ font-family: inherit;
468
+ text-align: left;
469
+ cursor: pointer;
470
+ transition:
471
+ background-color var(--duration-normal) var(--ease-standard),
472
+ border-color var(--duration-normal) var(--ease-standard);
473
+
474
+ &:hover {
475
+ border-color: var(--c-primary-medium);
476
+ }
477
+
478
+ &:focus-visible {
479
+ box-shadow: var(--shadow-focus);
480
+ outline: none;
481
+ }
482
+
483
+ &[data-selected] {
484
+ background: var(--c-primary-dim);
485
+ border-color: var(--c-primary-medium);
486
+ }
487
+
488
+ &[data-kind="dir"] .hk-file-browser-tile-name {
489
+ font-weight: 600;
490
+ }
491
+ }
492
+
493
+ .hk-file-browser-tile-name {
494
+ overflow: hidden;
495
+ white-space: nowrap;
496
+ text-overflow: ellipsis;
497
+ font-size: var(--text-sm);
498
+ color: rgb(var(--color-text));
499
+ }
500
+
501
+ .hk-file-browser-tile-meta {
502
+ overflow: hidden;
503
+ white-space: nowrap;
504
+ text-overflow: ellipsis;
505
+ font-size: var(--text-xs);
506
+ color: rgb(var(--color-muted));
507
+ }
508
+
509
+ // ------
510
+ // Footer — footerForm slot content above the action buttons
511
+ // ------
512
+
513
+ .hk-file-browser-footer {
514
+ display: flex;
515
+ flex-direction: column;
516
+ gap: var(--space-12);
517
+ width: 100%;
518
+ }
519
+
520
+ .hk-file-browser-footer-form {
521
+ display: flex;
522
+ flex-direction: column;
523
+ gap: var(--space-12);
524
+ }
525
+
526
+ .hk-file-browser-footer-actions {
527
+ display: flex;
528
+ justify-content: flex-end;
529
+ gap: var(--space-8);
530
+ }