lutra 0.1.68 → 0.1.70
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/AspectRatio.svelte +19 -9
- package/dist/components/AspectRatio.svelte.d.ts +2 -1
- package/dist/components/Avatar.svelte +5 -8
- package/dist/components/Close.svelte +24 -27
- package/dist/components/Close.svelte.d.ts +2 -0
- package/dist/components/ContextTip.svelte +3 -2
- package/dist/components/DataList.svelte +111 -0
- package/dist/components/DataList.svelte.d.ts +10 -0
- package/dist/components/DataListTypes.d.ts +14 -0
- package/dist/components/DataListTypes.js +1 -0
- package/dist/components/Dialog.svelte +38 -0
- package/dist/components/Icon.svelte +2 -2
- package/dist/components/IconButton.svelte +10 -22
- package/dist/components/Image.svelte +2 -2
- package/dist/components/Indicator.svelte +2 -1
- package/dist/components/Inset.svelte +13 -0
- package/dist/components/Layout.svelte +7 -3
- package/dist/components/Layout.svelte.d.ts +3 -2
- package/dist/components/MenuDropdown.svelte +12 -2
- package/dist/components/MenuItem.svelte +30 -14
- package/dist/components/MenuItem.svelte.d.ts +6 -0
- package/dist/components/Modal.svelte +36 -20
- package/dist/components/Popover.svelte +43 -13
- package/dist/components/TabbedContent.svelte +1 -1
- package/dist/components/TabbedContentItem.svelte +14 -0
- package/dist/components/TabbedContentItem.svelte.d.ts +4 -0
- package/dist/components/Table.svelte +69 -0
- package/dist/components/Table.svelte.d.ts +7 -0
- package/dist/components/Tabs.svelte +44 -36
- package/dist/components/Tag.svelte +53 -13
- package/dist/components/Tag.svelte.d.ts +4 -0
- package/dist/components/Theme.svelte +121 -94
- package/dist/components/Theme.svelte.d.ts +7 -6
- package/dist/components/Toast.svelte +11 -8
- package/dist/components/Tooltip.svelte +17 -10
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/css/1-props.css +197 -163
- package/dist/css/2-init.css +519 -0
- package/dist/css/{2-base.css → 3-base.css} +42 -131
- package/dist/css/{3-typo.css → 4-typo.css} +3 -1
- package/dist/css/lutra.css +7 -6
- package/dist/css/themes/DefaultTheme.css +26 -4
- package/dist/form/Button.svelte +20 -0
- package/dist/form/Button.svelte.d.ts +9 -0
- package/dist/form/Datepicker.svelte +13 -0
- package/dist/form/Datepicker.svelte.d.ts +3 -0
- package/dist/form/FieldContent.svelte +20 -11
- package/dist/form/FieldError.svelte +1 -1
- package/dist/form/FieldGroup.svelte +84 -0
- package/dist/form/FieldGroup.svelte.d.ts +20 -0
- package/dist/form/Fieldset.svelte +19 -11
- package/dist/form/Form.svelte +137 -63
- package/dist/form/Form.svelte.d.ts +21 -0
- package/dist/form/FormActions.svelte +21 -3
- package/dist/form/FormActions.svelte.d.ts +3 -0
- package/dist/form/FormSection.svelte +22 -20
- package/dist/form/ImageUpload.svelte +50 -30
- package/dist/form/ImageUpload.svelte.d.ts +14 -0
- package/dist/form/Input.svelte +62 -30
- package/dist/form/Input.svelte.d.ts +0 -1
- package/dist/form/InputLength.svelte +5 -5
- package/dist/form/Label.svelte +6 -6
- package/dist/form/LogoUpload.svelte +24 -10
- package/dist/form/Select.svelte +23 -10
- package/dist/form/Select.svelte.d.ts +6 -6
- package/dist/form/Textarea.svelte +11 -1
- package/dist/form/Toggle.svelte +162 -0
- package/dist/form/Toggle.svelte.d.ts +31 -17
- package/dist/form/client.svelte.js +0 -2
- package/dist/form/index.d.ts +1 -0
- package/dist/form/index.js +1 -0
- package/dist/state/Persisted.svelte.d.ts +6 -0
- package/dist/state/Persisted.svelte.js +29 -0
- package/dist/state/theme.svelte.d.ts +7 -0
- package/dist/state/theme.svelte.js +14 -0
- package/dist/types.d.ts +6 -23
- package/dist/types.js +0 -17
- package/dist/util/color.js +2 -2
- package/package.json +5 -4
- package/dist/config.d.ts +0 -30
- package/dist/config.js +0 -18
- /package/dist/css/{4-layout.css → 5-layout.css} +0 -0
- /package/dist/css/{5-media.css → 6-media.css} +0 -0
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description
|
|
6
|
+
* A wrapper that enforces an aspect ratio on its children. Accepts numeric, ratio string, or colon-separated formats.
|
|
7
|
+
* @cssprop --aspect-ratio - The aspect ratio of the container. (Default: 16 / 9)
|
|
8
|
+
* @example
|
|
9
|
+
* <AspectRatio ratio="4:3">
|
|
10
|
+
* <img src="photo.jpg" alt="Photo" style="width: 100%; height: 100%; object-fit: cover;" />
|
|
11
|
+
* </AspectRatio>
|
|
12
|
+
*/
|
|
3
13
|
let {
|
|
4
|
-
ratio = 16 / 9,
|
|
14
|
+
ratio = "16 / 9",
|
|
5
15
|
children
|
|
6
16
|
}: {
|
|
7
|
-
ratio
|
|
17
|
+
/** Aspect ratio as a number (e.g. 1.778), a ratio string (e.g. "16 / 9"), or colon-separated (e.g. "16:9"). */
|
|
18
|
+
ratio?: number | string;
|
|
8
19
|
children: Snippet;
|
|
9
20
|
} = $props();
|
|
21
|
+
|
|
22
|
+
const cssRatio = $derived(
|
|
23
|
+
typeof ratio === "string" ? ratio.replace(":", " / ") : ratio
|
|
24
|
+
);
|
|
10
25
|
</script>
|
|
11
26
|
|
|
12
|
-
<div class="AspectRatio" style="--aspect-ratio: {
|
|
27
|
+
<div class="AspectRatio" style="--aspect-ratio: {cssRatio}">
|
|
13
28
|
{@render children()}
|
|
14
29
|
</div>
|
|
15
30
|
|
|
16
31
|
<style>
|
|
17
|
-
@property --aspect-ratio {
|
|
18
|
-
syntax: "<number-percentage> / <number-percentage>";
|
|
19
|
-
inherits: false;
|
|
20
|
-
initial-value: 16 / 9;
|
|
21
|
-
}
|
|
22
32
|
.AspectRatio {
|
|
23
|
-
aspect-ratio: var(--aspect-ratio);
|
|
33
|
+
aspect-ratio: var(--aspect-ratio, 16 / 9);
|
|
24
34
|
}
|
|
25
35
|
</style>
|
|
26
36
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
-
ratio
|
|
3
|
+
/** Aspect ratio as a number (e.g. 1.778), a ratio string (e.g. "16 / 9"), or colon-separated (e.g. "16:9"). */
|
|
4
|
+
ratio?: number | string;
|
|
4
5
|
children: Snippet;
|
|
5
6
|
};
|
|
6
7
|
declare const AspectRatio: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* You can pick from three crop styles: circle, square, or rounded. The color of the placeholder is based on the name, making each visually distinct from each other.
|
|
10
10
|
* @cssprop --border-radius - The border radius of the avatar when cropped as rounded.
|
|
11
11
|
* @cssprop --mask-image - Custom mask image to use for the avatar.
|
|
12
|
+
* @cssprop --size - The size of the avatar. (Default: 3rem)
|
|
13
|
+
* @cssprop --user-color - The background color of the avatar. (Default: #666666)
|
|
14
|
+
* @cssprop --text-color - The text color of the avatar. (Default: rgba(0,0,0,0.85))
|
|
12
15
|
* @example
|
|
13
16
|
* <p>With picture:</p>
|
|
14
17
|
* <Avatar name="Auth70" shape="rounded" src="https://avatars.githubusercontent.com/u/122825113?s=200&v=4" --size="4rem" />
|
|
@@ -84,11 +87,6 @@
|
|
|
84
87
|
.Avatar.circle { border-radius: 50%; }
|
|
85
88
|
.Avatar.square { border-radius: 0; }
|
|
86
89
|
.Avatar.rounded { border-radius: var(--border-radius); }
|
|
87
|
-
.Avatar img {
|
|
88
|
-
block-size: 100%;
|
|
89
|
-
inline-size: 100%;
|
|
90
|
-
object-fit: cover;
|
|
91
|
-
}
|
|
92
90
|
.Avatar .Placeholder {
|
|
93
91
|
display: flex;
|
|
94
92
|
align-items: center;
|
|
@@ -97,9 +95,8 @@
|
|
|
97
95
|
inline-size: 100%;
|
|
98
96
|
background-color: var(--user-color);
|
|
99
97
|
color: var(--text-color);
|
|
100
|
-
|
|
101
|
-
font-
|
|
102
|
-
font-weight: 600;
|
|
98
|
+
font-size: calc(var(--size, 3rem) * 0.4);
|
|
99
|
+
font-weight: var(--font-weight-medium);
|
|
103
100
|
user-select: none;
|
|
104
101
|
}
|
|
105
102
|
</style>
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* @description
|
|
4
|
+
* A close button rendered as an X icon. Can be absolutely positioned in a corner of its containing element.
|
|
5
|
+
* @cssprop --close-padding - Padding around the icon. (Default: var(--space-xs))
|
|
6
|
+
* @cssprop --close-icon-size - Size of the close icon. (Default: max(1.5rem, 1rem))
|
|
7
|
+
* @example
|
|
8
|
+
* <div style="position: relative; padding: 2rem; border: 1px solid gray;">
|
|
9
|
+
* <Close position="top right" onclick={() => alert('closed')} />
|
|
10
|
+
* <p>Content with a close button</p>
|
|
11
|
+
* </div>
|
|
12
|
+
*/
|
|
2
13
|
let {
|
|
3
14
|
onclick,
|
|
4
15
|
position
|
|
5
16
|
}: {
|
|
17
|
+
/** Callback when the close button is clicked. */
|
|
6
18
|
onclick?: (e: MouseEvent) => void;
|
|
19
|
+
/** Absolute position within the parent container. */
|
|
7
20
|
position?: "top left" | "top right" | "bottom left" | "bottom right";
|
|
8
21
|
} = $props();
|
|
9
22
|
</script>
|
|
@@ -18,10 +31,9 @@
|
|
|
18
31
|
<style>
|
|
19
32
|
.Close {
|
|
20
33
|
cursor: pointer;
|
|
21
|
-
padding: var(--close-padding,
|
|
34
|
+
padding: var(--close-padding, var(--space-xs));
|
|
22
35
|
border-radius: 50%;
|
|
23
|
-
color: var(--text-color
|
|
24
|
-
cursor: pointer;
|
|
36
|
+
color: var(--text-color-p);
|
|
25
37
|
pointer-events: auto;
|
|
26
38
|
border: none;
|
|
27
39
|
}
|
|
@@ -40,37 +52,22 @@
|
|
|
40
52
|
svg {
|
|
41
53
|
display: block;
|
|
42
54
|
margin: 0;
|
|
43
|
-
width: max(1.5rem,
|
|
44
|
-
height: max(1.5rem,
|
|
55
|
+
width: var(--close-icon-size, max(1.5rem, 1rem));
|
|
56
|
+
height: var(--close-icon-size, max(1.5rem, 1rem));
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
.Close:hover {
|
|
48
|
-
color: var(--text-color-subtle
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.Close.top {
|
|
52
|
-
position: absolute;
|
|
53
|
-
top: 0;
|
|
54
|
-
right: 0;
|
|
55
|
-
z-index: 100;
|
|
60
|
+
color: var(--text-color-p-subtle);
|
|
56
61
|
}
|
|
57
62
|
|
|
63
|
+
.Close.top,
|
|
58
64
|
.Close.bottom {
|
|
59
65
|
position: absolute;
|
|
60
|
-
|
|
61
|
-
right: 0;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.Close.left {
|
|
65
|
-
position: absolute;
|
|
66
|
-
top: 0;
|
|
67
|
-
left: 0;
|
|
68
|
-
right: auto;
|
|
66
|
+
z-index: 100;
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
.Close.right
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
69
|
+
.Close.top.right { inset: 0 0 auto auto; }
|
|
70
|
+
.Close.top.left { inset: 0 auto auto 0; }
|
|
71
|
+
.Close.bottom.right { inset: auto 0 0 auto; }
|
|
72
|
+
.Close.bottom.left { inset: auto auto 0 0; }
|
|
76
73
|
</style>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
type $$ComponentProps = {
|
|
2
|
+
/** Callback when the close button is clicked. */
|
|
2
3
|
onclick?: (e: MouseEvent) => void;
|
|
4
|
+
/** Absolute position within the parent container. */
|
|
3
5
|
position?: "top left" | "top right" | "bottom left" | "bottom right";
|
|
4
6
|
};
|
|
5
7
|
declare const Close: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
</script>
|
|
19
19
|
|
|
20
20
|
<Tooltip {tip}>
|
|
21
|
-
<a href="#contexttip" onclick={(e) => { e.preventDefault(); e.stopPropagation(); }}>
|
|
21
|
+
<a class="ContextTip" href="#contexttip" onclick={(e) => { e.preventDefault(); e.stopPropagation(); }}>
|
|
22
22
|
<Icon icon={Help} --icon-width="16px" --icon-height="16px" --cursor="help" --vertical-align="baseline" />
|
|
23
23
|
</a>
|
|
24
24
|
</Tooltip>
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
justify-content: center;
|
|
36
36
|
}
|
|
37
37
|
a:focus-visible {
|
|
38
|
-
|
|
38
|
+
outline: var(--focus-ring);
|
|
39
39
|
outline-offset: 0px;
|
|
40
|
+
color: var(--focus-ring-color);
|
|
40
41
|
}
|
|
41
42
|
</style>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DataListItem } from "./DataListTypes.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description
|
|
6
|
+
* Renders an array of label/value pairs as a semantic description list (`<dl>`).
|
|
7
|
+
* Supports horizontal (side-by-side), vertical (stacked), or auto (container-query
|
|
8
|
+
* responsive) layouts. Values can be plain strings, snippets, render functions,
|
|
9
|
+
* or components.
|
|
10
|
+
*
|
|
11
|
+
* @cssprop --data-list-gap -- Gap between items in the list.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <DataList items={[
|
|
15
|
+
* { label: 'Name', value: 'Alice' },
|
|
16
|
+
* { label: 'Email', value: 'alice@example.com' },
|
|
17
|
+
* ]} />
|
|
18
|
+
*/
|
|
19
|
+
let {
|
|
20
|
+
items,
|
|
21
|
+
direction = 'auto',
|
|
22
|
+
}: {
|
|
23
|
+
/** The data items to display. */
|
|
24
|
+
items: DataListItem[];
|
|
25
|
+
/** Layout direction. 'auto' switches from horizontal to vertical based on container width. */
|
|
26
|
+
direction?: 'horizontal' | 'vertical' | 'auto';
|
|
27
|
+
} = $props();
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<div class="DataList">
|
|
31
|
+
<dl class={direction}>
|
|
32
|
+
{#each items as item}
|
|
33
|
+
<div>
|
|
34
|
+
<dt>{item.label}</dt>
|
|
35
|
+
<dd>
|
|
36
|
+
{#if item.snippet}
|
|
37
|
+
{@render item.snippet()}
|
|
38
|
+
{:else if item.render}
|
|
39
|
+
{@render item.render()}
|
|
40
|
+
{:else if item.component}
|
|
41
|
+
<item.component />
|
|
42
|
+
{:else if item.value}
|
|
43
|
+
{item.value}
|
|
44
|
+
{/if}
|
|
45
|
+
</dd>
|
|
46
|
+
</div>
|
|
47
|
+
{/each}
|
|
48
|
+
</dl>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<style>
|
|
52
|
+
.DataList {
|
|
53
|
+
container-type: inline-size;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
dl {
|
|
57
|
+
margin: 0;
|
|
58
|
+
padding: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
dt {
|
|
62
|
+
color: var(--text-color-p-subtle);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
dd {
|
|
66
|
+
margin: 0;
|
|
67
|
+
color: var(--text-color-p);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Horizontal layout: two-column grid with subgrid for aligned labels
|
|
72
|
+
*/
|
|
73
|
+
dl.horizontal,
|
|
74
|
+
dl.auto {
|
|
75
|
+
display: grid;
|
|
76
|
+
grid-template-columns: auto 1fr;
|
|
77
|
+
gap: var(--data-list-gap);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
dl.horizontal > div,
|
|
81
|
+
dl.auto > div {
|
|
82
|
+
display: grid;
|
|
83
|
+
grid-column: 1 / -1;
|
|
84
|
+
grid-template-columns: subgrid;
|
|
85
|
+
align-items: baseline;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Vertical layout: stacked label over value
|
|
90
|
+
*/
|
|
91
|
+
dl.vertical {
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
gap: var(--data-list-gap);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Auto: switch to vertical when the container is narrow
|
|
99
|
+
*/
|
|
100
|
+
@container (max-width: 300px) {
|
|
101
|
+
dl.auto {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
dl.auto > div {
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DataListItem } from "./DataListTypes.js";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** The data items to display. */
|
|
4
|
+
items: DataListItem[];
|
|
5
|
+
/** Layout direction. 'auto' switches from horizontal to vertical based on container width. */
|
|
6
|
+
direction?: 'horizontal' | 'vertical' | 'auto';
|
|
7
|
+
};
|
|
8
|
+
declare const DataList: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type DataList = ReturnType<typeof DataList>;
|
|
10
|
+
export default DataList;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Component, Snippet } from "svelte";
|
|
2
|
+
import type { RenderFn } from "../types.js";
|
|
3
|
+
export type DataListItem = {
|
|
4
|
+
/** Text label for the item (e.g. "Status", "Email") */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Text value to display */
|
|
7
|
+
value?: string;
|
|
8
|
+
/** Snippet to render as the value */
|
|
9
|
+
snippet?: Snippet;
|
|
10
|
+
/** Render function for the value (works in object literals) */
|
|
11
|
+
render?: RenderFn;
|
|
12
|
+
/** Component to render as the value */
|
|
13
|
+
component?: Component;
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
+
* @description
|
|
5
6
|
* A simple dialog component using the native `<dialog>` element.
|
|
6
7
|
* For more features (buttons, scrim control, etc.), use `<Modal>` instead.
|
|
8
|
+
* Uses modal tokens for styling (background, border, padding, shadow, etc.).
|
|
9
|
+
* @example
|
|
10
|
+
* <Dialog bind:open={showDialog} title="Confirm">
|
|
11
|
+
* <p>Are you sure?</p>
|
|
12
|
+
* </Dialog>
|
|
7
13
|
*/
|
|
8
14
|
let {
|
|
9
15
|
open = $bindable(false),
|
|
@@ -81,6 +87,38 @@
|
|
|
81
87
|
.Dialog[open] {
|
|
82
88
|
display: grid;
|
|
83
89
|
grid-template-rows: auto 1fr;
|
|
90
|
+
opacity: 1;
|
|
91
|
+
translate: 0 0;
|
|
92
|
+
transition:
|
|
93
|
+
opacity var(--transition-duration-fast) ease-out,
|
|
94
|
+
translate var(--transition-duration-fast) ease-out,
|
|
95
|
+
display var(--transition-duration-fast) allow-discrete,
|
|
96
|
+
overlay var(--transition-duration-fast) allow-discrete;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.Dialog[open]::backdrop {
|
|
100
|
+
opacity: 1;
|
|
101
|
+
transition:
|
|
102
|
+
opacity var(--transition-duration-fast) ease-out,
|
|
103
|
+
display var(--transition-duration-fast) allow-discrete,
|
|
104
|
+
overlay var(--transition-duration-fast) allow-discrete;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@starting-style {
|
|
108
|
+
.Dialog[open] {
|
|
109
|
+
opacity: 0;
|
|
110
|
+
translate: 0 var(--space-xs);
|
|
111
|
+
}
|
|
112
|
+
.Dialog[open]::backdrop {
|
|
113
|
+
opacity: 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (prefers-reduced-motion: reduce) {
|
|
118
|
+
.Dialog,
|
|
119
|
+
.Dialog::backdrop {
|
|
120
|
+
transition: none;
|
|
121
|
+
}
|
|
84
122
|
}
|
|
85
123
|
|
|
86
124
|
.DialogHeader {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* @description
|
|
6
6
|
* A component that displays an icon. It can be an image url or a component. The icon will be centered in the container.
|
|
7
|
-
* @cssprop --icon-width - The width of the icon. (Default:
|
|
8
|
-
* @cssprop --icon-height - The height of the icon. (Default:
|
|
7
|
+
* @cssprop --icon-width - The width of the icon. (Default: font-size or 1rem)
|
|
8
|
+
* @cssprop --icon-height - The height of the icon. (Default: font-size or 1rem)
|
|
9
9
|
* @cssprop --icon-color - The color of the icon. (Default: var(--text-color, currentColor))
|
|
10
10
|
* @example
|
|
11
11
|
* <script>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* A component that displays an icon with a possible label. It can also have a click event.
|
|
10
10
|
* The button has a padding of 0.75em by default to make it easier to tap on mobile devices. The padding can be changed using the `--padding` CSS variable.
|
|
11
11
|
* Icon and text color will be inherited from the parent element.
|
|
12
|
-
* @cssprop --padding - The padding of the icon button. (Default:
|
|
12
|
+
* @cssprop --padding - The padding of the icon button. (Default: var(--space-sm))
|
|
13
13
|
* @example
|
|
14
14
|
* <script>
|
|
15
15
|
* import Copy from 'lutra/Icons/Copy.svelte';
|
|
@@ -71,10 +71,11 @@
|
|
|
71
71
|
color: inherit;
|
|
72
72
|
opacity: 1;
|
|
73
73
|
background-color: var(--field-background-color, transparent);
|
|
74
|
-
transition: background-color
|
|
74
|
+
transition: background-color var(--transition-duration-fast);
|
|
75
75
|
border-radius: var(--field-border-radius);
|
|
76
76
|
}
|
|
77
|
-
.IconButton:hover
|
|
77
|
+
.IconButton:hover,
|
|
78
|
+
.IconButton:focus-visible {
|
|
78
79
|
background-color: var(--menu-background-color-hover);
|
|
79
80
|
}
|
|
80
81
|
.IconButton:active {
|
|
@@ -84,37 +85,24 @@
|
|
|
84
85
|
border: none;
|
|
85
86
|
background: none;
|
|
86
87
|
cursor: pointer;
|
|
87
|
-
color: var(--text-color-p, light-dark(black, white));
|
|
88
88
|
}
|
|
89
89
|
.IconMask {
|
|
90
90
|
height: 100%;
|
|
91
|
-
padding-inline: calc(var(--padding,
|
|
92
|
-
padding-block: calc(var(--padding,
|
|
91
|
+
padding-inline: calc(var(--padding, var(--space-sm)) * 0.8);
|
|
92
|
+
padding-block: calc(var(--padding, var(--space-sm)) * 0.8);
|
|
93
93
|
display: inline-grid;
|
|
94
|
-
gap:
|
|
94
|
+
gap: var(--space-xs);
|
|
95
95
|
grid-template: "icon";
|
|
96
96
|
align-items: center;
|
|
97
97
|
}
|
|
98
98
|
.IconMask.mask {
|
|
99
|
-
-webkit-mask-image: linear-gradient(to bottom,
|
|
100
|
-
mask-image: linear-gradient(to bottom,
|
|
99
|
+
-webkit-mask-image: linear-gradient(to bottom, transparent, black 35%, black 65%, transparent);
|
|
100
|
+
mask-image: linear-gradient(to bottom, transparent, black 35%, black 65%, transparent);
|
|
101
101
|
}
|
|
102
102
|
.IconContent {
|
|
103
103
|
grid-area: icon;
|
|
104
104
|
display: inline-flex;
|
|
105
|
-
gap:
|
|
105
|
+
gap: var(--space-xs);
|
|
106
106
|
align-items: center;
|
|
107
107
|
}
|
|
108
|
-
@media(max-width: 960px) {
|
|
109
|
-
.IconMask {
|
|
110
|
-
padding-inline: calc(var(--padding, 0.75em) * 0.75);
|
|
111
|
-
padding-block: calc(var(--padding, 0.75em) * 0.75);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
@media(max-width: 320px) {
|
|
115
|
-
.IconMask {
|
|
116
|
-
padding-inline: calc(var(--padding, 0.75em) * 0.6);
|
|
117
|
-
padding-block: calc(var(--padding, 0.75em) * 0.6);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
108
|
</style>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* <Image aspectRatio="16:9" fit="cover" src="https://images.unsplash.com/photo-1712337646541-d0c6f85447f8" alt="An example image" />
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { BROWSER } from 'esm-env';
|
|
13
13
|
import { decode } from "blurhash";
|
|
14
14
|
import { fade } from "svelte/transition";
|
|
15
15
|
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
let decoded = $state(false);
|
|
97
|
-
let loaded = $state(
|
|
97
|
+
let loaded = $state(BROWSER ? false : true);
|
|
98
98
|
|
|
99
99
|
const onload = () => {
|
|
100
100
|
loaded = true;
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
let _label = $derived(isSet ? StatusColors[color as StatusColor] : label ? label : 'status');
|
|
44
44
|
</script>
|
|
45
45
|
|
|
46
|
-
<span role="status" aria-label="{_label}" class="Indicator {color} {motion}" style="--bgColor: {isSet ? 'var(--status-'+color+')' : color};"></span>
|
|
46
|
+
<span role="status" aria-label="{_label}" class="Indicator {color} {motion}" style="--bgColor: {isSet ? 'var(--status-'+color+'-color)' : color};"></span>
|
|
47
47
|
|
|
48
48
|
<style>
|
|
49
49
|
.Indicator {
|
|
@@ -242,6 +242,7 @@
|
|
|
242
242
|
--mask: radial-gradient(circle, rgba(0, 0, 0, 0) 20%, rgba(0, 0, 0, 0) 45%, black 50%, black 100%);
|
|
243
243
|
-webkit-mask-image: var(--mask);
|
|
244
244
|
mask-image: var(--mask);
|
|
245
|
+
mask-size: 100% 100%;
|
|
245
246
|
filter: drop-shadow(0 0 calc(var(--isize) * 0.05) var(--bgColor));
|
|
246
247
|
}
|
|
247
248
|
.Indicator.spin::after,
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @description
|
|
6
|
+
* Negates the padding of a parent container by applying negative margins, allowing child content (e.g. images) to span edge-to-edge.
|
|
7
|
+
* Reads `--inset-block` and `--inset-inline` from the parent context (typically set by MenuItem or similar).
|
|
8
|
+
* @cssprop --inset-block - The block inset to negate. (Default: 0)
|
|
9
|
+
* @cssprop --inset-inline - The inline inset to negate. (Default: 0)
|
|
10
|
+
* @example
|
|
11
|
+
* <div style="padding: 1rem; --inset-block: 1rem; --inset-inline: 1rem;">
|
|
12
|
+
* <Inset>
|
|
13
|
+
* <img src="banner.jpg" alt="Full-bleed banner" />
|
|
14
|
+
* </Inset>
|
|
15
|
+
* </div>
|
|
16
|
+
*/
|
|
4
17
|
let {
|
|
5
18
|
children,
|
|
6
19
|
}: {
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type
|
|
2
|
+
import { getContext, type Snippet } from "svelte";
|
|
3
3
|
import "../css/lutra.css";
|
|
4
4
|
import Theme from "./Theme.svelte";
|
|
5
5
|
import ToastContainer from "./ToastContainer.svelte";
|
|
6
|
+
import { getContextItem, LutraContext, type LutraContextTypeMap, type LutraTheme } from "../types.js";
|
|
7
|
+
|
|
8
|
+
const lutra = getContext<() => LutraContextTypeMap>('lutra');
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Default layout component that imports styles and provides theming.
|
|
9
12
|
* Includes ToastContainer for toast notifications.
|
|
10
13
|
*/
|
|
11
14
|
let {
|
|
12
|
-
theme,
|
|
15
|
+
theme = lutra()?.[LutraContext.Theme]?.() ?? "system",
|
|
13
16
|
children,
|
|
14
17
|
}: {
|
|
15
18
|
/** The theme to use. Leave empty for auto-detection. */
|
|
16
|
-
theme?:
|
|
19
|
+
theme?: LutraTheme;
|
|
17
20
|
/** The content to display. */
|
|
18
21
|
children: Snippet;
|
|
19
22
|
} = $props();
|
|
23
|
+
|
|
20
24
|
</script>
|
|
21
25
|
|
|
22
26
|
<Theme theme={theme}>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Snippet } from "svelte";
|
|
2
2
|
import "../css/lutra.css";
|
|
3
|
+
import { type LutraTheme } from "../types.js";
|
|
3
4
|
type $$ComponentProps = {
|
|
4
5
|
/** The theme to use. Leave empty for auto-detection. */
|
|
5
|
-
theme?:
|
|
6
|
+
theme?: LutraTheme;
|
|
6
7
|
/** The content to display. */
|
|
7
8
|
children: Snippet;
|
|
8
9
|
};
|
|
@@ -7,8 +7,18 @@
|
|
|
7
7
|
import { arrowNavigation, matchOnType } from "../util/keyboard.svelte.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* @description
|
|
11
|
+
* A dropdown menu built on the Popover component. Handles keyboard navigation (arrow keys, type-ahead)
|
|
12
|
+
* and renders MenuItem entries. Uses menu tokens for styling via the Popover's CSS variable overrides.
|
|
13
|
+
* @example
|
|
14
|
+
* <MenuDropdown
|
|
15
|
+
* trigger="Options"
|
|
16
|
+
* items={[
|
|
17
|
+
* { type: 'item', text: 'Edit', onclick: () => {} },
|
|
18
|
+
* { type: 'divider' },
|
|
19
|
+
* { type: 'item', text: 'Delete', color: 'alert', onclick: () => {} },
|
|
20
|
+
* ]}
|
|
21
|
+
* />
|
|
12
22
|
*/
|
|
13
23
|
let {
|
|
14
24
|
open = $bindable(false),
|