lutra 0.1.0 → 0.1.5

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.
Files changed (154) hide show
  1. package/dist/components/Avatar.svelte +105 -0
  2. package/dist/components/Avatar.svelte.d.ts +14 -0
  3. package/dist/components/Close.svelte +76 -0
  4. package/dist/components/Close.svelte.d.ts +7 -0
  5. package/dist/components/ContextTip.svelte +41 -0
  6. package/dist/components/ContextTip.svelte.d.ts +7 -0
  7. package/dist/components/Icon.svelte +62 -0
  8. package/dist/components/Icon.svelte.d.ts +8 -0
  9. package/dist/components/IconButton.svelte +120 -0
  10. package/dist/components/IconButton.svelte.d.ts +16 -0
  11. package/dist/components/Image.svelte +172 -0
  12. package/dist/components/Image.svelte.d.ts +56 -0
  13. package/dist/components/Indicator.svelte +387 -0
  14. package/dist/components/Indicator.svelte.d.ts +12 -0
  15. package/dist/components/Inset.svelte +23 -0
  16. package/dist/components/Inset.svelte.d.ts +7 -0
  17. package/dist/components/Layout.svelte +2 -1
  18. package/dist/components/MenuDropdown.svelte +195 -0
  19. package/dist/components/MenuDropdown.svelte.d.ts +16 -0
  20. package/dist/components/MenuItem.svelte +159 -0
  21. package/dist/components/MenuItem.svelte.d.ts +11 -0
  22. package/dist/components/MenuItemContent.svelte +25 -0
  23. package/dist/components/MenuItemContent.svelte.d.ts +10 -0
  24. package/dist/components/MenuTypes.d.ts +79 -0
  25. package/dist/components/MenuTypes.js +1 -0
  26. package/dist/components/Modal.svelte +149 -0
  27. package/dist/components/Modal.svelte.d.ts +16 -0
  28. package/dist/components/Notification.svelte +115 -0
  29. package/dist/components/Notification.svelte.d.ts +12 -0
  30. package/dist/components/Overlay.svelte +31 -0
  31. package/dist/components/Overlay.svelte.d.ts +14 -0
  32. package/dist/components/OverlayContainer.svelte +31 -0
  33. package/dist/components/OverlayContainer.svelte.d.ts +18 -0
  34. package/dist/components/OverlayLayer.svelte +168 -0
  35. package/dist/components/OverlayLayer.svelte.d.ts +8 -0
  36. package/dist/components/PageContent.svelte +4 -82
  37. package/dist/components/PageContent.svelte.d.ts +0 -31
  38. package/dist/components/TabbedContent.svelte +74 -0
  39. package/dist/components/TabbedContent.svelte.d.ts +11 -0
  40. package/dist/components/TabbedContentItem.svelte +33 -0
  41. package/dist/components/TabbedContentItem.svelte.d.ts +10 -0
  42. package/dist/components/Table.svelte +41 -0
  43. package/dist/components/Table.svelte.d.ts +13 -0
  44. package/dist/components/Tabs.svelte +216 -0
  45. package/dist/components/Tabs.svelte.d.ts +20 -0
  46. package/dist/components/Tag.svelte +120 -0
  47. package/dist/components/Tag.svelte.d.ts +21 -0
  48. package/dist/components/Theme.svelte +32 -14
  49. package/dist/components/Tooltip.svelte +8 -8
  50. package/dist/components/UIContent.svelte +19 -0
  51. package/dist/components/UIContent.svelte.d.ts +7 -0
  52. package/dist/components/index.d.ts +28 -0
  53. package/dist/components/index.js +29 -0
  54. package/dist/components/notifications.svelte.d.ts +21 -0
  55. package/dist/components/notifications.svelte.js +30 -0
  56. package/dist/components/overlays.svelte.d.ts +36 -0
  57. package/dist/components/overlays.svelte.js +44 -0
  58. package/dist/css/1-props.css +389 -724
  59. package/dist/css/2-base.css +257 -123
  60. package/dist/css/3-typo.css +74 -34
  61. package/dist/css/4-layout.css +364 -1
  62. package/dist/css/5-media.css +106 -11
  63. package/dist/css/lutra.css +2 -1
  64. package/dist/css/themes/DefaultTheme.css +209 -0
  65. package/dist/form/Button.svelte +58 -0
  66. package/dist/form/Button.svelte.d.ts +15 -0
  67. package/dist/form/Datepicker.svelte +311 -0
  68. package/dist/form/Datepicker.svelte.d.ts +9 -0
  69. package/dist/form/FieldContent.svelte +178 -0
  70. package/dist/form/FieldContent.svelte.d.ts +21 -0
  71. package/dist/form/FieldError.svelte +24 -0
  72. package/dist/form/FieldError.svelte.d.ts +7 -0
  73. package/dist/form/Fieldset.svelte +103 -0
  74. package/dist/form/Fieldset.svelte.d.ts +20 -0
  75. package/dist/form/Form.svelte +220 -0
  76. package/dist/form/Form.svelte.d.ts +38 -0
  77. package/dist/form/FormActions.svelte +80 -0
  78. package/dist/form/FormActions.svelte.d.ts +9 -0
  79. package/dist/form/FormSection.svelte +96 -0
  80. package/dist/form/FormSection.svelte.d.ts +9 -0
  81. package/dist/form/ImageUpload.svelte +299 -0
  82. package/dist/form/ImageUpload.svelte.d.ts +20 -0
  83. package/dist/form/Input.svelte +444 -0
  84. package/dist/form/Input.svelte.d.ts +108 -0
  85. package/dist/form/InputLength.svelte +42 -0
  86. package/dist/form/InputLength.svelte.d.ts +9 -0
  87. package/dist/form/Label.svelte +88 -0
  88. package/dist/form/Label.svelte.d.ts +16 -0
  89. package/dist/form/LogoUpload.svelte +115 -0
  90. package/dist/form/LogoUpload.svelte.d.ts +18 -0
  91. package/dist/form/Select.svelte +186 -0
  92. package/dist/form/Select.svelte.d.ts +59 -0
  93. package/dist/form/Textarea.svelte +265 -0
  94. package/dist/form/Textarea.svelte.d.ts +95 -0
  95. package/dist/form/Toggle.svelte +4 -0
  96. package/dist/form/Toggle.svelte.d.ts +18 -0
  97. package/dist/form/client.svelte.d.ts +45 -0
  98. package/dist/form/client.svelte.js +102 -0
  99. package/dist/form/form.d.ts +55 -0
  100. package/dist/form/form.js +345 -0
  101. package/dist/form/index.d.ts +17 -0
  102. package/dist/form/index.js +17 -0
  103. package/dist/form/types.d.ts +55 -0
  104. package/dist/form/types.js +1 -0
  105. package/dist/icons/IconAlert.svelte +3 -0
  106. package/dist/icons/IconAlert.svelte.d.ts +26 -0
  107. package/dist/icons/IconCopy.svelte +3 -0
  108. package/dist/icons/IconCopy.svelte.d.ts +26 -0
  109. package/dist/icons/IconDone.svelte +3 -0
  110. package/dist/icons/IconDone.svelte.d.ts +26 -0
  111. package/dist/icons/IconError.svelte +3 -0
  112. package/dist/icons/IconError.svelte.d.ts +26 -0
  113. package/dist/icons/IconHelp.svelte +3 -0
  114. package/dist/icons/IconHelp.svelte.d.ts +26 -0
  115. package/dist/icons/IconHide.svelte +3 -0
  116. package/dist/icons/IconHide.svelte.d.ts +26 -0
  117. package/dist/icons/IconInfo.svelte +3 -0
  118. package/dist/icons/IconInfo.svelte.d.ts +26 -0
  119. package/dist/icons/IconLink.svelte +3 -0
  120. package/dist/icons/IconLink.svelte.d.ts +26 -0
  121. package/dist/icons/IconMenuBurger.svelte +3 -0
  122. package/dist/icons/IconMenuBurger.svelte.d.ts +26 -0
  123. package/dist/icons/IconMenuDots.svelte +3 -0
  124. package/dist/icons/IconMenuDots.svelte.d.ts +26 -0
  125. package/dist/icons/IconSearch.svelte +3 -0
  126. package/dist/icons/IconSearch.svelte.d.ts +26 -0
  127. package/dist/icons/IconShow.svelte +3 -0
  128. package/dist/icons/IconShow.svelte.d.ts +26 -0
  129. package/dist/icons/IconSuccess.svelte +3 -0
  130. package/dist/icons/IconSuccess.svelte.d.ts +26 -0
  131. package/dist/icons/IconWarning.svelte +3 -0
  132. package/dist/icons/IconWarning.svelte.d.ts +26 -0
  133. package/dist/icons/index.d.ts +14 -0
  134. package/dist/icons/index.js +14 -0
  135. package/dist/index.d.ts +3 -5
  136. package/dist/index.js +3 -5
  137. package/dist/util/StringOrComponent.svelte +20 -0
  138. package/dist/util/StringOrComponent.svelte.d.ts +8 -0
  139. package/dist/util/StringOrSnippet.svelte +16 -0
  140. package/dist/util/StringOrSnippet.svelte.d.ts +8 -0
  141. package/dist/util/attr.d.ts +5 -0
  142. package/dist/util/attr.js +21 -0
  143. package/dist/util/color.d.ts +51 -0
  144. package/dist/util/color.js +97 -0
  145. package/dist/util/dom.d.ts +15 -0
  146. package/dist/util/dom.js +73 -0
  147. package/dist/util/keyboard.svelte.d.ts +22 -0
  148. package/dist/util/keyboard.svelte.js +161 -0
  149. package/dist/util/locale.d.ts +1 -0
  150. package/dist/util/locale.js +47 -0
  151. package/dist/util/settings.d.ts +4 -0
  152. package/dist/util/settings.js +1 -0
  153. package/package.json +20 -11
  154. package/dist/css/0-layers.css +0 -1
