@dorsk/tsumikit 0.76.0 → 0.78.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/Divider.svelte +2 -1
- package/dist/components/atoms/Input.svelte +1 -1
- package/dist/components/atoms/Input.svelte.d.ts +1 -1
- package/dist/components/atoms/Select.svelte +3 -0
- package/dist/components/atoms/Textarea.svelte +1 -1
- package/dist/components/atoms/Textarea.svelte.d.ts +1 -1
- package/dist/components/layouts/AppShell.svelte +1 -0
- package/dist/components/layouts/NavBar.svelte +3 -0
- package/dist/components/molecules/Callout.svelte +5 -5
- package/dist/components/molecules/ChatBubble.svelte +4 -0
- package/dist/components/molecules/CodeBlock.svelte +7 -0
- package/dist/components/molecules/CopyButton.svelte +5 -1
- package/dist/components/molecules/Field.svelte +1 -0
- package/dist/components/molecules/FileButton.svelte +7 -1
- package/dist/components/molecules/FilterInput.svelte +2 -1
- package/dist/components/molecules/RadioGroup.svelte +3 -2
- package/dist/components/molecules/RichSelect.svelte +15 -6
- package/dist/components/molecules/SelectButton.svelte +12 -1
- package/dist/components/molecules/SelectButton.svelte.d.ts +1 -0
- package/dist/components/molecules/StatusBar.svelte +2 -0
- package/dist/components/molecules/Toggle.svelte +11 -1
- package/dist/components/molecules/Truncate.svelte +21 -3
- package/dist/components/organisms/ConversationFeed.svelte +1 -0
- package/dist/components/organisms/FilterSearchBar.svelte +8 -2
- package/dist/floating.js +7 -1
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
// `size` shadows the native char-width attribute (unused in token-sized
|
|
14
14
|
// layouts) to expose a height preset instead.
|
|
15
|
-
type Props = Omit<HTMLInputAttributes, 'size'> & {
|
|
15
|
+
type Props = Omit<HTMLInputAttributes, 'size' | 'onsubmit'> & {
|
|
16
16
|
mono?: boolean;
|
|
17
17
|
size?: ControlSize;
|
|
18
18
|
/** Fill the available width of a flex/Cluster row (flex: 1) instead of
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ControlSize } from '../../size';
|
|
2
2
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
3
|
import { type IconName } from './Icon.svelte';
|
|
4
|
-
type Props = Omit<HTMLInputAttributes, 'size'> & {
|
|
4
|
+
type Props = Omit<HTMLInputAttributes, 'size' | 'onsubmit'> & {
|
|
5
5
|
mono?: boolean;
|
|
6
6
|
size?: ControlSize;
|
|
7
7
|
/** Fill the available width of a flex/Cluster row (flex: 1) instead of
|
|
@@ -199,6 +199,7 @@
|
|
|
199
199
|
.select-wrap.w-auto {
|
|
200
200
|
display: inline-block;
|
|
201
201
|
width: auto;
|
|
202
|
+
max-width: 100%;
|
|
202
203
|
}
|
|
203
204
|
.select-wrap.select-grow {
|
|
204
205
|
flex: 1 1 0;
|
|
@@ -253,6 +254,8 @@
|
|
|
253
254
|
}
|
|
254
255
|
.select.w-auto {
|
|
255
256
|
width: auto;
|
|
257
|
+
max-width: 100%;
|
|
258
|
+
text-overflow: ellipsis;
|
|
256
259
|
}
|
|
257
260
|
.select.embedded {
|
|
258
261
|
background: var(--select-bg, var(--bg-elevated-2));
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import { getFieldContext, warnUnlabelled } from '../../field-context';
|
|
24
24
|
import { getInputGroupContext } from '../../input-group-context';
|
|
25
25
|
|
|
26
|
-
type Props = HTMLTextareaAttributes & {
|
|
26
|
+
type Props = Omit<HTMLTextareaAttributes, 'onsubmit'> & {
|
|
27
27
|
mono?: boolean;
|
|
28
28
|
autoresize?: boolean;
|
|
29
29
|
size?: ControlSize;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ControlSize } from '../../size';
|
|
2
2
|
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
|
3
|
-
type Props = HTMLTextareaAttributes & {
|
|
3
|
+
type Props = Omit<HTMLTextareaAttributes, 'onsubmit'> & {
|
|
4
4
|
mono?: boolean;
|
|
5
5
|
autoresize?: boolean;
|
|
6
6
|
size?: ControlSize;
|
|
@@ -90,19 +90,19 @@
|
|
|
90
90
|
gap: var(--sp-3);
|
|
91
91
|
padding: var(--sp-3);
|
|
92
92
|
}
|
|
93
|
-
:global(.callout-ok) {
|
|
93
|
+
:global(.card.callout-ok) {
|
|
94
94
|
--callout-tone: var(--ok);
|
|
95
95
|
}
|
|
96
|
-
:global(.callout-warn) {
|
|
96
|
+
:global(.card.callout-warn) {
|
|
97
97
|
--callout-tone: var(--warn);
|
|
98
98
|
}
|
|
99
|
-
:global(.callout-danger) {
|
|
99
|
+
:global(.card.callout-danger) {
|
|
100
100
|
--callout-tone: var(--danger);
|
|
101
101
|
}
|
|
102
|
-
:global(.callout-info) {
|
|
102
|
+
:global(.card.callout-info) {
|
|
103
103
|
--callout-tone: var(--info);
|
|
104
104
|
}
|
|
105
|
-
:global(.callout-accent) {
|
|
105
|
+
:global(.card.callout-accent) {
|
|
106
106
|
--callout-tone: var(--accent);
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -180,5 +180,9 @@
|
|
|
180
180
|
-webkit-line-clamp: var(--clamp);
|
|
181
181
|
line-clamp: var(--clamp);
|
|
182
182
|
overflow: hidden;
|
|
183
|
+
padding: calc(var(--focus-ring-width) + var(--focus-ring-offset));
|
|
184
|
+
padding-block-end: 0;
|
|
185
|
+
margin: calc(-1 * (var(--focus-ring-width) + var(--focus-ring-offset)));
|
|
186
|
+
margin-block-end: 0;
|
|
183
187
|
}
|
|
184
188
|
</style>
|
|
@@ -101,8 +101,15 @@
|
|
|
101
101
|
font-family: var(--font-mono);
|
|
102
102
|
color: var(--text-muted);
|
|
103
103
|
}
|
|
104
|
+
.cb-name {
|
|
105
|
+
min-width: 0;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
text-overflow: ellipsis;
|
|
108
|
+
white-space: nowrap;
|
|
109
|
+
}
|
|
104
110
|
.cb-body {
|
|
105
111
|
display: flex;
|
|
112
|
+
align-items: flex-start;
|
|
106
113
|
overflow: auto;
|
|
107
114
|
-webkit-overflow-scrolling: touch;
|
|
108
115
|
}
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
{variant}
|
|
61
61
|
{box}
|
|
62
62
|
{hitArea}
|
|
63
|
-
class="copy-btn {klass}"
|
|
63
|
+
class="copy-btn {labelShown && box !== undefined ? 'copy-labelled' : ''} {klass}"
|
|
64
64
|
sound={false}
|
|
65
65
|
onclick={copy}
|
|
66
66
|
aria-label={copied ? copiedLabel : label}
|
|
@@ -78,6 +78,10 @@
|
|
|
78
78
|
/* Both glyphs share one grid cell so the swap never changes the width. The
|
|
79
79
|
check springs in (the kit's one bounce: a rare confirmation); the copy
|
|
80
80
|
glyph fades out fast and back in over the base duration on revert. */
|
|
81
|
+
:global(.copy-btn.btn-box.copy-labelled) {
|
|
82
|
+
width: auto;
|
|
83
|
+
padding-inline: var(--sp-2);
|
|
84
|
+
}
|
|
81
85
|
.glyphs {
|
|
82
86
|
display: inline-grid;
|
|
83
87
|
place-items: center;
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
{:else if emoji}
|
|
94
94
|
<span class="emoji" aria-hidden="true">{emoji}</span>
|
|
95
95
|
{/if}
|
|
96
|
-
<span class:sr-only={onlyIcon}>{label}</span>
|
|
96
|
+
<span class="text" class:sr-only={onlyIcon}>{label}</span>
|
|
97
97
|
</label>
|
|
98
98
|
|
|
99
99
|
<style>
|
|
@@ -114,6 +114,7 @@
|
|
|
114
114
|
font-weight: var(--fw-medium);
|
|
115
115
|
font-size: var(--control-fs-md);
|
|
116
116
|
line-height: var(--lh-none);
|
|
117
|
+
max-width: 100%;
|
|
117
118
|
white-space: nowrap;
|
|
118
119
|
cursor: pointer;
|
|
119
120
|
user-select: none;
|
|
@@ -179,6 +180,11 @@
|
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
/* An emoji reads small next to an SVG glyph of the same size: one icon tier up. */
|
|
183
|
+
.text:not(.sr-only) {
|
|
184
|
+
min-width: 0;
|
|
185
|
+
overflow: hidden;
|
|
186
|
+
text-overflow: ellipsis;
|
|
187
|
+
}
|
|
182
188
|
.emoji {
|
|
183
189
|
display: inline-flex;
|
|
184
190
|
font-size: var(--icon-lg);
|
|
@@ -467,6 +467,7 @@
|
|
|
467
467
|
.fi__bar {
|
|
468
468
|
--fi-icon: var(--control-icon-md);
|
|
469
469
|
display: flex;
|
|
470
|
+
flex-wrap: wrap;
|
|
470
471
|
align-items: center;
|
|
471
472
|
gap: var(--sp-2);
|
|
472
473
|
padding: 0 var(--control-px-md);
|
|
@@ -522,7 +523,7 @@
|
|
|
522
523
|
position: relative;
|
|
523
524
|
display: flex;
|
|
524
525
|
flex: 1;
|
|
525
|
-
min-width:
|
|
526
|
+
min-width: min(100%, 6rem);
|
|
526
527
|
}
|
|
527
528
|
.fi__display {
|
|
528
529
|
position: absolute;
|
|
@@ -219,6 +219,7 @@
|
|
|
219
219
|
|
|
220
220
|
.rows {
|
|
221
221
|
gap: var(--sp-1);
|
|
222
|
+
min-width: 0;
|
|
222
223
|
}
|
|
223
224
|
.row-wrap {
|
|
224
225
|
min-width: 0;
|
|
@@ -250,8 +251,9 @@
|
|
|
250
251
|
}
|
|
251
252
|
.label-line {
|
|
252
253
|
display: flex;
|
|
254
|
+
flex-wrap: wrap;
|
|
253
255
|
align-items: baseline;
|
|
254
|
-
gap: var(--sp-2);
|
|
256
|
+
gap: var(--sp-px) var(--sp-2);
|
|
255
257
|
min-width: 0;
|
|
256
258
|
}
|
|
257
259
|
.row .label-text {
|
|
@@ -260,7 +262,6 @@
|
|
|
260
262
|
.note {
|
|
261
263
|
font-size: var(--fs-xs);
|
|
262
264
|
color: var(--text-faint);
|
|
263
|
-
white-space: nowrap;
|
|
264
265
|
}
|
|
265
266
|
.description {
|
|
266
267
|
font-size: var(--fs-xs);
|
|
@@ -119,11 +119,21 @@
|
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
$effect(() => {
|
|
122
|
-
if (
|
|
123
|
-
const el = root?.ownerDocument.getElementById(optionId(active));
|
|
124
|
-
el?.scrollIntoView?.({ block: 'nearest' });
|
|
122
|
+
if (open && active >= 0) revealActive();
|
|
125
123
|
});
|
|
126
124
|
|
|
125
|
+
// Scrolls the listbox only: `scrollIntoView` on a top-layer panel also
|
|
126
|
+
// scrolls the document in Chromium.
|
|
127
|
+
function revealActive() {
|
|
128
|
+
const list = root?.querySelector<HTMLElement>('.rs-list');
|
|
129
|
+
const row = rowEls()[active];
|
|
130
|
+
if (!list || !row) return;
|
|
131
|
+
const top = row.offsetTop;
|
|
132
|
+
const bottom = top + row.offsetHeight;
|
|
133
|
+
if (top < list.scrollTop) list.scrollTop = top;
|
|
134
|
+
else if (bottom > list.scrollTop + list.clientHeight) list.scrollTop = bottom - list.clientHeight;
|
|
135
|
+
}
|
|
136
|
+
|
|
127
137
|
function close() {
|
|
128
138
|
open = false;
|
|
129
139
|
}
|
|
@@ -303,8 +313,7 @@
|
|
|
303
313
|
async function onOpen() {
|
|
304
314
|
typeahead.reset();
|
|
305
315
|
await tick();
|
|
306
|
-
|
|
307
|
-
el?.scrollIntoView?.({ block: 'nearest' });
|
|
316
|
+
if (active >= 0) revealActive();
|
|
308
317
|
}
|
|
309
318
|
|
|
310
319
|
function onClose() {
|
|
@@ -459,7 +468,6 @@
|
|
|
459
468
|
}
|
|
460
469
|
.rs-placeholder {
|
|
461
470
|
display: block;
|
|
462
|
-
padding-inline: var(--sp-1);
|
|
463
471
|
color: var(--text-muted);
|
|
464
472
|
font-size: var(--control-fs-md);
|
|
465
473
|
line-height: var(--lh-tight);
|
|
@@ -486,6 +494,7 @@
|
|
|
486
494
|
padding: var(--sp-1);
|
|
487
495
|
}
|
|
488
496
|
.rs-list {
|
|
497
|
+
position: relative;
|
|
489
498
|
display: flex;
|
|
490
499
|
flex-direction: column;
|
|
491
500
|
gap: var(--sp-0-5);
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
shrink = true,
|
|
31
31
|
block = false,
|
|
32
32
|
sound = true,
|
|
33
|
+
disabled = false,
|
|
33
34
|
class: klass = '',
|
|
34
35
|
...rest
|
|
35
36
|
}: {
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
hitArea?: 'auto' | 'compact';
|
|
65
66
|
/** Play UI sounds when enabled globally; false silences this instance. */
|
|
66
67
|
sound?: boolean;
|
|
68
|
+
disabled?: boolean;
|
|
67
69
|
class?: string;
|
|
68
70
|
[key: string]: unknown;
|
|
69
71
|
} = $props();
|
|
@@ -81,6 +83,7 @@
|
|
|
81
83
|
class="select-button {klass}"
|
|
82
84
|
class:row={variant === 'row'}
|
|
83
85
|
class:active
|
|
86
|
+
class:disabled
|
|
84
87
|
data-tsu="SelectButton"
|
|
85
88
|
{...rest}
|
|
86
89
|
class:grow={grow}
|
|
@@ -98,6 +101,7 @@
|
|
|
98
101
|
aria-label={label}
|
|
99
102
|
{title}
|
|
100
103
|
{value}
|
|
104
|
+
{disabled}
|
|
101
105
|
onchange={change}
|
|
102
106
|
>
|
|
103
107
|
{#if groups}
|
|
@@ -138,18 +142,25 @@
|
|
|
138
142
|
.select-button.active {
|
|
139
143
|
color: var(--accent);
|
|
140
144
|
}
|
|
145
|
+
.select-button.disabled {
|
|
146
|
+
opacity: var(--disabled-opacity);
|
|
147
|
+
cursor: not-allowed;
|
|
148
|
+
}
|
|
141
149
|
/* The inert face takes no pointer events: mirror ghost hover, press and the
|
|
142
150
|
focus ring from the select overlaying it. */
|
|
143
151
|
.select-button:active :global(.btn-ghost) {
|
|
144
152
|
--btn-scale-dur: var(--dur-press);
|
|
145
153
|
scale: var(--press-scale-sm);
|
|
146
154
|
}
|
|
155
|
+
.select-button.disabled:active :global(.btn-ghost) {
|
|
156
|
+
scale: none;
|
|
157
|
+
}
|
|
147
158
|
.select-button:has(:focus-visible) {
|
|
148
159
|
outline: var(--focus-ring);
|
|
149
160
|
outline-offset: var(--focus-ring-offset);
|
|
150
161
|
}
|
|
151
162
|
@media (hover: hover) and (pointer: fine) {
|
|
152
|
-
.select-button:hover :global(.btn-ghost) {
|
|
163
|
+
.select-button:not(.disabled):hover :global(.btn-ghost) {
|
|
153
164
|
background: var(--bg-elevated-2);
|
|
154
165
|
}
|
|
155
166
|
}
|
|
@@ -74,6 +74,8 @@
|
|
|
74
74
|
.status-label {
|
|
75
75
|
flex: 1;
|
|
76
76
|
min-width: 0;
|
|
77
|
+
padding-block: calc(var(--focus-ring-width) + var(--focus-ring-offset));
|
|
78
|
+
margin-block: calc(-1 * (var(--focus-ring-width) + var(--focus-ring-offset)));
|
|
77
79
|
overflow: hidden;
|
|
78
80
|
text-overflow: ellipsis;
|
|
79
81
|
white-space: nowrap;
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
class:on={pressed}
|
|
64
64
|
aria-pressed={pressed}
|
|
65
65
|
>
|
|
66
|
-
{@render children?.()}
|
|
66
|
+
<span class="label">{@render children?.()}</span>
|
|
67
67
|
</button>
|
|
68
68
|
|
|
69
69
|
<style>
|
|
@@ -106,10 +106,20 @@
|
|
|
106
106
|
font-size: var(--control-fs-md);
|
|
107
107
|
--icon-size: var(--control-icon-md);
|
|
108
108
|
}
|
|
109
|
+
.label {
|
|
110
|
+
display: contents;
|
|
111
|
+
}
|
|
109
112
|
.toggle.grow {
|
|
110
113
|
flex: 1 1 0;
|
|
111
114
|
min-width: 0;
|
|
112
115
|
}
|
|
116
|
+
.toggle.grow .label {
|
|
117
|
+
display: block;
|
|
118
|
+
min-width: 0;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
text-overflow: ellipsis;
|
|
121
|
+
text-align: center;
|
|
122
|
+
}
|
|
113
123
|
.toggle.no-shrink {
|
|
114
124
|
flex: none;
|
|
115
125
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// observed and the longest candidate that fits is shown (mode `path`
|
|
10
10
|
// abbreviates fish-style). `copyable` copies the full text on click.
|
|
11
11
|
import { copyToClipboard } from '../../clipboard';
|
|
12
|
+
import { untrack } from 'svelte';
|
|
12
13
|
import { pathCandidates, truncate, type TruncateMode } from '../../truncate';
|
|
13
14
|
import Tooltip from './Tooltip.svelte';
|
|
14
15
|
|
|
@@ -72,15 +73,18 @@
|
|
|
72
73
|
let probe = $state<HTMLSpanElement | null>(null);
|
|
73
74
|
let avail = $state(Number.POSITIVE_INFINITY);
|
|
74
75
|
let chPx = $state(8);
|
|
76
|
+
let cap = $state(Number.POSITIVE_INFINITY);
|
|
75
77
|
|
|
76
78
|
$effect(() => {
|
|
77
79
|
if (!fit || !rail) return;
|
|
78
80
|
const el = rail;
|
|
79
81
|
const measure = () => {
|
|
80
|
-
|
|
82
|
+
const w = el.clientWidth;
|
|
83
|
+
if (w > avail) cap = Number.POSITIVE_INFINITY;
|
|
84
|
+
avail = w;
|
|
81
85
|
if (probe) chPx = probe.getBoundingClientRect().width / 10 || chPx;
|
|
82
86
|
};
|
|
83
|
-
measure
|
|
87
|
+
untrack(measure);
|
|
84
88
|
const ro = new ResizeObserver(measure);
|
|
85
89
|
ro.observe(el);
|
|
86
90
|
return () => ro.disconnect();
|
|
@@ -88,7 +92,7 @@
|
|
|
88
92
|
|
|
89
93
|
const shown = $derived.by(() => {
|
|
90
94
|
if (fit) {
|
|
91
|
-
const budget = Math.max(0, avail - 1);
|
|
95
|
+
const budget = Math.max(0, Math.min(avail - 1, cap));
|
|
92
96
|
return candidates.find((c) => [...c].length * chPx <= budget) ?? candidates[candidates.length - 1];
|
|
93
97
|
}
|
|
94
98
|
if (max === undefined) return text;
|
|
@@ -96,6 +100,17 @@
|
|
|
96
100
|
});
|
|
97
101
|
const isTruncated = $derived(shown !== text);
|
|
98
102
|
|
|
103
|
+
// The per-character estimate can undershoot (glyph fallbacks, late fonts): cap the budget below the spilling candidate.
|
|
104
|
+
$effect(() => {
|
|
105
|
+
if (!fit || !rail || shown === candidates[candidates.length - 1]) return;
|
|
106
|
+
const el = rail;
|
|
107
|
+
const id = requestAnimationFrame(() => {
|
|
108
|
+
const over = el.scrollWidth - el.clientWidth;
|
|
109
|
+
if (over > 0) cap = Math.min(untrack(() => cap), [...shown].length * chPx - over);
|
|
110
|
+
});
|
|
111
|
+
return () => cancelAnimationFrame(id);
|
|
112
|
+
});
|
|
113
|
+
|
|
99
114
|
let status = $state('');
|
|
100
115
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
101
116
|
async function copy(e: MouseEvent) {
|
|
@@ -173,6 +188,9 @@
|
|
|
173
188
|
max-width: 100%;
|
|
174
189
|
overflow: hidden;
|
|
175
190
|
}
|
|
191
|
+
.rail .trunc:focus-visible {
|
|
192
|
+
outline-offset: var(--focus-ring-offset-inset);
|
|
193
|
+
}
|
|
176
194
|
.grow {
|
|
177
195
|
flex: 1 1 0;
|
|
178
196
|
}
|
|
@@ -97,14 +97,20 @@
|
|
|
97
97
|
{#if showChips && (chips.length || text)}
|
|
98
98
|
<div class="fsb__chips">
|
|
99
99
|
{#each chips as f (f.span[0])}
|
|
100
|
-
<Badge
|
|
100
|
+
<Badge
|
|
101
|
+
tone="info"
|
|
102
|
+
truncate
|
|
103
|
+
title="{labelFor(f.field)} {operatorById(f.op)?.label} {f.values.join(', ') || '∅'}"
|
|
104
|
+
removable
|
|
105
|
+
onremove={() => remove(f.span)}
|
|
106
|
+
>
|
|
101
107
|
<span class="fsb__chip-field">{labelFor(f.field)}</span>
|
|
102
108
|
<span class="fsb__chip-op">{operatorById(f.op)?.label}</span>
|
|
103
109
|
<span class="fsb__chip-val">{f.values.join(', ') || '∅'}</span>
|
|
104
110
|
</Badge>
|
|
105
111
|
{/each}
|
|
106
112
|
{#if text}
|
|
107
|
-
<Badge tone="neutral">
|
|
113
|
+
<Badge tone="neutral" truncate title="text {text}">
|
|
108
114
|
<span class="fsb__chip-op">text</span>
|
|
109
115
|
<span class="fsb__chip-val">{text}</span>
|
|
110
116
|
</Badge>
|
package/dist/floating.js
CHANGED
|
@@ -20,9 +20,15 @@ function alignPos(align, start, size, fSize) {
|
|
|
20
20
|
export function place(trigger, floating, placement = 'bottom-start', gap = 6) {
|
|
21
21
|
placeAt(trigger.getBoundingClientRect(), floating, placement, gap);
|
|
22
22
|
}
|
|
23
|
+
// The enter transition starts the panel at `scale: var(--enter-scale)`, so a
|
|
24
|
+
// client rect taken on open is ~4% short; offset sizes ignore transforms.
|
|
25
|
+
function layoutSize(el) {
|
|
26
|
+
const { width, height } = el.getBoundingClientRect();
|
|
27
|
+
return { width: el.offsetWidth || width, height: el.offsetHeight || height };
|
|
28
|
+
}
|
|
23
29
|
/** `place` against a viewport rect instead of an element. */
|
|
24
30
|
export function placeAt(t, floating, placement = 'bottom-start', gap = 6) {
|
|
25
|
-
const f = floating
|
|
31
|
+
const f = layoutSize(floating);
|
|
26
32
|
const vw = document.documentElement.clientWidth;
|
|
27
33
|
const vh = document.documentElement.clientHeight;
|
|
28
34
|
const [side, align] = placement.split('-');
|
package/package.json
CHANGED