@dorsk/tsumikit 0.55.0 → 0.57.0
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/dist/components/atoms/Input.svelte +8 -1
- package/dist/components/atoms/Select.svelte +11 -1
- package/dist/components/atoms/Textarea.svelte +8 -1
- package/dist/components/molecules/FilterInput.svelte +66 -28
- package/dist/components/molecules/FilterInput.svelte.d.ts +13 -3
- package/package.json +1 -1
|
@@ -155,7 +155,14 @@
|
|
|
155
155
|
.input-lg {
|
|
156
156
|
min-height: var(--input-size, var(--control-height-large));
|
|
157
157
|
padding: var(--sp-3) var(--sp-4);
|
|
158
|
-
font-size: var(--fs-
|
|
158
|
+
font-size: max(16px, var(--fs-md));
|
|
159
|
+
}
|
|
160
|
+
/* iOS auto-zooms any field under 16px on focus; on touch the size modifiers
|
|
161
|
+
carry their difference through padding and height alone. */
|
|
162
|
+
@media (pointer: coarse) {
|
|
163
|
+
.input-sm {
|
|
164
|
+
font-size: max(16px, var(--fs-sm));
|
|
165
|
+
}
|
|
159
166
|
}
|
|
160
167
|
.input-grow {
|
|
161
168
|
flex: 1 1 0;
|
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
.select.select-lg {
|
|
229
229
|
min-height: var(--select-size, var(--control-height-large));
|
|
230
230
|
padding: var(--sp-3) var(--sp-4);
|
|
231
|
-
font-size: var(--fs-
|
|
231
|
+
font-size: max(16px, var(--fs-md));
|
|
232
232
|
}
|
|
233
233
|
.select.compact {
|
|
234
234
|
padding: var(--sp-1) var(--sp-2);
|
|
@@ -296,6 +296,16 @@
|
|
|
296
296
|
.select-wrap.no-chevron .select-face.compact {
|
|
297
297
|
padding-right: var(--sp-2);
|
|
298
298
|
}
|
|
299
|
+
/* iOS auto-zooms any field under 16px on focus; on touch the size modifiers
|
|
300
|
+
carry their difference through padding and height alone. */
|
|
301
|
+
@media (pointer: coarse) {
|
|
302
|
+
.select.compact {
|
|
303
|
+
font-size: max(16px, var(--fs-xs));
|
|
304
|
+
}
|
|
305
|
+
.select-face.compact {
|
|
306
|
+
font-size: max(16px, var(--fs-xs));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
299
309
|
.select:disabled ~ .select-face {
|
|
300
310
|
color: var(--text-muted);
|
|
301
311
|
}
|
|
@@ -254,9 +254,16 @@
|
|
|
254
254
|
}
|
|
255
255
|
.textarea-lg {
|
|
256
256
|
padding: var(--sp-3) var(--sp-4);
|
|
257
|
-
font-size: var(--fs-
|
|
257
|
+
font-size: max(16px, var(--fs-md));
|
|
258
258
|
min-height: var(--textarea-size, var(--control-height-large));
|
|
259
259
|
}
|
|
260
|
+
/* iOS auto-zooms any field under 16px on focus; on touch the size modifiers
|
|
261
|
+
carry their difference through padding and height alone. */
|
|
262
|
+
@media (pointer: coarse) {
|
|
263
|
+
.textarea-sm {
|
|
264
|
+
font-size: max(16px, var(--fs-sm));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
260
267
|
.textarea[aria-invalid='true'],
|
|
261
268
|
.textarea[aria-invalid='true']:focus {
|
|
262
269
|
border-color: var(--danger);
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import type { FilterNode, Query } from '../../query/ast';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* The reactive parse context handed to the `inline` and `below`
|
|
6
|
-
* host can render arbitrary Svelte nodes (badges, custom
|
|
7
|
-
*
|
|
5
|
+
* The reactive parse context handed to the `inline`, `display` and `below`
|
|
6
|
+
* snippets so a host can render arbitrary Svelte nodes (badges, custom
|
|
7
|
+
* components, chips) inside the bar, over the input or below it — all
|
|
8
|
+
* derived from the same value.
|
|
8
9
|
*/
|
|
9
10
|
export interface FilterInputContext {
|
|
10
11
|
/** The parsed AST for the current value. */
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
onchange,
|
|
69
70
|
onsubmit,
|
|
70
71
|
inline,
|
|
72
|
+
display,
|
|
71
73
|
below,
|
|
72
74
|
class: klass = '',
|
|
73
75
|
style: styleProp = '',
|
|
@@ -124,6 +126,15 @@
|
|
|
124
126
|
* inline (no below-bar chips). Receives the reactive parse context.
|
|
125
127
|
*/
|
|
126
128
|
inline?: Snippet<[FilterInputContext]>;
|
|
129
|
+
/**
|
|
130
|
+
* Rendering of the value shown over the input while the field is blurred
|
|
131
|
+
* and non-empty — a compact path, a formatted timestamp, a resolved id.
|
|
132
|
+
* Focusing the input (click, Tab, `hotkey`, `context.focus()`) reveals the
|
|
133
|
+
* raw text again. It is decoration, never a control: the overlay is
|
|
134
|
+
* `aria-hidden`, takes no pointer events and adds no tab stop, so the
|
|
135
|
+
* input stays the single focus target.
|
|
136
|
+
*/
|
|
137
|
+
display?: Snippet<[FilterInputContext]>;
|
|
127
138
|
/**
|
|
128
139
|
* Content rendered below the bar (e.g. removable chips). FilterSearchBar
|
|
129
140
|
* passes its chip row here; single-field hosts simply omit it.
|
|
@@ -181,6 +192,8 @@
|
|
|
181
192
|
focus: () => el?.focus()
|
|
182
193
|
});
|
|
183
194
|
|
|
195
|
+
const showDisplay = $derived(!!display && !focused && !!value);
|
|
196
|
+
|
|
184
197
|
// Emit the AST whenever the parse result changes.
|
|
185
198
|
$effect(() => {
|
|
186
199
|
onchange?.(ast, value);
|
|
@@ -352,31 +365,37 @@
|
|
|
352
365
|
<div class="fi__bar">
|
|
353
366
|
{#if icon}<span class="fi__icon"><Icon name={icon} label="Search" /></span>{/if}
|
|
354
367
|
{#if inline}{@render inline(ctx)}{/if}
|
|
355
|
-
<
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
368
|
+
<span class="fi__field">
|
|
369
|
+
<input
|
|
370
|
+
bind:this={el}
|
|
371
|
+
bind:value
|
|
372
|
+
class="fi__input"
|
|
373
|
+
class:fi__input--masked={showDisplay}
|
|
374
|
+
id={id ?? field?.id}
|
|
375
|
+
aria-describedby={ariaDescribedby ?? field?.describedBy}
|
|
376
|
+
aria-invalid={ariaInvalid ?? (field?.invalid ? 'true' : undefined)}
|
|
377
|
+
spellcheck="false"
|
|
378
|
+
autocomplete="off"
|
|
379
|
+
placeholder={hint}
|
|
380
|
+
{oninput}
|
|
381
|
+
onclick={refresh}
|
|
382
|
+
onkeyup={(e) => {
|
|
383
|
+
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') refresh();
|
|
384
|
+
}}
|
|
385
|
+
onfocus={() => {
|
|
386
|
+
focused = true;
|
|
387
|
+
refresh();
|
|
388
|
+
}}
|
|
389
|
+
onblur={() => {
|
|
390
|
+
focused = false;
|
|
391
|
+
setTimeout(() => (open = false), 120);
|
|
392
|
+
}}
|
|
393
|
+
{onkeydown}
|
|
394
|
+
/>
|
|
395
|
+
{#if display && showDisplay}
|
|
396
|
+
<span class="fi__display" aria-hidden="true">{@render display(ctx)}</span>
|
|
397
|
+
{/if}
|
|
398
|
+
</span>
|
|
380
399
|
{#if showHotkey && hotkey && !focused && !value}
|
|
381
400
|
<kbd class="fi__kbd" aria-hidden="true">{hotkey}</kbd>
|
|
382
401
|
{/if}
|
|
@@ -479,6 +498,22 @@
|
|
|
479
498
|
display: flex;
|
|
480
499
|
color: var(--text-faint);
|
|
481
500
|
}
|
|
501
|
+
.fi__field {
|
|
502
|
+
position: relative;
|
|
503
|
+
display: flex;
|
|
504
|
+
flex: 1;
|
|
505
|
+
min-width: 0;
|
|
506
|
+
}
|
|
507
|
+
.fi__display {
|
|
508
|
+
position: absolute;
|
|
509
|
+
inset: 0;
|
|
510
|
+
display: flex;
|
|
511
|
+
align-items: center;
|
|
512
|
+
gap: var(--sp-2);
|
|
513
|
+
min-width: 0;
|
|
514
|
+
overflow: hidden;
|
|
515
|
+
pointer-events: none;
|
|
516
|
+
}
|
|
482
517
|
.fi__input {
|
|
483
518
|
flex: 1;
|
|
484
519
|
border: 0;
|
|
@@ -492,6 +527,9 @@
|
|
|
492
527
|
.fi__input::placeholder {
|
|
493
528
|
color: var(--text-faint);
|
|
494
529
|
}
|
|
530
|
+
.fi__input--masked {
|
|
531
|
+
color: transparent;
|
|
532
|
+
}
|
|
495
533
|
.fi__clear {
|
|
496
534
|
display: flex;
|
|
497
535
|
border: 0;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { FilterNode, Query } from '../../query/ast';
|
|
2
2
|
/**
|
|
3
|
-
* The reactive parse context handed to the `inline` and `below`
|
|
4
|
-
* host can render arbitrary Svelte nodes (badges, custom
|
|
5
|
-
*
|
|
3
|
+
* The reactive parse context handed to the `inline`, `display` and `below`
|
|
4
|
+
* snippets so a host can render arbitrary Svelte nodes (badges, custom
|
|
5
|
+
* components, chips) inside the bar, over the input or below it — all
|
|
6
|
+
* derived from the same value.
|
|
6
7
|
*/
|
|
7
8
|
export interface FilterInputContext {
|
|
8
9
|
/** The parsed AST for the current value. */
|
|
@@ -73,6 +74,15 @@ type Own = {
|
|
|
73
74
|
* inline (no below-bar chips). Receives the reactive parse context.
|
|
74
75
|
*/
|
|
75
76
|
inline?: Snippet<[FilterInputContext]>;
|
|
77
|
+
/**
|
|
78
|
+
* Rendering of the value shown over the input while the field is blurred
|
|
79
|
+
* and non-empty — a compact path, a formatted timestamp, a resolved id.
|
|
80
|
+
* Focusing the input (click, Tab, `hotkey`, `context.focus()`) reveals the
|
|
81
|
+
* raw text again. It is decoration, never a control: the overlay is
|
|
82
|
+
* `aria-hidden`, takes no pointer events and adds no tab stop, so the
|
|
83
|
+
* input stays the single focus target.
|
|
84
|
+
*/
|
|
85
|
+
display?: Snippet<[FilterInputContext]>;
|
|
76
86
|
/**
|
|
77
87
|
* Content rendered below the bar (e.g. removable chips). FilterSearchBar
|
|
78
88
|
* passes its chip row here; single-field hosts simply omit it.
|
package/package.json
CHANGED