@lyeve-labs/ui-kit 0.36.0 → 0.38.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/README.md +147 -0
- package/dist/components/AuthShell.svelte +25 -2
- package/dist/components/AuthShell.svelte.d.ts +13 -0
- package/dist/components/CopyButton.svelte +58 -15
- package/dist/components/CopyButton.svelte.d.ts +17 -1
- package/dist/components/CopyField.svelte +58 -15
- package/dist/components/CopyField.svelte.d.ts +10 -0
- package/dist/components/EmptyState.svelte +14 -1
- package/dist/components/EmptyState.svelte.d.ts +6 -0
- package/dist/components/FilterChips.svelte +132 -26
- package/dist/components/FilterChips.svelte.d.ts +28 -1
- package/dist/components/Input.svelte +9 -1
- package/dist/components/Input.svelte.d.ts +6 -0
- package/dist/components/NumberInput.svelte +7 -1
- package/dist/components/PageShell.svelte +28 -1
- package/dist/components/PageShell.svelte.d.ts +15 -1
- package/dist/components/RadioGroup.svelte +19 -4
- package/dist/components/RadioGroup.svelte.d.ts +11 -0
- package/dist/components/SegmentedControl.svelte +62 -7
- package/dist/components/SegmentedControl.svelte.d.ts +18 -0
- package/dist/components/Select.svelte +9 -1
- package/dist/components/Select.svelte.d.ts +6 -0
- package/dist/components/SidebarNav.svelte +8 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +9 -1
- package/dist/internal/copy.svelte.d.ts +13 -2
- package/dist/internal/copy.svelte.js +13 -3
- package/dist/internal/document-title.d.ts +11 -0
- package/dist/internal/document-title.js +28 -0
- package/dist/internal/field.d.ts +8 -0
- package/dist/internal/field.js +10 -0
- package/package.json +1 -1
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
FIELD_WRAP,
|
|
54
54
|
controlBorder,
|
|
55
55
|
describedBy,
|
|
56
|
+
joinIds,
|
|
56
57
|
} from '../internal/field.js';
|
|
57
58
|
import { createListbox } from '../internal/listbox.svelte.js';
|
|
58
59
|
import {
|
|
@@ -75,6 +76,12 @@
|
|
|
75
76
|
required?: boolean;
|
|
76
77
|
disabled?: boolean;
|
|
77
78
|
error?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Ids of other elements that describe the control, separated by spaces,
|
|
81
|
+
* such as the message a wrapping Field renders. They are read after the
|
|
82
|
+
* control's own hint or error.
|
|
83
|
+
*/
|
|
84
|
+
describedBy?: string;
|
|
78
85
|
class?: string;
|
|
79
86
|
/** The rows, as data. */
|
|
80
87
|
options?: SelectOption[];
|
|
@@ -102,6 +109,7 @@
|
|
|
102
109
|
required = false,
|
|
103
110
|
disabled = false,
|
|
104
111
|
error,
|
|
112
|
+
describedBy: callerIds,
|
|
105
113
|
class: cls = '',
|
|
106
114
|
options = [],
|
|
107
115
|
searchable = false,
|
|
@@ -312,7 +320,7 @@
|
|
|
312
320
|
}}
|
|
313
321
|
aria-invalid={error ? 'true' : undefined}
|
|
314
322
|
aria-required={required ? 'true' : undefined}
|
|
315
|
-
aria-describedby={describedBy(fieldId, error, hint)}
|
|
323
|
+
aria-describedby={joinIds(describedBy(fieldId, error, hint), callerIds)}
|
|
316
324
|
{...box.triggerAttrs}
|
|
317
325
|
class="{CONTROL_BASE} {controlBorder(!!error)} flex cursor-pointer items-center gap-2 pe-8
|
|
318
326
|
text-start"
|
|
@@ -53,6 +53,12 @@ interface Props {
|
|
|
53
53
|
required?: boolean;
|
|
54
54
|
disabled?: boolean;
|
|
55
55
|
error?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Ids of other elements that describe the control, separated by spaces,
|
|
58
|
+
* such as the message a wrapping Field renders. They are read after the
|
|
59
|
+
* control's own hint or error.
|
|
60
|
+
*/
|
|
61
|
+
describedBy?: string;
|
|
56
62
|
class?: string;
|
|
57
63
|
/** The rows, as data. */
|
|
58
64
|
options?: SelectOption[];
|
|
@@ -166,7 +166,14 @@
|
|
|
166
166
|
{@render body(node)}
|
|
167
167
|
</span>
|
|
168
168
|
{:else if node.href && branch}
|
|
169
|
-
|
|
169
|
+
<!--
|
|
170
|
+
The rail stacks the disclosure under the link, under a mouse and under
|
|
171
|
+
a finger alike, so the link keeps the rail's width. Side by side the two
|
|
172
|
+
did not fit. Under a finger the pair took 92px and scrolled the nav
|
|
173
|
+
sideways. Under a mouse the link shrank to its own padding with its icon
|
|
174
|
+
under the chevron, and a rail with a gutter scrolled as well.
|
|
175
|
+
-->
|
|
176
|
+
<div class={collapsed ? 'flex flex-col items-start gap-1' : 'flex items-center gap-1'}>
|
|
170
177
|
<a
|
|
171
178
|
href={node.href}
|
|
172
179
|
aria-current={current ? 'page' : undefined}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export type { CellFit } from './components/Table.svelte';
|
|
|
25
25
|
export type { SidebarState } from './components/AppShell.svelte';
|
|
26
26
|
export type { PageWidth, SectionVariant } from './internal/layout.js';
|
|
27
27
|
export type { TreeNode, TriState } from './internal/tree.js';
|
|
28
|
+
export { setDocumentTitleFormat, type DocumentTitleFormat } from './internal/document-title.js';
|
|
28
29
|
export { default as Button } from './components/Button.svelte';
|
|
29
30
|
export { default as ButtonGroup } from './components/ButtonGroup.svelte';
|
|
30
31
|
export { default as Input } from './components/Input.svelte';
|
|
@@ -79,10 +80,12 @@ export { default as CheckoutSteps } from './components/CheckoutSteps.svelte';
|
|
|
79
80
|
export { default as PluginCart } from './components/PluginCart.svelte';
|
|
80
81
|
export type { QuickPick } from './components/PluginCart.svelte';
|
|
81
82
|
export { billedCount, formatCents, ladderRows, ladderState, type BillingPeriod, type CartCatalog, type CartPlugin, type CartQuote, type CartQuoteItem, type DiscountBracket, type LadderState, } from './internal/pricing.js';
|
|
83
|
+
export type { AccentTone, StatusTone } from './internal/tone.js';
|
|
82
84
|
export { default as Stat } from './components/Stat.svelte';
|
|
83
85
|
export { default as Kbd } from './components/Kbd.svelte';
|
|
84
86
|
export { default as CopyButton } from './components/CopyButton.svelte';
|
|
85
87
|
export { default as CopyField } from './components/CopyField.svelte';
|
|
88
|
+
export { CopyState, copyToClipboard, type CopyStatus } from './internal/copy.svelte.js';
|
|
86
89
|
export { default as Avatar } from './components/Avatar.svelte';
|
|
87
90
|
export { default as AvatarGroup } from './components/AvatarGroup.svelte';
|
|
88
91
|
export { default as Logo } from './components/Logo.svelte';
|
|
@@ -100,4 +103,4 @@ export { cn, type ClassValue } from './utils/cn.js';
|
|
|
100
103
|
export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setTheme, setThemePreference, systemTheme, themeBootScript, watchThemePreference, toggleTheme, watchSystemTheme, THEME_PREFERENCES, type Theme, type ThemePreference, } from './utils/theme.js';
|
|
101
104
|
export * as motion from './motion.js';
|
|
102
105
|
export type { Rung as MotionRung, Curve as MotionCurve } from './motion.js';
|
|
103
|
-
export declare const VERSION = "0.
|
|
106
|
+
export declare const VERSION = "0.38.0";
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,10 @@ export { default as Table } from './components/Table.svelte';
|
|
|
22
22
|
export { default as DescriptionList } from './components/DescriptionList.svelte';
|
|
23
23
|
export { default as Toolbar } from './components/Toolbar.svelte';
|
|
24
24
|
export { default as TreeView } from './components/TreeView.svelte';
|
|
25
|
+
// Stated once in an app's root layout, the format turns every PageShell's
|
|
26
|
+
// title into the browser tab's. An app that never states one gets no title
|
|
27
|
+
// element from the kit.
|
|
28
|
+
export { setDocumentTitleFormat } from './internal/document-title.js';
|
|
25
29
|
// ── Forms & inputs ─────────────────────────────────────────────────────────
|
|
26
30
|
export { default as Button } from './components/Button.svelte';
|
|
27
31
|
export { default as ButtonGroup } from './components/ButtonGroup.svelte';
|
|
@@ -79,6 +83,10 @@ export { default as Stat } from './components/Stat.svelte';
|
|
|
79
83
|
export { default as Kbd } from './components/Kbd.svelte';
|
|
80
84
|
export { default as CopyButton } from './components/CopyButton.svelte';
|
|
81
85
|
export { default as CopyField } from './components/CopyField.svelte';
|
|
86
|
+
// The clipboard write and the confirmation both copy controls run on, for a
|
|
87
|
+
// control the kit does not ship. A menu item that copies then falls back the
|
|
88
|
+
// same way on an insecure origin and confirms on the same clock.
|
|
89
|
+
export { CopyState, copyToClipboard } from './internal/copy.svelte.js';
|
|
82
90
|
// ── Media ──────────────────────────────────────────────────────────────────
|
|
83
91
|
export { default as Avatar } from './components/Avatar.svelte';
|
|
84
92
|
export { default as AvatarGroup } from './components/AvatarGroup.svelte';
|
|
@@ -108,4 +116,4 @@ export * as motion from './motion.js';
|
|
|
108
116
|
// ── Version ────────────────────────────────────────────────────────────────
|
|
109
117
|
// Generated from package.json by `pnpm version:sync`. Bump package.json, never
|
|
110
118
|
// this line. The build and the test suite fail when the two disagree.
|
|
111
|
-
export const VERSION = '0.
|
|
119
|
+
export const VERSION = '0.38.0';
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Both controls report the same three states on the same clock, so a value
|
|
5
5
|
* copied from a field and one copied from a code block confirm the same way.
|
|
6
|
+
* The package entry point exports the write and the state too, so a control
|
|
7
|
+
* the kit does not ship confirms the same way as well.
|
|
6
8
|
*/
|
|
9
|
+
/** Where the last copy stands: at rest, confirmed, or refused. */
|
|
7
10
|
export type CopyStatus = 'idle' | 'copied' | 'failed';
|
|
8
11
|
/** How long the confirmation holds before the control returns to rest. */
|
|
9
12
|
export declare const COPY_REVERT_MS = 1500;
|
|
@@ -16,9 +19,17 @@ export declare const COPY_FAILED_MESSAGE = "Copy failed";
|
|
|
16
19
|
* writeText rejects while the document is not focused. Either way the value
|
|
17
20
|
* goes through a selected, off-screen textarea and the legacy copy command,
|
|
18
21
|
* which the browser still honors inside the click. Only when that also
|
|
19
|
-
* refuses
|
|
22
|
+
* refuses does it resolve to false. It never throws.
|
|
23
|
+
*/
|
|
24
|
+
export declare function copyToClipboard(value: string): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* A copy and its outcome, on the clock CopyButton and CopyField confirm on.
|
|
27
|
+
*
|
|
28
|
+
* `status` reads `copied` or `failed` for 1.5 seconds after `copy` and `idle`
|
|
29
|
+
* otherwise. It is reactive, so markup that reads it follows it. Create one
|
|
30
|
+
* per control while the component initializes, and call `dispose` when that
|
|
31
|
+
* component unmounts, so the revert timer cannot fire after it.
|
|
20
32
|
*/
|
|
21
|
-
export declare function writeClipboard(value: string): Promise<boolean>;
|
|
22
33
|
export declare class CopyState {
|
|
23
34
|
#private;
|
|
24
35
|
status: CopyStatus;
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Both controls report the same three states on the same clock, so a value
|
|
5
5
|
* copied from a field and one copied from a code block confirm the same way.
|
|
6
|
+
* The package entry point exports the write and the state too, so a control
|
|
7
|
+
* the kit does not ship confirms the same way as well.
|
|
6
8
|
*/
|
|
7
9
|
/** How long the confirmation holds before the control returns to rest. */
|
|
8
10
|
export const COPY_REVERT_MS = 1500;
|
|
@@ -15,9 +17,9 @@ export const COPY_FAILED_MESSAGE = 'Copy failed';
|
|
|
15
17
|
* writeText rejects while the document is not focused. Either way the value
|
|
16
18
|
* goes through a selected, off-screen textarea and the legacy copy command,
|
|
17
19
|
* which the browser still honors inside the click. Only when that also
|
|
18
|
-
* refuses
|
|
20
|
+
* refuses does it resolve to false. It never throws.
|
|
19
21
|
*/
|
|
20
|
-
export async function
|
|
22
|
+
export async function copyToClipboard(value) {
|
|
21
23
|
const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;
|
|
22
24
|
if (clipboard) {
|
|
23
25
|
try {
|
|
@@ -50,6 +52,14 @@ function legacyCopy(value) {
|
|
|
50
52
|
area.remove();
|
|
51
53
|
}
|
|
52
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* A copy and its outcome, on the clock CopyButton and CopyField confirm on.
|
|
57
|
+
*
|
|
58
|
+
* `status` reads `copied` or `failed` for 1.5 seconds after `copy` and `idle`
|
|
59
|
+
* otherwise. It is reactive, so markup that reads it follows it. Create one
|
|
60
|
+
* per control while the component initializes, and call `dispose` when that
|
|
61
|
+
* component unmounts, so the revert timer cannot fire after it.
|
|
62
|
+
*/
|
|
53
63
|
export class CopyState {
|
|
54
64
|
status = $state('idle');
|
|
55
65
|
#timer;
|
|
@@ -57,7 +67,7 @@ export class CopyState {
|
|
|
57
67
|
// A second press restarts the window. Without this the first press's timer
|
|
58
68
|
// reverts the second copy part way through its own.
|
|
59
69
|
clearTimeout(this.#timer);
|
|
60
|
-
this.status = (await
|
|
70
|
+
this.status = (await copyToClipboard(value)) ? 'copied' : 'failed';
|
|
61
71
|
this.#timer = setTimeout(() => (this.status = 'idle'), COPY_REVERT_MS);
|
|
62
72
|
}
|
|
63
73
|
dispose() {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Turns a page's name into the words its browser tab shows. */
|
|
2
|
+
export type DocumentTitleFormat = (title: string) => string;
|
|
3
|
+
/**
|
|
4
|
+
* States the format every PageShell below the calling component renders its
|
|
5
|
+
* document title in. Call it while a layout initializes, the way any context
|
|
6
|
+
* is set. A format that reads reactive state is run again when that state
|
|
7
|
+
* changes.
|
|
8
|
+
*/
|
|
9
|
+
export declare function setDocumentTitleFormat(format: DocumentTitleFormat): void;
|
|
10
|
+
/** The format a layout above stated, or undefined when none did. */
|
|
11
|
+
export declare function getDocumentTitleFormat(): DocumentTitleFormat | undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words a browser tab shows for a page, stated once for a whole app.
|
|
3
|
+
*
|
|
4
|
+
* A console rendered its own title element on every page, and each page spelled
|
|
5
|
+
* the suffix after the page name for itself. PageShell already holds the page's
|
|
6
|
+
* name, so an app that states the format once in its root layout gets every
|
|
7
|
+
* PageShell page titled the same way. An app that states none gets no title
|
|
8
|
+
* from the kit at all, and its pages keep whatever they render themselves.
|
|
9
|
+
*
|
|
10
|
+
* Context rather than a module variable: one server process renders pages for
|
|
11
|
+
* every visitor, and a format that reads the request (a tenant's name, say)
|
|
12
|
+
* would otherwise leak from one render into the next.
|
|
13
|
+
*/
|
|
14
|
+
import { getContext, setContext } from 'svelte';
|
|
15
|
+
const FORMAT = Symbol('document-title-format');
|
|
16
|
+
/**
|
|
17
|
+
* States the format every PageShell below the calling component renders its
|
|
18
|
+
* document title in. Call it while a layout initializes, the way any context
|
|
19
|
+
* is set. A format that reads reactive state is run again when that state
|
|
20
|
+
* changes.
|
|
21
|
+
*/
|
|
22
|
+
export function setDocumentTitleFormat(format) {
|
|
23
|
+
setContext(FORMAT, format);
|
|
24
|
+
}
|
|
25
|
+
/** The format a layout above stated, or undefined when none did. */
|
|
26
|
+
export function getDocumentTitleFormat() {
|
|
27
|
+
return getContext(FORMAT);
|
|
28
|
+
}
|
package/dist/internal/field.d.ts
CHANGED
|
@@ -105,3 +105,11 @@ export declare function segmentedBorder(error: boolean): string;
|
|
|
105
105
|
* by the wrapper's own rounding.
|
|
106
106
|
*/
|
|
107
107
|
export declare const CONTROL_SEGMENT: string;
|
|
108
|
+
/**
|
|
109
|
+
* Joins a control's own message id with the ids its caller names.
|
|
110
|
+
*
|
|
111
|
+
* A control inside a Field, or explained by text elsewhere on the page, has to
|
|
112
|
+
* point at that text as well as at its own hint or error. Returns undefined
|
|
113
|
+
* when there is nothing to point at, for the reason describedBy does.
|
|
114
|
+
*/
|
|
115
|
+
export declare function joinIds(...ids: (string | undefined)[]): string | undefined;
|
package/dist/internal/field.js
CHANGED
|
@@ -134,3 +134,13 @@ export function segmentedBorder(error) {
|
|
|
134
134
|
export const CONTROL_SEGMENT = 'shrink-0 rounded-sm border-0 bg-transparent p-0 text-center text-sm text-fg tabular-nums ' +
|
|
135
135
|
'outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand ' +
|
|
136
136
|
'disabled:cursor-not-allowed';
|
|
137
|
+
/**
|
|
138
|
+
* Joins a control's own message id with the ids its caller names.
|
|
139
|
+
*
|
|
140
|
+
* A control inside a Field, or explained by text elsewhere on the page, has to
|
|
141
|
+
* point at that text as well as at its own hint or error. Returns undefined
|
|
142
|
+
* when there is nothing to point at, for the reason describedBy does.
|
|
143
|
+
*/
|
|
144
|
+
export function joinIds(...ids) {
|
|
145
|
+
return ids.filter(Boolean).join(' ') || undefined;
|
|
146
|
+
}
|
package/package.json
CHANGED