lutra 0.0.33 → 0.1.4
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 +4 -24
- package/dist/components/AspectRatio.svelte +26 -0
- package/dist/components/AspectRatio.svelte.d.ts +8 -0
- package/dist/components/Avatar.svelte +105 -0
- package/dist/components/Avatar.svelte.d.ts +14 -0
- package/dist/{display → components}/Close.svelte +25 -7
- package/dist/components/Close.svelte.d.ts +7 -0
- package/dist/components/ContextTip.svelte +41 -0
- package/dist/components/ContextTip.svelte.d.ts +7 -0
- package/dist/components/Dialog.svelte +78 -0
- package/dist/components/Dialog.svelte.d.ts +14 -0
- package/dist/components/Icon.svelte +62 -0
- package/dist/components/Icon.svelte.d.ts +8 -0
- package/dist/{display → components}/IconButton.svelte +43 -14
- package/dist/components/IconButton.svelte.d.ts +16 -0
- package/dist/components/Image.svelte +172 -0
- package/dist/components/Image.svelte.d.ts +56 -0
- package/dist/{display → components}/Indicator.svelte +44 -9
- package/dist/components/Indicator.svelte.d.ts +12 -0
- package/dist/{display → components}/Inset.svelte +8 -3
- package/dist/components/Inset.svelte.d.ts +7 -0
- package/dist/components/Layout.svelte +33 -0
- package/dist/components/Layout.svelte.d.ts +11 -0
- package/dist/components/MenuDropdown.svelte +195 -0
- package/dist/components/MenuDropdown.svelte.d.ts +16 -0
- package/dist/{nav → components}/MenuItem.svelte +46 -38
- package/dist/components/MenuItem.svelte.d.ts +11 -0
- package/dist/components/MenuItemContent.svelte +25 -0
- package/dist/components/MenuItemContent.svelte.d.ts +10 -0
- package/dist/{nav → components}/MenuTypes.d.ts +19 -5
- package/dist/components/Modal.svelte +149 -0
- package/dist/components/Modal.svelte.d.ts +16 -0
- package/dist/{display → components}/Notification.svelte +33 -22
- package/dist/components/Notification.svelte.d.ts +12 -0
- package/dist/components/Overlay.svelte +31 -0
- package/dist/components/Overlay.svelte.d.ts +14 -0
- package/dist/{layout → components}/OverlayContainer.svelte +6 -3
- package/dist/{layout → components}/OverlayContainer.svelte.d.ts +4 -1
- package/dist/components/OverlayLayer.svelte +168 -0
- package/dist/components/OverlayLayer.svelte.d.ts +8 -0
- package/dist/components/PageContent.svelte +108 -0
- package/dist/components/PageContent.svelte.d.ts +38 -0
- package/dist/components/TabbedContent.svelte +74 -0
- package/dist/components/TabbedContent.svelte.d.ts +11 -0
- package/dist/components/TabbedContentItem.svelte +33 -0
- package/dist/components/TabbedContentItem.svelte.d.ts +10 -0
- package/dist/components/Table.svelte +41 -0
- package/dist/components/Table.svelte.d.ts +13 -0
- package/dist/{nav → components}/Tabs.svelte +99 -41
- package/dist/components/Tabs.svelte.d.ts +20 -0
- package/dist/components/Tag.svelte +120 -0
- package/dist/components/Tag.svelte.d.ts +21 -0
- package/dist/components/Theme.svelte +105 -0
- package/dist/components/Theme.svelte.d.ts +17 -0
- package/dist/{display → components}/Tooltip.svelte +41 -16
- package/dist/components/Tooltip.svelte.d.ts +12 -0
- package/dist/components/UIContent.svelte +19 -0
- package/dist/components/UIContent.svelte.d.ts +7 -0
- package/dist/components/index.d.ts +28 -0
- package/dist/components/index.js +29 -0
- package/dist/{display → components}/notifications.svelte.d.ts +1 -1
- package/dist/{display → components}/notifications.svelte.js +3 -4
- package/dist/{layout → components}/overlays.svelte.d.ts +4 -2
- package/dist/config.d.ts +30 -0
- package/dist/config.js +18 -0
- package/dist/css/1-props.css +440 -0
- package/dist/css/2-base.css +343 -0
- package/dist/css/3-typo.css +106 -0
- package/dist/css/4-layout.css +368 -0
- package/dist/css/5-media.css +116 -0
- package/dist/css/lutra.css +7 -0
- package/dist/css/themes/DefaultTheme.css +209 -0
- package/dist/form/Button.svelte +35 -16
- package/dist/form/Button.svelte.d.ts +8 -19
- package/dist/form/Datepicker.svelte +311 -0
- package/dist/form/Datepicker.svelte.d.ts +9 -0
- package/dist/form/FieldContent.svelte +69 -44
- package/dist/form/FieldContent.svelte.d.ts +7 -17
- package/dist/form/FieldError.svelte +16 -6
- package/dist/form/FieldError.svelte.d.ts +4 -15
- package/dist/form/Fieldset.svelte +48 -13
- package/dist/form/Fieldset.svelte.d.ts +5 -16
- package/dist/form/Form.svelte +158 -74
- package/dist/form/Form.svelte.d.ts +17 -17
- package/dist/form/{FieldActions.svelte → FormActions.svelte} +29 -17
- package/dist/form/FormActions.svelte.d.ts +9 -0
- package/dist/form/FormSection.svelte +96 -0
- package/dist/form/FormSection.svelte.d.ts +9 -0
- package/dist/form/ImageUpload.svelte +134 -94
- package/dist/form/ImageUpload.svelte.d.ts +5 -16
- package/dist/form/Input.svelte +254 -136
- package/dist/form/Input.svelte.d.ts +12 -21
- package/dist/form/InputLength.svelte +15 -5
- package/dist/form/InputLength.svelte.d.ts +4 -15
- package/dist/form/Label.svelte +55 -11
- package/dist/form/Label.svelte.d.ts +6 -15
- package/dist/form/LogoUpload.svelte +36 -21
- package/dist/form/LogoUpload.svelte.d.ts +4 -15
- package/dist/form/Select.svelte +100 -50
- package/dist/form/Select.svelte.d.ts +5 -16
- package/dist/form/Textarea.svelte +200 -98
- package/dist/form/Textarea.svelte.d.ts +11 -24
- package/dist/form/Toggle.svelte +3 -1
- package/dist/form/Toggle.svelte.d.ts +4 -1
- package/dist/form/client.svelte.d.ts +1 -0
- package/dist/form/client.svelte.js +6 -2
- package/dist/form/form.d.ts +10 -9
- package/dist/form/form.js +37 -32
- package/dist/form/index.d.ts +3 -4
- package/dist/form/index.js +3 -4
- package/dist/form/types.d.ts +9 -16
- package/dist/icons/IconAlert.svelte.d.ts +4 -1
- package/dist/icons/IconCopy.svelte.d.ts +4 -1
- package/dist/icons/IconDone.svelte.d.ts +4 -1
- package/dist/icons/IconError.svelte.d.ts +4 -1
- package/dist/icons/IconHelp.svelte.d.ts +4 -1
- package/dist/icons/IconHide.svelte.d.ts +4 -1
- package/dist/icons/IconInfo.svelte.d.ts +4 -1
- package/dist/icons/IconLink.svelte.d.ts +4 -1
- package/dist/icons/IconMenuBurger.svelte.d.ts +4 -1
- package/dist/icons/IconMenuDots.svelte.d.ts +4 -1
- package/dist/icons/IconSearch.svelte.d.ts +4 -1
- package/dist/icons/IconShow.svelte.d.ts +4 -1
- package/dist/icons/IconSuccess.svelte.d.ts +4 -1
- package/dist/icons/IconWarning.svelte.d.ts +4 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -2
- package/dist/types.d.ts +39 -0
- package/dist/types.js +25 -0
- package/dist/util/StringOrComponent.svelte +20 -0
- package/dist/util/StringOrComponent.svelte.d.ts +8 -0
- package/dist/util/StringOrSnippet.svelte +16 -0
- package/dist/util/StringOrSnippet.svelte.d.ts +8 -0
- package/dist/{utils → util}/dom.js +1 -2
- package/dist/util/locale.d.ts +1 -0
- package/dist/util/locale.js +47 -0
- package/dist/util/settings.d.ts +4 -0
- package/package.json +35 -79
- package/dist/color.css +0 -0
- package/dist/display/Avatar.svelte +0 -61
- package/dist/display/Avatar.svelte.d.ts +0 -19
- package/dist/display/Badge.svelte +0 -91
- package/dist/display/Badge.svelte.d.ts +0 -30
- package/dist/display/Callout.svelte +0 -109
- package/dist/display/Callout.svelte.d.ts +0 -28
- package/dist/display/Close.svelte.d.ts +0 -18
- package/dist/display/Code.svelte +0 -190
- package/dist/display/Code.svelte.d.ts +0 -32
- package/dist/display/ContextTip.svelte +0 -23
- package/dist/display/ContextTip.svelte.d.ts +0 -18
- package/dist/display/DataList.svelte +0 -16
- package/dist/display/DataList.svelte.d.ts +0 -21
- package/dist/display/Details.svelte +0 -49
- package/dist/display/Details.svelte.d.ts +0 -27
- package/dist/display/Hero.svelte +0 -50
- package/dist/display/Hero.svelte.d.ts +0 -26
- package/dist/display/Icon.svelte +0 -39
- package/dist/display/Icon.svelte.d.ts +0 -19
- package/dist/display/IconButton.svelte.d.ts +0 -27
- package/dist/display/Image.svelte +0 -91
- package/dist/display/Image.svelte.d.ts +0 -26
- package/dist/display/Indicator.svelte.d.ts +0 -23
- package/dist/display/Inset.svelte.d.ts +0 -18
- package/dist/display/LineChart.svelte +0 -385
- package/dist/display/LineChart.svelte.d.ts +0 -24
- package/dist/display/LoadingIndicator.svelte +0 -33
- package/dist/display/LoadingIndicator.svelte.d.ts +0 -15
- package/dist/display/Modal.svelte +0 -116
- package/dist/display/Modal.svelte.d.ts +0 -27
- package/dist/display/Notification.svelte.d.ts +0 -23
- package/dist/display/Panel.svelte +0 -23
- package/dist/display/Panel.svelte.d.ts +0 -19
- package/dist/display/Popup.svelte +0 -111
- package/dist/display/Popup.svelte.d.ts +0 -25
- package/dist/display/Stat.svelte +0 -81
- package/dist/display/Stat.svelte.d.ts +0 -30
- package/dist/display/Table.svelte +0 -28
- package/dist/display/Table.svelte.d.ts +0 -24
- package/dist/display/TablePaginator.svelte +0 -51
- package/dist/display/TablePaginator.svelte.d.ts +0 -21
- package/dist/display/Tag.svelte +0 -90
- package/dist/display/Tag.svelte.d.ts +0 -32
- package/dist/display/Tooltip.svelte.d.ts +0 -23
- package/dist/display/chart.d.ts +0 -78
- package/dist/display/chart.js +0 -212
- package/dist/display/index.d.ts +0 -24
- package/dist/display/index.js +0 -24
- package/dist/form/FieldActions.svelte.d.ts +0 -20
- package/dist/form/FieldContainer.svelte +0 -37
- package/dist/form/FieldContainer.svelte.d.ts +0 -19
- package/dist/form/FieldSection.svelte +0 -86
- package/dist/form/FieldSection.svelte.d.ts +0 -20
- package/dist/layout/Layout.svelte +0 -47
- package/dist/layout/Layout.svelte.d.ts +0 -22
- package/dist/layout/LayoutFooter.svelte +0 -21
- package/dist/layout/LayoutFooter.svelte.d.ts +0 -18
- package/dist/layout/LayoutGrid.svelte +0 -51
- package/dist/layout/LayoutGrid.svelte.d.ts +0 -27
- package/dist/layout/LayoutHeader.svelte +0 -97
- package/dist/layout/LayoutHeader.svelte.d.ts +0 -34
- package/dist/layout/LayoutSideMenu.svelte +0 -55
- package/dist/layout/LayoutSideMenu.svelte.d.ts +0 -21
- package/dist/layout/LayoutTypes.d.ts +0 -15
- package/dist/layout/LayoutTypes.js +0 -9
- package/dist/layout/Overlay.svelte +0 -20
- package/dist/layout/Overlay.svelte.d.ts +0 -25
- package/dist/layout/OverlayLayer.svelte +0 -140
- package/dist/layout/OverlayLayer.svelte.d.ts +0 -19
- package/dist/layout/PageContent.svelte +0 -82
- package/dist/layout/PageContent.svelte.d.ts +0 -25
- package/dist/layout/Theme.svelte +0 -243
- package/dist/layout/Theme.svelte.d.ts +0 -19
- package/dist/layout/UIContent.svelte +0 -15
- package/dist/layout/UIContent.svelte.d.ts +0 -18
- package/dist/layout/index.d.ts +0 -11
- package/dist/layout/index.js +0 -11
- package/dist/nav/Breadcrumb.svelte +0 -82
- package/dist/nav/Breadcrumb.svelte.d.ts +0 -28
- package/dist/nav/Menu.svelte +0 -170
- package/dist/nav/Menu.svelte.d.ts +0 -27
- package/dist/nav/MenuItem.svelte.d.ts +0 -22
- package/dist/nav/NavMenu.svelte +0 -181
- package/dist/nav/NavMenu.svelte.d.ts +0 -19
- package/dist/nav/TabbedContent.svelte +0 -43
- package/dist/nav/TabbedContent.svelte.d.ts +0 -23
- package/dist/nav/Tabs.svelte.d.ts +0 -25
- package/dist/nav/index.d.ts +0 -7
- package/dist/nav/index.js +0 -6
- package/dist/style.css +0 -950
- package/dist/typo/Clamp.svelte +0 -25
- package/dist/typo/Clamp.svelte.d.ts +0 -24
- package/dist/typo/H.svelte +0 -52
- package/dist/typo/H.svelte.d.ts +0 -28
- package/dist/typo/H1.svelte +0 -14
- package/dist/typo/H1.svelte.d.ts +0 -26
- package/dist/typo/H2.svelte +0 -14
- package/dist/typo/H2.svelte.d.ts +0 -26
- package/dist/typo/H3.svelte +0 -14
- package/dist/typo/H3.svelte.d.ts +0 -26
- package/dist/typo/H4.svelte +0 -14
- package/dist/typo/H4.svelte.d.ts +0 -26
- package/dist/typo/H5.svelte +0 -14
- package/dist/typo/H5.svelte.d.ts +0 -26
- package/dist/typo/H6.svelte +0 -14
- package/dist/typo/H6.svelte.d.ts +0 -26
- package/dist/typo/P.svelte +0 -34
- package/dist/typo/P.svelte.d.ts +0 -26
- package/dist/typo/index.d.ts +0 -9
- package/dist/typo/index.js +0 -9
- package/dist/utils/StringOrComponent.svelte +0 -14
- package/dist/utils/StringOrComponent.svelte.d.ts +0 -19
- package/dist/utils/StringOrSnippet.svelte +0 -11
- package/dist/utils/StringOrSnippet.svelte.d.ts +0 -19
- package/dist/utils/defaults.d.ts +0 -4
- package/dist/utils/hooks.server.d.ts +0 -2
- package/dist/utils/hooks.server.js +0 -16
- package/dist/utils/id.d.ts +0 -1
- package/dist/utils/id.js +0 -3
- package/dist/utils/index.d.ts +0 -9
- package/dist/utils/index.js +0 -6
- package/dist/utils/isSnippet.d.ts +0 -3
- package/dist/utils/isSnippet.js +0 -11
- /package/dist/{nav → components}/MenuTypes.js +0 -0
- /package/dist/{layout → components}/overlays.svelte.js +0 -0
- /package/dist/{utils → util}/attr.d.ts +0 -0
- /package/dist/{utils → util}/attr.js +0 -0
- /package/dist/{utils → util}/color.d.ts +0 -0
- /package/dist/{utils → util}/color.js +0 -0
- /package/dist/{utils → util}/dom.d.ts +0 -0
- /package/dist/{utils → util}/keyboard.svelte.d.ts +0 -0
- /package/dist/{utils → util}/keyboard.svelte.js +0 -0
- /package/dist/{utils/defaults.js → util/settings.js} +0 -0
- /package/dist/{utils → util}/transitions.d.ts +0 -0
- /package/dist/{utils → util}/transitions.js +0 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
/**
|
3
|
+
* @description
|
4
|
+
* An image component that can be used to display images with different aspect ratios and fit modes.
|
5
|
+
* Can also decode a BlurHash.
|
6
|
+
* @cssprop --width - The width of the image.
|
7
|
+
* @cssprop --height - The height of the image.
|
8
|
+
* @example
|
9
|
+
* <Image aspectRatio="16:9" fit="cover" src="https://images.unsplash.com/photo-1712337646541-d0c6f85447f8" alt="An example image" />
|
10
|
+
*/
|
11
|
+
|
12
|
+
import { browser } from "$app/environment";
|
13
|
+
import { decode } from "blurhash";
|
14
|
+
import { fade } from "svelte/transition";
|
15
|
+
|
16
|
+
let {
|
17
|
+
hash,
|
18
|
+
width,
|
19
|
+
height,
|
20
|
+
aspectRatio,
|
21
|
+
fit,
|
22
|
+
src,
|
23
|
+
srcset,
|
24
|
+
alt,
|
25
|
+
style = '',
|
26
|
+
class: className,
|
27
|
+
...rest
|
28
|
+
}: {
|
29
|
+
/**
|
30
|
+
* @description
|
31
|
+
* A BlurHash string to decode into an image.
|
32
|
+
*/
|
33
|
+
hash?: string;
|
34
|
+
/**
|
35
|
+
* @description
|
36
|
+
* The aspect ratio of the image.
|
37
|
+
*/
|
38
|
+
aspectRatio?: string;
|
39
|
+
/**
|
40
|
+
* @description
|
41
|
+
* The fit mode of the image.
|
42
|
+
* @default 'cover'
|
43
|
+
*/
|
44
|
+
fit?: 'cover' | 'contain' | 'scale-down';
|
45
|
+
/**
|
46
|
+
* @description
|
47
|
+
* The source URL of the image.
|
48
|
+
*/
|
49
|
+
src?: string;
|
50
|
+
/**
|
51
|
+
* @description
|
52
|
+
* The source URL of the image (with srcset).
|
53
|
+
*/
|
54
|
+
srcset?: string;
|
55
|
+
/**
|
56
|
+
* @description
|
57
|
+
* The alt text of the image.
|
58
|
+
*/
|
59
|
+
alt?: string;
|
60
|
+
/**
|
61
|
+
* @description
|
62
|
+
* The width of the image.
|
63
|
+
*/
|
64
|
+
width?: string | number;
|
65
|
+
/**
|
66
|
+
* @description
|
67
|
+
* The height of the image.
|
68
|
+
*/
|
69
|
+
height?: string | number;
|
70
|
+
/**
|
71
|
+
* @description
|
72
|
+
* Additional style attributes for the image.
|
73
|
+
*/
|
74
|
+
style?: string;
|
75
|
+
/**
|
76
|
+
* @description
|
77
|
+
* Additional classes to apply to the image.
|
78
|
+
*/
|
79
|
+
class?: string;
|
80
|
+
} = $props();
|
81
|
+
|
82
|
+
let canvas: HTMLCanvasElement | null = $state(null);
|
83
|
+
let el: HTMLImageElement | null = $state(null);
|
84
|
+
let elWidth = $state(32);
|
85
|
+
let elHeight = $state(32);
|
86
|
+
|
87
|
+
if(!src && srcset) {
|
88
|
+
const [src1] = srcset.split(", ");
|
89
|
+
src = src1.split(" ")[0];
|
90
|
+
}
|
91
|
+
|
92
|
+
if(aspectRatio) {
|
93
|
+
style += ` aspect-ratio: ${aspectRatio};`;
|
94
|
+
}
|
95
|
+
|
96
|
+
let decoded = $state(false);
|
97
|
+
let loaded = $state(browser ? false : true);
|
98
|
+
|
99
|
+
const onload = () => {
|
100
|
+
loaded = true;
|
101
|
+
};
|
102
|
+
|
103
|
+
$effect(() => {
|
104
|
+
if(hash) {
|
105
|
+
setTimeout(() => {
|
106
|
+
const pixels = decode(hash!, elWidth, elHeight);
|
107
|
+
const ctx = canvas!.getContext("2d");
|
108
|
+
const imageData = ctx!.createImageData(elWidth, elHeight);
|
109
|
+
imageData.data.set(pixels);
|
110
|
+
ctx!.putImageData(imageData, 0, 0);
|
111
|
+
decoded = true;
|
112
|
+
}, 0);
|
113
|
+
}
|
114
|
+
});
|
115
|
+
|
116
|
+
</script>
|
117
|
+
|
118
|
+
<div class="Image" class:loaded>
|
119
|
+
<img
|
120
|
+
bind:this={el}
|
121
|
+
bind:clientWidth={elWidth}
|
122
|
+
bind:clientHeight={elHeight}
|
123
|
+
{onload}
|
124
|
+
{src}
|
125
|
+
{srcset}
|
126
|
+
{alt}
|
127
|
+
width={width ? width : '100%'}
|
128
|
+
height={height ? height : '100%'}
|
129
|
+
{style}
|
130
|
+
class="{className} {fit}"
|
131
|
+
{...rest}
|
132
|
+
/>
|
133
|
+
{#if !loaded && hash}
|
134
|
+
<canvas class:decoded out:fade={{ duration: 100 }} width={elWidth} height={elHeight} bind:this={canvas}></canvas>
|
135
|
+
{/if}
|
136
|
+
</div>
|
137
|
+
|
138
|
+
<style>
|
139
|
+
.Image {
|
140
|
+
position: relative;
|
141
|
+
display: grid;
|
142
|
+
grid-template-areas: "img";
|
143
|
+
width: var(--width, 100%);
|
144
|
+
height: var(--height, 100%);
|
145
|
+
}
|
146
|
+
canvas {
|
147
|
+
z-index: 2;
|
148
|
+
opacity: 0;
|
149
|
+
width: 100%;
|
150
|
+
grid-area: img;
|
151
|
+
transition: opacity var(--transition-speed-slow);
|
152
|
+
}
|
153
|
+
canvas.decoded {
|
154
|
+
opacity: 1;
|
155
|
+
}
|
156
|
+
img {
|
157
|
+
z-index: 1;
|
158
|
+
grid-area: img;
|
159
|
+
display: inline-block;
|
160
|
+
vertical-align: middle;
|
161
|
+
opacity: 0;
|
162
|
+
transition: opacity var(--transition-speed-slow);
|
163
|
+
width: var(--width, 100%);
|
164
|
+
height: var(--height, 100%);
|
165
|
+
}
|
166
|
+
img.cover { object-fit: cover; }
|
167
|
+
img.contain { object-fit: contain; }
|
168
|
+
img.scale-down { object-fit: scale-down; }
|
169
|
+
.Image.loaded img {
|
170
|
+
opacity: 1;
|
171
|
+
}
|
172
|
+
</style>
|
@@ -0,0 +1,56 @@
|
|
1
|
+
type $$ComponentProps = {
|
2
|
+
/**
|
3
|
+
* @description
|
4
|
+
* A BlurHash string to decode into an image.
|
5
|
+
*/
|
6
|
+
hash?: string;
|
7
|
+
/**
|
8
|
+
* @description
|
9
|
+
* The aspect ratio of the image.
|
10
|
+
*/
|
11
|
+
aspectRatio?: string;
|
12
|
+
/**
|
13
|
+
* @description
|
14
|
+
* The fit mode of the image.
|
15
|
+
* @default 'cover'
|
16
|
+
*/
|
17
|
+
fit?: 'cover' | 'contain' | 'scale-down';
|
18
|
+
/**
|
19
|
+
* @description
|
20
|
+
* The source URL of the image.
|
21
|
+
*/
|
22
|
+
src?: string;
|
23
|
+
/**
|
24
|
+
* @description
|
25
|
+
* The source URL of the image (with srcset).
|
26
|
+
*/
|
27
|
+
srcset?: string;
|
28
|
+
/**
|
29
|
+
* @description
|
30
|
+
* The alt text of the image.
|
31
|
+
*/
|
32
|
+
alt?: string;
|
33
|
+
/**
|
34
|
+
* @description
|
35
|
+
* The width of the image.
|
36
|
+
*/
|
37
|
+
width?: string | number;
|
38
|
+
/**
|
39
|
+
* @description
|
40
|
+
* The height of the image.
|
41
|
+
*/
|
42
|
+
height?: string | number;
|
43
|
+
/**
|
44
|
+
* @description
|
45
|
+
* Additional style attributes for the image.
|
46
|
+
*/
|
47
|
+
style?: string;
|
48
|
+
/**
|
49
|
+
* @description
|
50
|
+
* Additional classes to apply to the image.
|
51
|
+
*/
|
52
|
+
class?: string;
|
53
|
+
};
|
54
|
+
declare const Image: import("svelte").Component<$$ComponentProps, {}, "">;
|
55
|
+
type Image = ReturnType<typeof Image>;
|
56
|
+
export default Image;
|
@@ -1,14 +1,49 @@
|
|
1
|
-
<script lang="ts">
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
<script lang="ts">
|
2
|
+
import { isStatusColor, StatusColors, type StatusColorOrString, type StatusColor } from "../util/color.js";
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @description
|
6
|
+
* A status indicator. Can be used to show the state of something, like a task or a process.
|
7
|
+
* @aria role="status"
|
8
|
+
* @aria aria-label="" - The name of the status color if used, otherwise pass a `label` prop.
|
9
|
+
* @cssprop --size - The size of the indicator. (Default: 0.75em)
|
10
|
+
* @cssprop --animation-duration - The duration of the animation when motion is applied. Clamps lower value to 0.5s and upper value to 3s. (Default: 1.2s)
|
11
|
+
* @cssprop --animation-iteration-count - The number of times the animation should repeat. (Default: infinite)
|
12
|
+
* @cssprop --margin-inline - The inline margin for the indicator. (Default: calc(var(--size) * 0.75))
|
13
|
+
* @example
|
14
|
+
* <h5>Without motion</h5>
|
15
|
+
* <p>
|
16
|
+
* <Indicator /> <Indicator color="ok" /> <Indicator color="alert" /> <Indicator color="warn" /> <Indicator color="info" /> <Indicator color="task" /> Static indicators
|
17
|
+
* </p>
|
18
|
+
* <h5>With motion</h5>
|
19
|
+
* <p>
|
20
|
+
* <Indicator motion="tunnel" color="blue" --size="1em" />
|
21
|
+
* <Indicator motion="blink" color="alert" --animation-duration="1s" --size="1em" />
|
22
|
+
* <Indicator motion="spin" color="ok" --size="1em" />
|
23
|
+
* <Indicator motion="bulge" color="alert" --size="1em" />
|
24
|
+
* <Indicator motion="highlight" color="warn" --animation-duration="2s" --size="1em" />
|
25
|
+
* <Indicator motion="pulse" color="task" --size="1em" />
|
26
|
+
* <Indicator motion="typing" color="default" --size="1em" />
|
27
|
+
* Moving indicators
|
28
|
+
* </p>
|
29
|
+
*/
|
30
|
+
let {
|
31
|
+
color = "default",
|
32
|
+
motion,
|
33
|
+
label
|
34
|
+
}: {
|
35
|
+
/** The color of the tag. Select from default status colors or provide a CSS Color value. */
|
36
|
+
color?: StatusColorOrString;
|
37
|
+
/** Possible motion to apply to the indicator. */
|
38
|
+
motion?: "pulse" | "spin" | "blink" | "highlight" | "bulge" | "tunnel" | "typing";
|
39
|
+
/** ARIA label to use when a custom color is applied */
|
40
|
+
label?: string;
|
41
|
+
} = $props();
|
42
|
+
let isSet = $derived(isStatusColor(color));
|
43
|
+
let _label = $derived(isSet ? StatusColors[color as StatusColor] : label ? label : 'status');
|
9
44
|
</script>
|
10
45
|
|
11
|
-
<span role="status" aria-label="{_label}" class="Indicator {color} {motion}" style="--bgColor: {isSet ? 'var(--status-'+color+')' : color};"
|
46
|
+
<span role="status" aria-label="{_label}" class="Indicator {color} {motion}" style="--bgColor: {isSet ? 'var(--status-'+color+')' : color};"></span>
|
12
47
|
|
13
48
|
<style>
|
14
49
|
.Indicator {
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { type StatusColorOrString } from "../util/color.js";
|
2
|
+
type $$ComponentProps = {
|
3
|
+
/** The color of the tag. Select from default status colors or provide a CSS Color value. */
|
4
|
+
color?: StatusColorOrString;
|
5
|
+
/** Possible motion to apply to the indicator. */
|
6
|
+
motion?: "pulse" | "spin" | "blink" | "highlight" | "bulge" | "tunnel" | "typing";
|
7
|
+
/** ARIA label to use when a custom color is applied */
|
8
|
+
label?: string;
|
9
|
+
};
|
10
|
+
declare const Indicator: import("svelte").Component<$$ComponentProps, {}, "">;
|
11
|
+
type Indicator = ReturnType<typeof Indicator>;
|
12
|
+
export default Indicator;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import type { Snippet } from "svelte";
|
3
|
+
import "../css/lutra.css";
|
4
|
+
import Theme from "./Theme.svelte";
|
5
|
+
import OverlayContainer from "./OverlayContainer.svelte";
|
6
|
+
/**
|
7
|
+
* @description
|
8
|
+
* Default layout component that imports default styles and wraps the entire application in a theme.
|
9
|
+
*/
|
10
|
+
let {
|
11
|
+
theme,
|
12
|
+
children,
|
13
|
+
}: {
|
14
|
+
/** The theme to use for the layout. Leave empty to detect automatically or get from user preferences, if any exist. */
|
15
|
+
theme?: 'light' | 'dark' | undefined;
|
16
|
+
/** The content to display. */
|
17
|
+
children: Snippet;
|
18
|
+
} = $props();
|
19
|
+
</script>
|
20
|
+
|
21
|
+
<Theme theme={theme}>
|
22
|
+
<div class="Layout">
|
23
|
+
{@render children()}
|
24
|
+
</div>
|
25
|
+
<OverlayContainer />
|
26
|
+
</Theme>
|
27
|
+
|
28
|
+
<style>
|
29
|
+
.Layout {
|
30
|
+
min-height: 100dvh;
|
31
|
+
height: 100dvh;
|
32
|
+
}
|
33
|
+
</style>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import type { Snippet } from "svelte";
|
2
|
+
import "../css/lutra.css";
|
3
|
+
type $$ComponentProps = {
|
4
|
+
/** The theme to use for the layout. Leave empty to detect automatically or get from user preferences, if any exist. */
|
5
|
+
theme?: 'light' | 'dark' | undefined;
|
6
|
+
/** The content to display. */
|
7
|
+
children: Snippet;
|
8
|
+
};
|
9
|
+
declare const Layout: import("svelte").Component<$$ComponentProps, {}, "">;
|
10
|
+
type Layout = ReturnType<typeof Layout>;
|
11
|
+
export default Layout;
|
@@ -0,0 +1,195 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import type { Snippet } from "svelte";
|
3
|
+
import type { MenuItem as Item } from "./MenuTypes.js";
|
4
|
+
import MenuItem from "./MenuItem.svelte";
|
5
|
+
import UiContent from "./UIContent.svelte";
|
6
|
+
import { arrowNavigation, getNextFocusableElement, matchOnType } from "../util/keyboard.svelte.js";
|
7
|
+
import { findContainingBlock, getPossiblyContainedPosition } from "../util/dom.js";
|
8
|
+
import Overlay from "./Overlay.svelte";
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @description
|
12
|
+
* A menu component that can be used to create dropdown menus.
|
13
|
+
*/
|
14
|
+
let {
|
15
|
+
open = $bindable(false),
|
16
|
+
items,
|
17
|
+
trigger,
|
18
|
+
}: {
|
19
|
+
/** Whether the menu is open */
|
20
|
+
open?: boolean;
|
21
|
+
/** The items to display in the menu */
|
22
|
+
items: Item[];
|
23
|
+
/** The trigger for the menu */
|
24
|
+
trigger: string | Snippet<[{ toggle: () => void, isOpen: boolean }]>;
|
25
|
+
} = $props();
|
26
|
+
|
27
|
+
let _open = $state(open);
|
28
|
+
let triggerEl: HTMLDivElement | null = $state(null);
|
29
|
+
let contentEl: HTMLDivElement | null = $state(null);
|
30
|
+
let menuEl: HTMLDivElement | null = $state(null);
|
31
|
+
let currentIndex: number = $state(-1);
|
32
|
+
let keyboardHasFocus: boolean = $state(false);
|
33
|
+
|
34
|
+
const id = crypto.randomUUID();
|
35
|
+
|
36
|
+
$effect(() => {
|
37
|
+
if(_open) {
|
38
|
+
window.addEventListener('click', clickoutside);
|
39
|
+
window.addEventListener('keydown', onkeydown);
|
40
|
+
} else {
|
41
|
+
window.removeEventListener('click', clickoutside);
|
42
|
+
window.removeEventListener('keydown', onkeydown);
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
function toggle() {
|
47
|
+
_open = !_open;
|
48
|
+
}
|
49
|
+
|
50
|
+
let scrollable = $derived.by(() => {
|
51
|
+
if(!contentEl) return false;
|
52
|
+
return contentEl.scrollHeight > contentEl.clientHeight;
|
53
|
+
});
|
54
|
+
|
55
|
+
function onclick(e: MouseEvent) {
|
56
|
+
e.preventDefault();
|
57
|
+
_open = !_open;
|
58
|
+
}
|
59
|
+
|
60
|
+
function clickoutside(e: MouseEvent) {
|
61
|
+
if(!_open) return;
|
62
|
+
if(contentEl && !contentEl.contains(e.target as Node) && !triggerEl?.contains(e.target as Node)) {
|
63
|
+
_open = false;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
function onkeydown(e: KeyboardEvent) {
|
68
|
+
if(!_open) return;
|
69
|
+
const active = document.activeElement as HTMLButtonElement | HTMLAnchorElement;
|
70
|
+
switch(e.key) {
|
71
|
+
case "Escape":
|
72
|
+
e.preventDefault();
|
73
|
+
_open = false;
|
74
|
+
break;
|
75
|
+
case "Tab":
|
76
|
+
// try to open the next menu if it exists
|
77
|
+
e.preventDefault();
|
78
|
+
e.stopPropagation();
|
79
|
+
_open = false;
|
80
|
+
setTimeout(() => {
|
81
|
+
const nextEl = getNextFocusableElement(menuEl, triggerEl, e.shiftKey ? "previous" : "next");
|
82
|
+
console.log('nextEl', nextEl)
|
83
|
+
if(nextEl) {
|
84
|
+
nextEl.focus();
|
85
|
+
if(nextEl.tagName === "BUTTON" || nextEl.tagName === "A" && nextEl.parentElement?.classList.contains("Trigger")) {
|
86
|
+
nextEl.click();
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}, 0);
|
90
|
+
break;
|
91
|
+
case "ArrowDown":
|
92
|
+
e.preventDefault();
|
93
|
+
arrowNavigation(contentEl, "down");
|
94
|
+
matchOnType(contentEl, e); // call to reset the search
|
95
|
+
keyboardHasFocus = true;
|
96
|
+
break;
|
97
|
+
case "ArrowUp":
|
98
|
+
e.preventDefault();
|
99
|
+
arrowNavigation(contentEl, "up");
|
100
|
+
matchOnType(contentEl, e); // call to reset the search
|
101
|
+
keyboardHasFocus = true;
|
102
|
+
break;
|
103
|
+
case "Enter":
|
104
|
+
case "Space":
|
105
|
+
e.preventDefault();
|
106
|
+
active.click();
|
107
|
+
break;
|
108
|
+
default:
|
109
|
+
matchOnType(contentEl, e);
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
function mouseover(e: MouseEvent, item: Item, index: number) {
|
114
|
+
if(item.type === "item") {
|
115
|
+
currentIndex = index;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
</script>
|
120
|
+
|
121
|
+
|
122
|
+
<UiContent>
|
123
|
+
<div class="MenuDropdown" bind:this={menuEl}>
|
124
|
+
<div
|
125
|
+
class="Trigger"
|
126
|
+
bind:this={triggerEl}
|
127
|
+
>
|
128
|
+
{#if typeof trigger === "string"}
|
129
|
+
<button type="button" class="button" {onclick} aria-haspopup="true" aria-controls={id} aria-expanded="{_open}">
|
130
|
+
{trigger}
|
131
|
+
</button>
|
132
|
+
{:else}
|
133
|
+
{@render trigger({ toggle: toggle, isOpen: _open })}
|
134
|
+
{/if}
|
135
|
+
</div>
|
136
|
+
{#if _open && triggerEl}
|
137
|
+
<Overlay position="anchor" id="o-{id}" anchor={triggerEl} layer="menu">
|
138
|
+
<div {id}
|
139
|
+
class="MenuDropdownContent"
|
140
|
+
class:scrollable={scrollable}
|
141
|
+
role="menu"
|
142
|
+
bind:this={contentEl}
|
143
|
+
>
|
144
|
+
<ul>
|
145
|
+
{#each items as item, index}
|
146
|
+
<MenuItem {keyboardHasFocus} onmouseover={mouseover} item={item} {index} />
|
147
|
+
{/each}
|
148
|
+
</ul>
|
149
|
+
</div>
|
150
|
+
</Overlay>
|
151
|
+
{/if}
|
152
|
+
</div>
|
153
|
+
</UiContent>
|
154
|
+
|
155
|
+
<style>
|
156
|
+
.MenuDropdown {
|
157
|
+
position: relative;
|
158
|
+
}
|
159
|
+
|
160
|
+
.Trigger {
|
161
|
+
position: relative;
|
162
|
+
display: inline-flex;
|
163
|
+
}
|
164
|
+
|
165
|
+
.MenuDropdownContent {
|
166
|
+
max-height: calc(50vh - 2rem);
|
167
|
+
margin: 0;
|
168
|
+
z-index: 1000;
|
169
|
+
margin: 0;
|
170
|
+
border: var(--menu-border-size) var(--menu-border-style) var(--menu-border-color);
|
171
|
+
border-radius: var(--menu-border-radius);
|
172
|
+
box-shadow: 0 0.5rem 1rem var(--shadow-color);
|
173
|
+
background-color: var(--menu-background-color);
|
174
|
+
width: var(--width, 25ch);
|
175
|
+
overflow-x: clip;
|
176
|
+
overflow-y: auto;
|
177
|
+
scrollbar-width: thin;
|
178
|
+
scrollbar-color: var(--scrollbar-color);
|
179
|
+
}
|
180
|
+
|
181
|
+
.MenuDropdownContent.scrollable {
|
182
|
+
border-top-right-radius: 0;
|
183
|
+
border-bottom-right-radius: 0;
|
184
|
+
}
|
185
|
+
|
186
|
+
.MenuDropdownContent :global(:has(li:last-of-type[data-type="item"])) {
|
187
|
+
padding-block-end: 0.5rem;
|
188
|
+
}
|
189
|
+
|
190
|
+
ul {
|
191
|
+
margin: 0;
|
192
|
+
list-style: none;
|
193
|
+
padding: 0;
|
194
|
+
}
|
195
|
+
</style>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import type { Snippet } from "svelte";
|
2
|
+
import type { MenuItem as Item } from "./MenuTypes.js";
|
3
|
+
type $$ComponentProps = {
|
4
|
+
/** Whether the menu is open */
|
5
|
+
open?: boolean;
|
6
|
+
/** The items to display in the menu */
|
7
|
+
items: Item[];
|
8
|
+
/** The trigger for the menu */
|
9
|
+
trigger: string | Snippet<[{
|
10
|
+
toggle: () => void;
|
11
|
+
isOpen: boolean;
|
12
|
+
}]>;
|
13
|
+
};
|
14
|
+
declare const MenuDropdown: import("svelte").Component<$$ComponentProps, {}, "open">;
|
15
|
+
type MenuDropdown = ReturnType<typeof MenuDropdown>;
|
16
|
+
export default MenuDropdown;
|