@lyeve-labs/ui-kit 0.22.0 → 0.22.2
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/AppShell.svelte +4 -2
- package/dist/components/PageHeader.svelte +1 -1
- package/dist/components/PageHeader.svelte.d.ts +1 -1
- package/dist/components/Select.svelte +1 -1
- package/dist/components/Select.svelte.d.ts +1 -1
- package/dist/components/Table.svelte +4 -1
- package/dist/components/dialog/ConfirmDialog.svelte +9 -2
- package/dist/components/dialog/Dialog.svelte +28 -23
- package/dist/components/dialog/dialog-manager.svelte.d.ts +6 -0
- package/dist/components/dialog/dialog-manager.svelte.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/overlay.js +7 -3
- package/dist/internal/panel.d.ts +5 -1
- package/dist/internal/panel.js +5 -1
- package/dist/styles/theme.css +1 -1
- package/dist/utils/theme.js +1 -1
- package/package.json +2 -2
- package/src/lib/styles/theme.css +1 -1
|
@@ -208,12 +208,14 @@
|
|
|
208
208
|
to its target and moves focus to it only if the target can hold focus,
|
|
209
209
|
so without this the link moved the page and left focus on the body, and
|
|
210
210
|
the next Tab started again at the top of the document: the sidebar the
|
|
211
|
-
reader had just skipped.
|
|
211
|
+
reader had just skipped. No outline on it: the region is a landing, not
|
|
212
|
+
a control, and the browser's default drew a box around the whole page
|
|
213
|
+
body the moment the link was used. -->
|
|
212
214
|
<main
|
|
213
215
|
id="content"
|
|
214
216
|
tabindex="-1"
|
|
215
217
|
data-print="unclip"
|
|
216
|
-
class="min-w-0 flex-1 overflow-auto bg-ink"
|
|
218
|
+
class="min-w-0 flex-1 overflow-auto bg-ink outline-none"
|
|
217
219
|
>
|
|
218
220
|
{@render children()}
|
|
219
221
|
</main>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Drop the bottom margin, for a caller that owns the rhythm itself.
|
|
15
15
|
*
|
|
16
16
|
* The margin is opt-out rather than removed. Forty-three pages across the
|
|
17
|
-
*
|
|
17
|
+
* consuming applications render this component directly and take their heading gap from
|
|
18
18
|
* it, so deleting it outright would have moved every one of them by 32px
|
|
19
19
|
* with nothing in their own source to explain why.
|
|
20
20
|
*/
|
|
@@ -12,7 +12,7 @@ interface Props {
|
|
|
12
12
|
* Drop the bottom margin, for a caller that owns the rhythm itself.
|
|
13
13
|
*
|
|
14
14
|
* The margin is opt-out rather than removed. Forty-three pages across the
|
|
15
|
-
*
|
|
15
|
+
* consuming applications render this component directly and take their heading gap from
|
|
16
16
|
* it, so deleting it outright would have moved every one of them by 32px
|
|
17
17
|
* with nothing in their own source to explain why.
|
|
18
18
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* The event a native select hands its change handler.
|
|
6
6
|
*
|
|
7
|
-
* Frozen, and it stays frozen. Every call site in the
|
|
7
|
+
* Frozen, and it stays frozen. Every call site in the consuming applications passes an
|
|
8
8
|
* unannotated arrow whose parameter is contextually typed from this prop, and
|
|
9
9
|
* several of them read `e.currentTarget.value` or call
|
|
10
10
|
* `e.currentTarget.form.requestSubmit()`. Retyping the callback to take a
|
|
@@ -2,7 +2,7 @@ import type { Component } from 'svelte';
|
|
|
2
2
|
/**
|
|
3
3
|
* The event a native select hands its change handler.
|
|
4
4
|
*
|
|
5
|
-
* Frozen, and it stays frozen. Every call site in the
|
|
5
|
+
* Frozen, and it stays frozen. Every call site in the consuming applications passes an
|
|
6
6
|
* unannotated arrow whose parameter is contextually typed from this prop, and
|
|
7
7
|
* several of them read `e.currentTarget.value` or call
|
|
8
8
|
* `e.currentTarget.form.requestSubmit()`. Retyping the callback to take a
|
|
@@ -210,7 +210,10 @@
|
|
|
210
210
|
}
|
|
211
211
|
</script>
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
<!-- overflow-hidden on the frame, not only on the scroller: the hovered row's
|
|
214
|
+
ring is square and the frame is not, and the last row's corners drew past
|
|
215
|
+
the frame's rounded ones. -->
|
|
216
|
+
<div data-testid="table-frame" class="relative w-full overflow-hidden rounded-xl border border-line {cls}">
|
|
214
217
|
<!--
|
|
215
218
|
data-print: the box exists to clip. On paper there is no viewport to clip
|
|
216
219
|
to, and every column past the edge would simply not be printed.
|
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
let confirmLabel = $derived(
|
|
43
43
|
typeof entry.meta?.confirmLabel === 'string' ? entry.meta.confirmLabel : 'Confirm',
|
|
44
44
|
);
|
|
45
|
+
// An identifier the message refers to. Set apart in monospace on its own
|
|
46
|
+
// line rather than inside the sentence, where a UUID wraps mid-string.
|
|
47
|
+
let detail = $derived(typeof entry.meta?.confirmDetail === 'string' ? entry.meta.confirmDetail : '');
|
|
45
48
|
|
|
46
49
|
async function handleConfirm() {
|
|
47
50
|
if (loading) return;
|
|
@@ -80,12 +83,16 @@
|
|
|
80
83
|
{#if message}
|
|
81
84
|
<p class="text-sm text-muted mt-1">{message}</p>
|
|
82
85
|
{/if}
|
|
86
|
+
{#if detail}
|
|
87
|
+
<p class="mt-2 break-all font-mono text-xs text-faint">{detail}</p>
|
|
88
|
+
{/if}
|
|
83
89
|
</div>
|
|
84
90
|
</div>
|
|
85
91
|
|
|
86
|
-
<!-- Actions
|
|
92
|
+
<!-- Actions. Cancel takes focus first: a destructive dialog must not
|
|
93
|
+
accept an Enter pressed before it was read. -->
|
|
87
94
|
<div class="flex items-center justify-end gap-3 pt-2">
|
|
88
|
-
<Button variant="secondary" size="sm" onclick={handleCancel}>
|
|
95
|
+
<Button variant="secondary" size="sm" onclick={handleCancel} data-initial-focus>
|
|
89
96
|
{cancelLabel}
|
|
90
97
|
</Button>
|
|
91
98
|
<Button variant="danger" size="sm" onclick={handleConfirm} {loading}>
|
|
@@ -137,34 +137,39 @@
|
|
|
137
137
|
tabindex="-1"
|
|
138
138
|
onkeydown={handleKeydown}
|
|
139
139
|
>
|
|
140
|
-
<!-- Header
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
140
|
+
<!-- Header. A confirm dialog has none: it renders its own title beside
|
|
141
|
+
the warning icon and offers Cancel, so a header here was an empty row
|
|
142
|
+
with a close control in it, and that control was the first thing
|
|
143
|
+
focused. Escape still dismisses. -->
|
|
144
|
+
{#if entry.meta?.confirmTitle === undefined}
|
|
145
|
+
<div class="flex items-center justify-between px-6 pt-6 pb-2">
|
|
146
|
+
<div class="flex-1 min-w-0">
|
|
147
|
+
{#if entry.options.title}
|
|
148
|
+
{#if typeof entry.options.title === 'string'}
|
|
149
|
+
<h2 class="text-lg font-semibold text-fg truncate">
|
|
150
|
+
{entry.options.title}
|
|
151
|
+
</h2>
|
|
152
|
+
{:else}
|
|
153
|
+
{@render entry.options.title()}
|
|
154
|
+
{/if}
|
|
150
155
|
{/if}
|
|
151
|
-
|
|
152
|
-
</div>
|
|
156
|
+
</div>
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
{#if !entry.options.persistent}
|
|
159
|
+
<button
|
|
160
|
+
class="inline-flex items-center justify-center w-8 h-8 -me-2 rounded-lg
|
|
157
161
|
text-muted hover:text-fg hover:bg-surface-2 transition-colors duration-150 shrink-0"
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
onclick={() => handleClose()}
|
|
163
|
+
aria-label="Close"
|
|
164
|
+
>
|
|
165
|
+
<X class="w-4 h-4" />
|
|
166
|
+
</button>
|
|
167
|
+
{/if}
|
|
168
|
+
</div>
|
|
169
|
+
{/if}
|
|
165
170
|
|
|
166
171
|
<!-- Body -->
|
|
167
|
-
<div class=
|
|
172
|
+
<div class={entry.meta?.confirmTitle === undefined ? 'px-6 py-2' : 'px-6 pt-6 pb-2'}>
|
|
168
173
|
{#if entry.options.body}
|
|
169
174
|
{@render entry.options.body()}
|
|
170
175
|
{:else if entry.meta?.confirmTitle !== undefined}
|
|
@@ -55,6 +55,12 @@ export interface ConfirmOptions {
|
|
|
55
55
|
confirmLabel?: string;
|
|
56
56
|
/** The verb on the dismissing button. Defaults to `Cancel`. */
|
|
57
57
|
cancelLabel?: string;
|
|
58
|
+
/**
|
|
59
|
+
* An identifier the message refers to, such as the id of the record about
|
|
60
|
+
* to be deleted. Rendered on its own line in monospace, so a UUID never
|
|
61
|
+
* wraps inside the sentence.
|
|
62
|
+
*/
|
|
63
|
+
detail?: string;
|
|
58
64
|
}
|
|
59
65
|
/**
|
|
60
66
|
* Convenience: confirm dialog.
|
|
@@ -151,6 +151,7 @@ export function confirm(title, message, options) {
|
|
|
151
151
|
// would be indistinguishable from an override to the empty case.
|
|
152
152
|
...(options?.confirmLabel !== undefined ? { confirmLabel: options.confirmLabel } : {}),
|
|
153
153
|
...(options?.cancelLabel !== undefined ? { cancelLabel: options.cancelLabel } : {}),
|
|
154
|
+
...(options?.detail !== undefined ? { confirmDetail: options.detail } : {}),
|
|
154
155
|
});
|
|
155
156
|
// Cancelling a dialog dismisses it, and dismissal rejects. Callers write
|
|
156
157
|
// `if (await confirm(...))`, so a rejection on Cancel is an unhandled
|
package/dist/index.d.ts
CHANGED
|
@@ -89,4 +89,4 @@ export type { ConfirmOptions } from './components/dialog/dialog-manager.svelte.j
|
|
|
89
89
|
export type { DialogOptions, DialogEntry, DialogSize } from './components/dialog/types.js';
|
|
90
90
|
export { cn, type ClassValue } from './utils/cn.js';
|
|
91
91
|
export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setTheme, setThemePreference, systemTheme, themeBootScript, toggleTheme, watchSystemTheme, THEME_PREFERENCES, type Theme, type ThemePreference, } from './utils/theme.js';
|
|
92
|
-
export declare const VERSION = "0.22.
|
|
92
|
+
export declare const VERSION = "0.22.2";
|
package/dist/index.js
CHANGED
|
@@ -96,4 +96,4 @@ export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setThe
|
|
|
96
96
|
// ── Version ────────────────────────────────────────────────────────────────
|
|
97
97
|
// Generated from package.json by `pnpm version:sync`. Bump package.json, never
|
|
98
98
|
// this line; the build and the test suite fail when the two disagree.
|
|
99
|
-
export const VERSION = '0.22.
|
|
99
|
+
export const VERSION = '0.22.2';
|
package/dist/internal/overlay.js
CHANGED
|
@@ -50,9 +50,13 @@ function focusable(node) {
|
|
|
50
50
|
export function overlay(node) {
|
|
51
51
|
const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
52
52
|
lockBodyScroll();
|
|
53
|
-
// A panel
|
|
54
|
-
//
|
|
55
|
-
|
|
53
|
+
// A panel may name where focus lands with data-initial-focus: a confirm
|
|
54
|
+
// dialog puts it on Cancel, so that Enter on a dialog a person has not read
|
|
55
|
+
// yet does nothing, and the close control is never the first thing focused.
|
|
56
|
+
// Otherwise the first focusable element takes it. A panel with nothing
|
|
57
|
+
// focusable still has to receive focus, or the screen reader stays on the
|
|
58
|
+
// element behind the overlay and reads the wrong thing.
|
|
59
|
+
const first = node.querySelector('[data-initial-focus]') ?? focusable(node)[0];
|
|
56
60
|
if (first) {
|
|
57
61
|
first.focus();
|
|
58
62
|
}
|
package/dist/internal/panel.d.ts
CHANGED
|
@@ -39,8 +39,12 @@
|
|
|
39
39
|
* border-line-strong, not border-line: a panel floating over arbitrary content
|
|
40
40
|
* needs a boundary that clears 3:1, which line does not. It carries the
|
|
41
41
|
* resting text colour so a row can override it with a single utility.
|
|
42
|
+
*
|
|
43
|
+
* overflow-hidden, because the rows are square and the panel is not: the
|
|
44
|
+
* active ring on the first or last row drew its corners past the panel's
|
|
45
|
+
* rounded ones, a box poking out of the box that holds it.
|
|
42
46
|
*/
|
|
43
|
-
export declare const PANEL_SURFACE = "absolute z-dropdown mt-1 rounded-xl border border-line-strong bg-surface text-fg shadow-2xl";
|
|
47
|
+
export declare const PANEL_SURFACE = "absolute z-dropdown mt-1 overflow-hidden rounded-xl border border-line-strong bg-surface text-fg shadow-2xl";
|
|
44
48
|
/**
|
|
45
49
|
* The scrolling region inside it.
|
|
46
50
|
*
|
package/dist/internal/panel.js
CHANGED
|
@@ -39,8 +39,12 @@
|
|
|
39
39
|
* border-line-strong, not border-line: a panel floating over arbitrary content
|
|
40
40
|
* needs a boundary that clears 3:1, which line does not. It carries the
|
|
41
41
|
* resting text colour so a row can override it with a single utility.
|
|
42
|
+
*
|
|
43
|
+
* overflow-hidden, because the rows are square and the panel is not: the
|
|
44
|
+
* active ring on the first or last row drew its corners past the panel's
|
|
45
|
+
* rounded ones, a box poking out of the box that holds it.
|
|
42
46
|
*/
|
|
43
|
-
export const PANEL_SURFACE = 'absolute z-dropdown mt-1 rounded-xl border border-line-strong bg-surface text-fg shadow-2xl';
|
|
47
|
+
export const PANEL_SURFACE = 'absolute z-dropdown mt-1 overflow-hidden rounded-xl border border-line-strong bg-surface text-fg shadow-2xl';
|
|
44
48
|
/**
|
|
45
49
|
* The scrolling region inside it.
|
|
46
50
|
*
|
package/dist/styles/theme.css
CHANGED
|
@@ -409,7 +409,7 @@ html[data-theme='light'] {
|
|
|
409
409
|
/*
|
|
410
410
|
* Print.
|
|
411
411
|
*
|
|
412
|
-
* The
|
|
412
|
+
* The consuming applications had no `@media print` rule anywhere, and three surfaces print:
|
|
413
413
|
* the portal prints an invoice, the ops console prints an audit log, the admin
|
|
414
414
|
* prints a subject-access export. All three printed the sidebar, the theme
|
|
415
415
|
* toggle and the nav, in a dark palette, and all three printed one screenful
|
package/dist/utils/theme.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* helper here understands.
|
|
23
23
|
*/
|
|
24
24
|
/**
|
|
25
|
-
* The one key every surface
|
|
25
|
+
* The one key every surface of every consuming application reads and writes.
|
|
26
26
|
*
|
|
27
27
|
* Not exported. A surface that needs the name has `getThemePreference` and
|
|
28
28
|
* `setThemePreference`; a surface that spells the key itself is how two of
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lyeve-labs/ui-kit",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.2",
|
|
4
4
|
"description": "A clean, accessible, palette-aware Svelte 5 component library. The design system behind LyEve.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "LyEve Labs <hello@lyeve.com>",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"type": "module",
|
|
25
25
|
"sideEffects": false,
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
27
|
+
"node": ">=24"
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist",
|
package/src/lib/styles/theme.css
CHANGED
|
@@ -409,7 +409,7 @@ html[data-theme='light'] {
|
|
|
409
409
|
/*
|
|
410
410
|
* Print.
|
|
411
411
|
*
|
|
412
|
-
* The
|
|
412
|
+
* The consuming applications had no `@media print` rule anywhere, and three surfaces print:
|
|
413
413
|
* the portal prints an invoice, the ops console prints an audit log, the admin
|
|
414
414
|
* prints a subject-access export. All three printed the sidebar, the theme
|
|
415
415
|
* toggle and the nav, in a dark palette, and all three printed one screenful
|