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.
Files changed (274) hide show
  1. package/README.md +4 -24
  2. package/dist/components/AspectRatio.svelte +26 -0
  3. package/dist/components/AspectRatio.svelte.d.ts +8 -0
  4. package/dist/components/Avatar.svelte +105 -0
  5. package/dist/components/Avatar.svelte.d.ts +14 -0
  6. package/dist/{display → components}/Close.svelte +25 -7
  7. package/dist/components/Close.svelte.d.ts +7 -0
  8. package/dist/components/ContextTip.svelte +41 -0
  9. package/dist/components/ContextTip.svelte.d.ts +7 -0
  10. package/dist/components/Dialog.svelte +78 -0
  11. package/dist/components/Dialog.svelte.d.ts +14 -0
  12. package/dist/components/Icon.svelte +62 -0
  13. package/dist/components/Icon.svelte.d.ts +8 -0
  14. package/dist/{display → components}/IconButton.svelte +43 -14
  15. package/dist/components/IconButton.svelte.d.ts +16 -0
  16. package/dist/components/Image.svelte +172 -0
  17. package/dist/components/Image.svelte.d.ts +56 -0
  18. package/dist/{display → components}/Indicator.svelte +44 -9
  19. package/dist/components/Indicator.svelte.d.ts +12 -0
  20. package/dist/{display → components}/Inset.svelte +8 -3
  21. package/dist/components/Inset.svelte.d.ts +7 -0
  22. package/dist/components/Layout.svelte +33 -0
  23. package/dist/components/Layout.svelte.d.ts +11 -0
  24. package/dist/components/MenuDropdown.svelte +195 -0
  25. package/dist/components/MenuDropdown.svelte.d.ts +16 -0
  26. package/dist/{nav → components}/MenuItem.svelte +46 -38
  27. package/dist/components/MenuItem.svelte.d.ts +11 -0
  28. package/dist/components/MenuItemContent.svelte +25 -0
  29. package/dist/components/MenuItemContent.svelte.d.ts +10 -0
  30. package/dist/{nav → components}/MenuTypes.d.ts +19 -5
  31. package/dist/components/Modal.svelte +149 -0
  32. package/dist/components/Modal.svelte.d.ts +16 -0
  33. package/dist/{display → components}/Notification.svelte +33 -22
  34. package/dist/components/Notification.svelte.d.ts +12 -0
  35. package/dist/components/Overlay.svelte +31 -0
  36. package/dist/components/Overlay.svelte.d.ts +14 -0
  37. package/dist/{layout → components}/OverlayContainer.svelte +6 -3
  38. package/dist/{layout → components}/OverlayContainer.svelte.d.ts +4 -1
  39. package/dist/components/OverlayLayer.svelte +168 -0
  40. package/dist/components/OverlayLayer.svelte.d.ts +8 -0
  41. package/dist/components/PageContent.svelte +108 -0
  42. package/dist/components/PageContent.svelte.d.ts +38 -0
  43. package/dist/components/TabbedContent.svelte +74 -0
  44. package/dist/components/TabbedContent.svelte.d.ts +11 -0
  45. package/dist/components/TabbedContentItem.svelte +33 -0
  46. package/dist/components/TabbedContentItem.svelte.d.ts +10 -0
  47. package/dist/components/Table.svelte +41 -0
  48. package/dist/components/Table.svelte.d.ts +13 -0
  49. package/dist/{nav → components}/Tabs.svelte +99 -41
  50. package/dist/components/Tabs.svelte.d.ts +20 -0
  51. package/dist/components/Tag.svelte +120 -0
  52. package/dist/components/Tag.svelte.d.ts +21 -0
  53. package/dist/components/Theme.svelte +105 -0
  54. package/dist/components/Theme.svelte.d.ts +17 -0
  55. package/dist/{display → components}/Tooltip.svelte +41 -16
  56. package/dist/components/Tooltip.svelte.d.ts +12 -0
  57. package/dist/components/UIContent.svelte +19 -0
  58. package/dist/components/UIContent.svelte.d.ts +7 -0
  59. package/dist/components/index.d.ts +28 -0
  60. package/dist/components/index.js +29 -0
  61. package/dist/{display → components}/notifications.svelte.d.ts +1 -1
  62. package/dist/{display → components}/notifications.svelte.js +3 -4
  63. package/dist/{layout → components}/overlays.svelte.d.ts +4 -2
  64. package/dist/config.d.ts +30 -0
  65. package/dist/config.js +18 -0
  66. package/dist/css/1-props.css +440 -0
  67. package/dist/css/2-base.css +343 -0
  68. package/dist/css/3-typo.css +106 -0
  69. package/dist/css/4-layout.css +368 -0
  70. package/dist/css/5-media.css +116 -0
  71. package/dist/css/lutra.css +7 -0
  72. package/dist/css/themes/DefaultTheme.css +209 -0
  73. package/dist/form/Button.svelte +35 -16
  74. package/dist/form/Button.svelte.d.ts +8 -19
  75. package/dist/form/Datepicker.svelte +311 -0
  76. package/dist/form/Datepicker.svelte.d.ts +9 -0
  77. package/dist/form/FieldContent.svelte +69 -44
  78. package/dist/form/FieldContent.svelte.d.ts +7 -17
  79. package/dist/form/FieldError.svelte +16 -6
  80. package/dist/form/FieldError.svelte.d.ts +4 -15
  81. package/dist/form/Fieldset.svelte +48 -13
  82. package/dist/form/Fieldset.svelte.d.ts +5 -16
  83. package/dist/form/Form.svelte +158 -74
  84. package/dist/form/Form.svelte.d.ts +17 -17
  85. package/dist/form/{FieldActions.svelte → FormActions.svelte} +29 -17
  86. package/dist/form/FormActions.svelte.d.ts +9 -0
  87. package/dist/form/FormSection.svelte +96 -0
  88. package/dist/form/FormSection.svelte.d.ts +9 -0
  89. package/dist/form/ImageUpload.svelte +134 -94
  90. package/dist/form/ImageUpload.svelte.d.ts +5 -16
  91. package/dist/form/Input.svelte +254 -136
  92. package/dist/form/Input.svelte.d.ts +12 -21
  93. package/dist/form/InputLength.svelte +15 -5
  94. package/dist/form/InputLength.svelte.d.ts +4 -15
  95. package/dist/form/Label.svelte +55 -11
  96. package/dist/form/Label.svelte.d.ts +6 -15
  97. package/dist/form/LogoUpload.svelte +36 -21
  98. package/dist/form/LogoUpload.svelte.d.ts +4 -15
  99. package/dist/form/Select.svelte +100 -50
  100. package/dist/form/Select.svelte.d.ts +5 -16
  101. package/dist/form/Textarea.svelte +200 -98
  102. package/dist/form/Textarea.svelte.d.ts +11 -24
  103. package/dist/form/Toggle.svelte +3 -1
  104. package/dist/form/Toggle.svelte.d.ts +4 -1
  105. package/dist/form/client.svelte.d.ts +1 -0
  106. package/dist/form/client.svelte.js +6 -2
  107. package/dist/form/form.d.ts +10 -9
  108. package/dist/form/form.js +37 -32
  109. package/dist/form/index.d.ts +3 -4
  110. package/dist/form/index.js +3 -4
  111. package/dist/form/types.d.ts +9 -16
  112. package/dist/icons/IconAlert.svelte.d.ts +4 -1
  113. package/dist/icons/IconCopy.svelte.d.ts +4 -1
  114. package/dist/icons/IconDone.svelte.d.ts +4 -1
  115. package/dist/icons/IconError.svelte.d.ts +4 -1
  116. package/dist/icons/IconHelp.svelte.d.ts +4 -1
  117. package/dist/icons/IconHide.svelte.d.ts +4 -1
  118. package/dist/icons/IconInfo.svelte.d.ts +4 -1
  119. package/dist/icons/IconLink.svelte.d.ts +4 -1
  120. package/dist/icons/IconMenuBurger.svelte.d.ts +4 -1
  121. package/dist/icons/IconMenuDots.svelte.d.ts +4 -1
  122. package/dist/icons/IconSearch.svelte.d.ts +4 -1
  123. package/dist/icons/IconShow.svelte.d.ts +4 -1
  124. package/dist/icons/IconSuccess.svelte.d.ts +4 -1
  125. package/dist/icons/IconWarning.svelte.d.ts +4 -1
  126. package/dist/index.d.ts +3 -1
  127. package/dist/index.js +3 -2
  128. package/dist/types.d.ts +39 -0
  129. package/dist/types.js +25 -0
  130. package/dist/util/StringOrComponent.svelte +20 -0
  131. package/dist/util/StringOrComponent.svelte.d.ts +8 -0
  132. package/dist/util/StringOrSnippet.svelte +16 -0
  133. package/dist/util/StringOrSnippet.svelte.d.ts +8 -0
  134. package/dist/{utils → util}/dom.js +1 -2
  135. package/dist/util/locale.d.ts +1 -0
  136. package/dist/util/locale.js +47 -0
  137. package/dist/util/settings.d.ts +4 -0
  138. package/package.json +35 -79
  139. package/dist/color.css +0 -0
  140. package/dist/display/Avatar.svelte +0 -61
  141. package/dist/display/Avatar.svelte.d.ts +0 -19
  142. package/dist/display/Badge.svelte +0 -91
  143. package/dist/display/Badge.svelte.d.ts +0 -30
  144. package/dist/display/Callout.svelte +0 -109
  145. package/dist/display/Callout.svelte.d.ts +0 -28
  146. package/dist/display/Close.svelte.d.ts +0 -18
  147. package/dist/display/Code.svelte +0 -190
  148. package/dist/display/Code.svelte.d.ts +0 -32
  149. package/dist/display/ContextTip.svelte +0 -23
  150. package/dist/display/ContextTip.svelte.d.ts +0 -18
  151. package/dist/display/DataList.svelte +0 -16
  152. package/dist/display/DataList.svelte.d.ts +0 -21
  153. package/dist/display/Details.svelte +0 -49
  154. package/dist/display/Details.svelte.d.ts +0 -27
  155. package/dist/display/Hero.svelte +0 -50
  156. package/dist/display/Hero.svelte.d.ts +0 -26
  157. package/dist/display/Icon.svelte +0 -39
  158. package/dist/display/Icon.svelte.d.ts +0 -19
  159. package/dist/display/IconButton.svelte.d.ts +0 -27
  160. package/dist/display/Image.svelte +0 -91
  161. package/dist/display/Image.svelte.d.ts +0 -26
  162. package/dist/display/Indicator.svelte.d.ts +0 -23
  163. package/dist/display/Inset.svelte.d.ts +0 -18
  164. package/dist/display/LineChart.svelte +0 -385
  165. package/dist/display/LineChart.svelte.d.ts +0 -24
  166. package/dist/display/LoadingIndicator.svelte +0 -33
  167. package/dist/display/LoadingIndicator.svelte.d.ts +0 -15
  168. package/dist/display/Modal.svelte +0 -116
  169. package/dist/display/Modal.svelte.d.ts +0 -27
  170. package/dist/display/Notification.svelte.d.ts +0 -23
  171. package/dist/display/Panel.svelte +0 -23
  172. package/dist/display/Panel.svelte.d.ts +0 -19
  173. package/dist/display/Popup.svelte +0 -111
  174. package/dist/display/Popup.svelte.d.ts +0 -25
  175. package/dist/display/Stat.svelte +0 -81
  176. package/dist/display/Stat.svelte.d.ts +0 -30
  177. package/dist/display/Table.svelte +0 -28
  178. package/dist/display/Table.svelte.d.ts +0 -24
  179. package/dist/display/TablePaginator.svelte +0 -51
  180. package/dist/display/TablePaginator.svelte.d.ts +0 -21
  181. package/dist/display/Tag.svelte +0 -90
  182. package/dist/display/Tag.svelte.d.ts +0 -32
  183. package/dist/display/Tooltip.svelte.d.ts +0 -23
  184. package/dist/display/chart.d.ts +0 -78
  185. package/dist/display/chart.js +0 -212
  186. package/dist/display/index.d.ts +0 -24
  187. package/dist/display/index.js +0 -24
  188. package/dist/form/FieldActions.svelte.d.ts +0 -20
  189. package/dist/form/FieldContainer.svelte +0 -37
  190. package/dist/form/FieldContainer.svelte.d.ts +0 -19
  191. package/dist/form/FieldSection.svelte +0 -86
  192. package/dist/form/FieldSection.svelte.d.ts +0 -20
  193. package/dist/layout/Layout.svelte +0 -47
  194. package/dist/layout/Layout.svelte.d.ts +0 -22
  195. package/dist/layout/LayoutFooter.svelte +0 -21
  196. package/dist/layout/LayoutFooter.svelte.d.ts +0 -18
  197. package/dist/layout/LayoutGrid.svelte +0 -51
  198. package/dist/layout/LayoutGrid.svelte.d.ts +0 -27
  199. package/dist/layout/LayoutHeader.svelte +0 -97
  200. package/dist/layout/LayoutHeader.svelte.d.ts +0 -34
  201. package/dist/layout/LayoutSideMenu.svelte +0 -55
  202. package/dist/layout/LayoutSideMenu.svelte.d.ts +0 -21
  203. package/dist/layout/LayoutTypes.d.ts +0 -15
  204. package/dist/layout/LayoutTypes.js +0 -9
  205. package/dist/layout/Overlay.svelte +0 -20
  206. package/dist/layout/Overlay.svelte.d.ts +0 -25
  207. package/dist/layout/OverlayLayer.svelte +0 -140
  208. package/dist/layout/OverlayLayer.svelte.d.ts +0 -19
  209. package/dist/layout/PageContent.svelte +0 -82
  210. package/dist/layout/PageContent.svelte.d.ts +0 -25
  211. package/dist/layout/Theme.svelte +0 -243
  212. package/dist/layout/Theme.svelte.d.ts +0 -19
  213. package/dist/layout/UIContent.svelte +0 -15
  214. package/dist/layout/UIContent.svelte.d.ts +0 -18
  215. package/dist/layout/index.d.ts +0 -11
  216. package/dist/layout/index.js +0 -11
  217. package/dist/nav/Breadcrumb.svelte +0 -82
  218. package/dist/nav/Breadcrumb.svelte.d.ts +0 -28
  219. package/dist/nav/Menu.svelte +0 -170
  220. package/dist/nav/Menu.svelte.d.ts +0 -27
  221. package/dist/nav/MenuItem.svelte.d.ts +0 -22
  222. package/dist/nav/NavMenu.svelte +0 -181
  223. package/dist/nav/NavMenu.svelte.d.ts +0 -19
  224. package/dist/nav/TabbedContent.svelte +0 -43
  225. package/dist/nav/TabbedContent.svelte.d.ts +0 -23
  226. package/dist/nav/Tabs.svelte.d.ts +0 -25
  227. package/dist/nav/index.d.ts +0 -7
  228. package/dist/nav/index.js +0 -6
  229. package/dist/style.css +0 -950
  230. package/dist/typo/Clamp.svelte +0 -25
  231. package/dist/typo/Clamp.svelte.d.ts +0 -24
  232. package/dist/typo/H.svelte +0 -52
  233. package/dist/typo/H.svelte.d.ts +0 -28
  234. package/dist/typo/H1.svelte +0 -14
  235. package/dist/typo/H1.svelte.d.ts +0 -26
  236. package/dist/typo/H2.svelte +0 -14
  237. package/dist/typo/H2.svelte.d.ts +0 -26
  238. package/dist/typo/H3.svelte +0 -14
  239. package/dist/typo/H3.svelte.d.ts +0 -26
  240. package/dist/typo/H4.svelte +0 -14
  241. package/dist/typo/H4.svelte.d.ts +0 -26
  242. package/dist/typo/H5.svelte +0 -14
  243. package/dist/typo/H5.svelte.d.ts +0 -26
  244. package/dist/typo/H6.svelte +0 -14
  245. package/dist/typo/H6.svelte.d.ts +0 -26
  246. package/dist/typo/P.svelte +0 -34
  247. package/dist/typo/P.svelte.d.ts +0 -26
  248. package/dist/typo/index.d.ts +0 -9
  249. package/dist/typo/index.js +0 -9
  250. package/dist/utils/StringOrComponent.svelte +0 -14
  251. package/dist/utils/StringOrComponent.svelte.d.ts +0 -19
  252. package/dist/utils/StringOrSnippet.svelte +0 -11
  253. package/dist/utils/StringOrSnippet.svelte.d.ts +0 -19
  254. package/dist/utils/defaults.d.ts +0 -4
  255. package/dist/utils/hooks.server.d.ts +0 -2
  256. package/dist/utils/hooks.server.js +0 -16
  257. package/dist/utils/id.d.ts +0 -1
  258. package/dist/utils/id.js +0 -3
  259. package/dist/utils/index.d.ts +0 -9
  260. package/dist/utils/index.js +0 -6
  261. package/dist/utils/isSnippet.d.ts +0 -3
  262. package/dist/utils/isSnippet.js +0 -11
  263. /package/dist/{nav → components}/MenuTypes.js +0 -0
  264. /package/dist/{layout → components}/overlays.svelte.js +0 -0
  265. /package/dist/{utils → util}/attr.d.ts +0 -0
  266. /package/dist/{utils → util}/attr.js +0 -0
  267. /package/dist/{utils → util}/color.d.ts +0 -0
  268. /package/dist/{utils → util}/color.js +0 -0
  269. /package/dist/{utils → util}/dom.d.ts +0 -0
  270. /package/dist/{utils → util}/keyboard.svelte.d.ts +0 -0
  271. /package/dist/{utils → util}/keyboard.svelte.js +0 -0
  272. /package/dist/{utils/defaults.js → util/settings.js} +0 -0
  273. /package/dist/{utils → util}/transitions.d.ts +0 -0
  274. /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">import { isStatusColor, StatusColors } from "../utils/color.js";
2
- let {
3
- color = "default",
4
- motion,
5
- label
6
- } = $props();
7
- let isSet = $derived(isStatusColor(color));
8
- let _label = $derived(isSet ? StatusColors[color] : label ? label : "status");
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;
@@ -1,6 +1,11 @@
1
- <script lang="ts">let {
2
- children
3
- } = $props();
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+
4
+ let {
5
+ children,
6
+ }: {
7
+ children: Snippet;
8
+ } = $props();
4
9
  </script>
5
10
 
6
11
  <div class="Inset">
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from "svelte";
2
+ type $$ComponentProps = {
3
+ children: Snippet;
4
+ };
5
+ declare const Inset: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type Inset = ReturnType<typeof Inset>;
7
+ export default Inset;
@@ -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;