@@ -0,0 +1,159 @@
1
+ <script lang="ts">
2
+ import { isStatusColor } from "../util/color.js";
3
+ import MenuItemContent from "./MenuItemContent.svelte";
4
+ import type { MenuItem as Item } from "./MenuTypes.js";
5
+
6
+ let {
7
+ item,
8
+ index,
9
+ onmouseover,
10
+ keyboardHasFocus,
11
+ shape = 'default',
12
+ }: {
13
+ item: Item;
14
+ index: number;
15
+ onmouseover?: (e: MouseEvent, item: Item, index: number) => void;
16
+ keyboardHasFocus?: boolean;
17
+ shape?: 'default' | 'rounded' | 'pill';
18
+ } = $props();
19
+
20
+ let isSet = $derived(item.type !== 'divider' ? isStatusColor(item.color) : false);
21
+ let el: HTMLElement | null = $state(null);
22
+
23
+ function mouseover(e: MouseEvent) {
24
+ if(onmouseover && item.type === "item") {
25
+ el?.focus();
26
+ }
27
+ }
28
+ </script>
29
+
30
+ <!-- svelte-ignore a11y_mouse_events_have_key_events -->
31
+ <li
32
+ onmouseover={mouseover}
33
+ data-index={index}
34
+ class:keyboardHasFocus
35
+ class:divider={item.type === 'divider'}
36
+ class:header={item.type === 'header'}
37
+ class={shape}
38
+ data-type="{item.type}"
39
+ style="--color: {isSet && item.type !== 'divider' ? 'var(--status-'+item.color+')' : (item.type !== 'divider' && item.color ? item.color : 'var(--menu-text)')}"
40
+ >
41
+ {#if item.type === 'divider'}
42
+ <hr />
43
+ {:else if item.type === 'header'}
44
+ <div class="Header">
45
+ <MenuItemContent {...item} />
46
+ </div>
47
+ {:else if item.type === 'text'}
48
+ <div class="Text">
49
+ <MenuItemContent {...item} />
50
+ </div>
51
+ {:else if item.type === 'item'}
52
+ {#if item.href}
53
+ <a href="{item.href}" class="Item" bind:this={el}>
54
+ <span class="Content">
55
+ <MenuItemContent {...item} />
56
+ </span>
57
+ {#if item.shortcut}
58
+ <span class="Shortcut">{item.shortcut}</span>
59
+ {/if}
60
+ </a>
61
+ {:else if item.onclick}
62
+ <button type="button" onclick={(e) => item.type === 'item' ? item.onclick!(e, item) : undefined} class="Item" bind:this={el}>
63
+ <span class="Content">
64
+ <MenuItemContent {...item} />
65
+ </span>
66
+ {#if item.shortcut}
67
+ <span class="Shortcut">{item.shortcut}</span>
68
+ {/if}
69
+ </button>
70
+ {:else if item.component}
71
+ <div class="Item Custom">
72
+ <MenuItemContent {...item} />
73
+ </div>
74
+ {/if}
75
+ {/if}
76
+ </li>
77
+
78
+ <style>
79
+ button {
80
+ background-color: transparent;
81
+ border: none;
82
+ padding: 0;
83
+ margin: 0;
84
+ font: inherit;
85
+ color: inherit;
86
+ text-align: left;
87
+ }
88
+ li {
89
+ margin: 0;
90
+ list-style: none;
91
+ padding: 0;
92
+ user-select: none;
93
+ }
94
+
95
+ li .Item,
96
+ li .Header {
97
+ font-size: var(--font-size, 0.9em);
98
+ text-align: left;
99
+ padding-block: 0.5rem;
100
+ padding-inline: 1rem;
101
+ display: inline-flex;
102
+ align-items: center;
103
+ justify-content: space-between;
104
+ width: 100%;
105
+ color: inherit;
106
+ text-decoration: none;
107
+ color: var(--color);
108
+ --inset-block: 0.5rem;
109
+ --inset-inline: 1rem;
110
+ border-radius: none;
111
+ }
112
+
113
+ li.rounded .Item,
114
+ li.rounded .Header {
115
+ border-radius: var(--menu-border-radius);
116
+ }
117
+
118
+ li .Header {
119
+ font-weight: 600;
120
+ }
121
+
122
+ li:not(.keyboardHasFocus) .Item:not(.Custom):hover,
123
+ li .Item:not(.Custom):focus-visible {
124
+ background-color: var(--menu-background-color-hover);
125
+ cursor: pointer;
126
+ outline: none;
127
+ }
128
+
129
+ li .Item span.Shortcut {
130
+ font-size: max(0.75em, 9px);
131
+ text-align: right;
132
+ color: var(--menu-text-color-subtle);
133
+ }
134
+
135
+ li .Item:not(.Custom):active {
136
+ scale: 1;
137
+ }
138
+
139
+ li.divider {
140
+ padding-block: 0.5rem;
141
+ }
142
+
143
+ hr {
144
+ display: block;
145
+ border: none;
146
+ margin: 0;
147
+ border-top: 1px solid var(--menu-border-color);
148
+ }
149
+
150
+ li:first-child[data-type="item"] {
151
+ margin-block-start: var(--menu-item-margin, 0.5rem);
152
+ }
153
+
154
+ @media (pointer: none) {
155
+ li .Item span.Shortcut {
156
+ display: none;
157
+ }
158
+ }
159
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { MenuItem as Item } from "./MenuTypes.js";
2
+ type $$ComponentProps = {
3
+ item: Item;
4
+ index: number;
5
+ onmouseover?: (e: MouseEvent, item: Item, index: number) => void;
6
+ keyboardHasFocus?: boolean;
7
+ shape?: 'default' | 'rounded' | 'pill';
8
+ };
9
+ declare const MenuItem: import("svelte").Component<$$ComponentProps, {}, "">;
10
+ type MenuItem = ReturnType<typeof MenuItem>;
11
+ export default MenuItem;
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import type { Component, Snippet } from "svelte";
3
+
4
+ let {
5
+ text,
6
+ snippet,
7
+ component: Comp,
8
+ props
9
+ }: {
10
+ text?: string;
11
+ snippet?: Snippet;
12
+ component?: Component;
13
+ props?: any;
14
+ } = $props();
15
+ </script>
16
+
17
+ {#if text}
18
+ {text}
19
+ {/if}
20
+ {#if snippet}
21
+ {@render snippet([...props])}
22
+ {/if}
23
+ {#if Comp}
24
+ <Comp {...props} />
25
+ {/if}
@@ -0,0 +1,10 @@
1
+ import type { Component, Snippet } from "svelte";
2
+ type $$ComponentProps = {
3
+ text?: string;
4
+ snippet?: Snippet;
5
+ component?: Component;
6
+ props?: any;
7
+ };
8
+ declare const MenuItemContent: Component<$$ComponentProps, {}, "">;
9
+ type MenuItemContent = ReturnType<typeof MenuItemContent>;
10
+ export default MenuItemContent;
@@ -0,0 +1,79 @@
1
+ import type { StatusColorOrString } from "../util/color.js";
2
+ import type { Component, Snippet } from "svelte";
3
+ export type MenuItem = {
4
+ /** Type of menu item to render. */
5
+ type: 'divider';
6
+ } | {
7
+ /** Type of menu item to render. */
8
+ type: 'header';
9
+ /** Text label of the item to display to the user. */
10
+ text?: string;
11
+ /** Snippet to display. */
12
+ snippet?: Snippet;
13
+ /** Component to display. */
14
+ component?: Component;
15
+ /** Color to use for the item. */
16
+ color?: StatusColorOrString;
17
+ } | {
18
+ /** Type of menu item to render. */
19
+ type: 'text';
20
+ /** Text label of the item to display to the user. */
21
+ text?: string;
22
+ /** Color to use for the item. */
23
+ color?: StatusColorOrString;
24
+ } | {
25
+ /** Type of menu item to render. */
26
+ type: 'item';
27
+ /** Text label of the item to display to the user. */
28
+ text?: string;
29
+ /** Snippet to display. */
30
+ snippet?: Snippet;
31
+ /** Component to display. */
32
+ component?: Component;
33
+ /** Keyboard shortcut to display next to the item. */
34
+ shortcut?: string;
35
+ /** Icon to display. Pass either a Svelte Component or an URL. Use the Icon component to recolor your icons according to the user theme. */
36
+ icon?: string | Component;
37
+ /** Path or URL to use for the menu item. */
38
+ href?: string;
39
+ /** Click event handler. */
40
+ onclick?: (event: MouseEvent, item: MenuItem) => void;
41
+ /** If true, disables the item. */
42
+ disabled?: boolean;
43
+ /** Color to use for the item. */
44
+ color?: StatusColorOrString;
45
+ /** Menu item children. Pass an array of menu items to create a nested menu. */
46
+ children?: MenuItem[];
47
+ };
48
+ export type TabItem = {
49
+ /** Unique identifier of the item. */
50
+ id?: string;
51
+ /** Text label of the item to display to the user. */
52
+ label: string;
53
+ /** Path or URL to use for the item. If the href ends with a star (*), it will match any path that starts with the given path. This allows for nested active items. */
54
+ href?: string;
55
+ /** Click event handler. */
56
+ onclick?: (event: MouseEvent, item: TabItem, index: number) => void;
57
+ /** If true, overrides the currently selected item. */
58
+ active?: boolean;
59
+ };
60
+ export type TabbedContentItem = {
61
+ /** Text label of the item to display to the user. */
62
+ label: string;
63
+ /** URL hash to use for the item. */
64
+ hash?: string;
65
+ /** Content to display when the item is selected. */
66
+ text?: string;
67
+ /** Snippet to display. */
68
+ snippet?: Snippet;
69
+ /** Component to display. */
70
+ component?: Component;
71
+ };
72
+ export type BreadcrumbItem = {
73
+ /** Text label of the item to display to the user. */
74
+ label: string;
75
+ /** Icon to display. Pass either a Svelte Component or an URL. Use the Icon component to recolor your icons according to the user theme. */
76
+ icon?: string | Component;
77
+ /** Path or URL to use for the breadcrumb item. */
78
+ href?: string;
79
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,149 @@
1
+ <script lang="ts">
2
+ import UiContent from "./UIContent.svelte";
3
+ import { getContext, type Snippet } from "svelte";
4
+ import { slidefade } from "../util/transitions.js";
5
+ import { attr } from "../util/attr.js";
6
+
7
+ /**
8
+ * @description
9
+ * A modal component that uses the popover api. Both trigger and content elements are snippets.
10
+ * For the trigger element, you get an `attrs` function that applies the necessary attributes to your trigger with the `use:attrs` directive.
11
+ * @example
12
+ * <div>
13
+ * {#snippet trigger(attrs)}
14
+ * <button use:attrs>foo</button>
15
+ * {/snippet}
16
+ * {#snippet content(close)}
17
+ * <div>bar</div>
18
+ * {/snippet}
19
+ * <Modal trigger={trigger} content={content} />
20
+ * <Modal trigger={trigger} content={content} hover />
21
+ * </div>
22
+ */
23
+ let {
24
+ contained,
25
+ content,
26
+ buttons,
27
+ trigger,
28
+ shape = "rounded",
29
+ }: {
30
+ /** Whether the modal should be contained with a border */
31
+ contained?: boolean;
32
+ /** The content of the modal */
33
+ content: Snippet<[close: () => void]>;
34
+ /** Snippet containing the trigger element */
35
+ trigger: Snippet<[attrs: (node: Element) => void]>;
36
+ /** Buttons to be displayed in the modal */
37
+ buttons?: Snippet<[close: () => void]>;
38
+ /** The shape of the modal */
39
+ shape?: "rounded" | "sharp";
40
+ } = $props();
41
+
42
+ if(contained === undefined) { contained = getContext('lutra.modal.contained') ?? getContext('lutra.contained') ?? false; }
43
+
44
+ const id = `po-${Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)}`;
45
+ let isOpen = $state(false);
46
+
47
+ function closeModal() { document.getElementById(id)!.hidePopover(); isOpen = false; }
48
+ function toggleModal() { isOpen = !isOpen; }
49
+
50
+ function clickElsewhere(e: MouseEvent) {
51
+ if (e.target instanceof HTMLElement && !e.target.closest('.ModalContent')) {
52
+ closeModal();
53
+ }
54
+ }
55
+
56
+ $effect(() => {
57
+ if(isOpen) {
58
+ document.getElementsByTagName("html")[0].style.overflow = "hidden";
59
+ } else {
60
+ document.getElementsByTagName("html")[0].style.overflow = "auto";
61
+ }
62
+ });
63
+
64
+ let attrs = $derived.by(() => {
65
+ return attr({
66
+ id: `trigger-${id}`,
67
+ popovertarget: id,
68
+ onclick: toggleModal,
69
+ })
70
+ });
71
+
72
+ </script>
73
+
74
+ <div class="Modal">
75
+ <div class="Trigger">
76
+ {@render trigger(attrs)}
77
+ </div>
78
+ {#if isOpen}
79
+ <UiContent>
80
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
81
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
82
+ <div {id} onclick={clickElsewhere} popover="auto" class="ModalContainer">
83
+ <div class="ModalContent {shape}" class:contained>
84
+ <div class="ModalContentInside">
85
+ {@render content(closeModal)}
86
+ {#if buttons}
87
+ <div class="ModalActions">
88
+ {@render buttons(closeModal)}
89
+ </div>
90
+ {/if}
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </UiContent>
95
+ {/if}
96
+ </div>
97
+
98
+ <style>
99
+ .Modal, .Trigger {
100
+ position: relative;
101
+ display: inline-block;
102
+ }
103
+ .ModalContainer {
104
+ border: 0;
105
+ width: 100vw;
106
+ height: 100vh;
107
+ background-color: var(--bg-overlay);
108
+ backdrop-filter: var(--overlay-filter);
109
+ overflow-y: auto;
110
+ }
111
+ .ModalContent {
112
+ background: var(--bg, var(--background-main));
113
+ box-shadow: var(--shadow);
114
+ opacity: 1;
115
+ position: absolute;
116
+ left: 50%;
117
+ top: 50%;
118
+ transform: translate(-50%, -50%);
119
+ box-shadow: 0 0.25rem 1rem 0 var(--shadow);
120
+ }
121
+ .ModalContentInsize {
122
+ container-type: inline-size;
123
+ }
124
+ .ModalContent.rounded {
125
+ border-radius: var(--border-radius);
126
+ }
127
+ .ModalContent.contained {
128
+ border: var(--border);
129
+ }
130
+ .ModalActions {
131
+ display: flex;
132
+ gap: 1rem;
133
+ border-top: var(--border);
134
+ justify-content: flex-end;
135
+ padding: 1rem;
136
+ background: var(--bg-subtle) linear-gradient(0deg, transparent, 95%, color-mix(in hsl, transparent 95%, var(--mix-target)));
137
+ }
138
+ [popover] {
139
+ animation: fadeIn 0.2s;
140
+ }
141
+ @keyframes fadeIn {
142
+ from {
143
+ opacity: 0;
144
+ }
145
+ to {
146
+ opacity: 1;
147
+ }
148
+ }
149
+ </style>
@@ -0,0 +1,16 @@
1
+ import { type Snippet } from "svelte";
2
+ type $$ComponentProps = {
3
+ /** Whether the modal should be contained with a border */
4
+ contained?: boolean;
5
+ /** The content of the modal */
6
+ content: Snippet<[close: () => void]>;
7
+ /** Snippet containing the trigger element */
8
+ trigger: Snippet<[attrs: (node: Element) => void]>;
9
+ /** Buttons to be displayed in the modal */
10
+ buttons?: Snippet<[close: () => void]>;
11
+ /** The shape of the modal */
12
+ shape?: "rounded" | "sharp";
13
+ };
14
+ declare const Modal: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type Modal = ReturnType<typeof Modal>;
16
+ export default Modal;
@@ -0,0 +1,115 @@
1
+ <script lang="ts">
2
+ import Overlay from "./Overlay.svelte";
3
+ import PageContent from "./PageContent.svelte";
4
+ import { removeOverlay } from "./overlays.svelte.js";
5
+ import type { Snippet, Component } from "svelte";
6
+ import Close from "./Close.svelte";
7
+ import Icon from "./Icon.svelte";
8
+
9
+ let {
10
+ id = crypto.randomUUID(),
11
+ children,
12
+ title,
13
+ content,
14
+ icon,
15
+ actions,
16
+ }: {
17
+ id?: string;
18
+ children?: Snippet;
19
+ title?: string;
20
+ content?: string;
21
+ icon?: string | Component;
22
+ actions?: Snippet;
23
+ } = $props();
24
+
25
+ function onclick(e: MouseEvent) {
26
+ e.preventDefault();
27
+ removeOverlay(id);
28
+ }
29
+
30
+ </script>
31
+
32
+ {#snippet notification()}
33
+ <div class="Notification">
34
+ {#if !actions}
35
+ <Close position="top right" {onclick} />
36
+ {/if}
37
+ {#if icon}
38
+ <div class="Icon">
39
+ <Icon {icon} --vertical-align="text-top" --icon-width="2rem" --icon-height="2rem" />
40
+ </div>
41
+ {/if}
42
+ <div class="Content">
43
+ <PageContent --margin-scale="0.35">
44
+ {#if children}
45
+ {@render children()}
46
+ {:else}
47
+ {#if title}
48
+ <h5>{title}</h5>
49
+ {/if}
50
+ <p>{content}</p>
51
+ {/if}
52
+ </PageContent>
53
+ </div>
54
+ {#if actions}
55
+ <div class="Actions">
56
+ {@render actions()}
57
+ </div>
58
+ {/if}
59
+ </div>
60
+ {/snippet}
61
+
62
+ {#if children}
63
+ <Overlay z={100} layer="notifications" position="bottom right" {id}>
64
+ {@render notification()}
65
+ </Overlay>
66
+ {:else}
67
+ {@render notification()}
68
+ {/if}
69
+
70
+ <style>
71
+ .Notification {
72
+ display: block;
73
+ pointer-events: none;
74
+ background-color: var(--notification-background-color);
75
+ border-radius: var(--notification-border-radius);
76
+ border: var(--notification-border-size) var(--notification-border-style) var(--notification-border-color);
77
+ padding: 0.75rem 1rem;
78
+ width: 30rem;
79
+ font-size: 0.85em;
80
+ display: grid;
81
+ grid-template-areas: "content";
82
+ grid-template-columns: 1fr;
83
+ gap: 1rem;
84
+ box-shadow: 0 0.5rem 1rem var(--shadow-color);
85
+ }
86
+ .Notification:has(.Icon):has(.Actions) {
87
+ grid-template-areas: "icon content actions";
88
+ grid-template-columns: auto 1fr auto;
89
+ }
90
+ .Notification:not(:has(.Icon)):has(.Actions) {
91
+ grid-template-areas: "content actions";
92
+ grid-template-columns: 1fr auto;
93
+ }
94
+ .Notification:has(.Icon):not(:has(.Actions)) {
95
+ grid-template-areas: "icon content";
96
+ grid-template-columns: auto 1fr;
97
+ }
98
+ .Icon {
99
+ grid-area: icon;
100
+ display: flex;
101
+ gap: 0.5rem;
102
+ align-items: center;
103
+ pointer-events: auto;
104
+ }
105
+ .Content {
106
+ grid-area: content;
107
+ }
108
+ .Actions {
109
+ grid-area: actions;
110
+ display: flex;
111
+ gap: 0.5rem;
112
+ align-items: center;
113
+ pointer-events: auto;
114
+ }
115
+ </style>
@@ -0,0 +1,12 @@
1
+ import type { Snippet, Component } from "svelte";
2
+ type $$ComponentProps = {
3
+ id?: string;
4
+ children?: Snippet;
5
+ title?: string;
6
+ content?: string;
7
+ icon?: string | Component;
8
+ actions?: Snippet;
9
+ };
10
+ declare const Notification: Component<$$ComponentProps, {}, "">;
11
+ type Notification = ReturnType<typeof Notification>;
12
+ export default Notification;
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import { onDestroy, onMount, type Snippet } from "svelte";
3
+ import { addOverlay, removeOverlay, type OverlayPosition, type TransitionOpts } from "./overlays.svelte.js";
4
+
5
+ let {
6
+ id = crypto.randomUUID(),
7
+ children,
8
+ position = "center",
9
+ anchor,
10
+ layer,
11
+ transition,
12
+ z,
13
+ }: {
14
+ id?: string;
15
+ children: Snippet;
16
+ anchor?: HTMLElement;
17
+ layer?: string;
18
+ position?: OverlayPosition;
19
+ transition?: TransitionOpts;
20
+ z?: number;
21
+ } = $props();
22
+
23
+ onMount(() => {
24
+ addOverlay({ id, z, layer, snippet: children, transition, position, anchor });
25
+ });
26
+
27
+ onDestroy(() => {
28
+ removeOverlay(id);
29
+ });
30
+ </script>
31
+
@@ -0,0 +1,14 @@
1
+ import { type Snippet } from "svelte";
2
+ import { type OverlayPosition, type TransitionOpts } from "./overlays.svelte.js";
3
+ type $$ComponentProps = {
4
+ id?: string;
5
+ children: Snippet;
6
+ anchor?: HTMLElement;
7
+ layer?: string;
8
+ position?: OverlayPosition;
9
+ transition?: TransitionOpts;
10
+ z?: number;
11
+ };
12
+ declare const Overlay: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type Overlay = ReturnType<typeof Overlay>;
14
+ export default Overlay;
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import { overlays, type OverlayItem } from './overlays.svelte.js';
3
+ import OverlayLayer from './OverlayLayer.svelte';
4
+ import { slidefade } from '../util/transitions.js';
5
+
6
+ </script>
7
+
8
+ <div class="Overlay">
9
+ <OverlayLayer position="top left" items={overlays.topLeft} />
10
+ <OverlayLayer position="top right" items={overlays.topRight} />
11
+ <OverlayLayer position="top center" items={overlays.topCenter} />
12
+ <OverlayLayer position="bottom left" items={overlays.bottomLeft} />
13
+ <OverlayLayer position="bottom right" items={overlays.bottomRight} />
14
+ <OverlayLayer position="bottom center" items={overlays.bottomCenter} />
15
+ <OverlayLayer position="center" items={overlays.center} />
16
+ <OverlayLayer position="anchor" items={overlays.anchor} />
17
+ </div>
18
+
19
+ <style>
20
+ .Overlay {
21
+ isolation: isolate;
22
+ display: block;
23
+ position: fixed;
24
+ top: 0;
25
+ left: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+ z-index: 1000;
29
+ pointer-events: none;
30
+ }
31
+ </style>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const OverlayContainer: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type OverlayContainer = InstanceType<typeof OverlayContainer>;
18
+ export default OverlayContainer;