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
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
import MenuItemContent from "./MenuItemContent.svelte";
|
|
4
4
|
import type { MenuItem as Item } from "./MenuTypes.js";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @description
|
|
8
|
+
* A single menu item within a menu list. Supports item, header, text, and divider types.
|
|
9
|
+
* Items can be links, buttons, or custom rendered content. Keyboard navigation is handled by the parent MenuDropdown.
|
|
10
|
+
* @cssprop --menu-item-font-size - Font size of the menu item. (Default: var(--font-size-sm))
|
|
11
|
+
* @cssprop --menu-item-padding-block - Block padding of the menu item. (Default: var(--space-xs))
|
|
12
|
+
* @cssprop --menu-item-padding-inline - Inline padding of the menu item. (Default: var(--space-md))
|
|
13
|
+
* @cssprop --menu-item-gap - Gap between icon and text within the item. (Default: var(--space-sm))
|
|
14
|
+
* @cssprop --menu-item-margin - Top margin of the first item. (Default: var(--space-xs))
|
|
15
|
+
* @cssprop --menu-shortcut-font-size - Font size of the keyboard shortcut label. (Default: max(0.75em, 9px))
|
|
16
|
+
*/
|
|
6
17
|
let {
|
|
7
18
|
item,
|
|
8
19
|
index,
|
|
@@ -11,11 +22,17 @@
|
|
|
11
22
|
keyboardHasFocus,
|
|
12
23
|
shape = 'default',
|
|
13
24
|
}: {
|
|
25
|
+
/** The menu item data object. */
|
|
14
26
|
item: Item;
|
|
27
|
+
/** The index of this item in the menu list. */
|
|
15
28
|
index: number;
|
|
29
|
+
/** Callback when the mouse enters the item. */
|
|
16
30
|
onmouseover?: (e: MouseEvent, item: Item, index: number) => void;
|
|
31
|
+
/** Callback when the item is selected. */
|
|
17
32
|
onselect?: (item: Item, index: number) => void;
|
|
33
|
+
/** Whether keyboard navigation is active, suppressing mouse hover styles. */
|
|
18
34
|
keyboardHasFocus?: boolean;
|
|
35
|
+
/** The border-radius shape of the item. */
|
|
19
36
|
shape?: 'default' | 'rounded' | 'pill';
|
|
20
37
|
} = $props();
|
|
21
38
|
|
|
@@ -104,20 +121,19 @@
|
|
|
104
121
|
li .Item,
|
|
105
122
|
li .Header,
|
|
106
123
|
li .Text {
|
|
107
|
-
font-size: var(--font-size,
|
|
124
|
+
font-size: var(--menu-item-font-size, var(--font-size-sm));
|
|
108
125
|
text-align: left;
|
|
109
|
-
padding-block:
|
|
110
|
-
padding-inline:
|
|
126
|
+
padding-block: var(--menu-item-padding-block, var(--space-xs));
|
|
127
|
+
padding-inline: var(--menu-item-padding-inline, var(--space-md));
|
|
111
128
|
display: inline-flex;
|
|
112
129
|
align-items: center;
|
|
113
130
|
justify-content: space-between;
|
|
114
131
|
width: 100%;
|
|
115
|
-
color: inherit;
|
|
116
132
|
text-decoration: none;
|
|
117
133
|
color: var(--color);
|
|
118
|
-
--inset-block:
|
|
119
|
-
--inset-inline:
|
|
120
|
-
border-radius:
|
|
134
|
+
--inset-block: var(--menu-item-padding-block, var(--space-xs));
|
|
135
|
+
--inset-inline: var(--menu-item-padding-inline, var(--space-md));
|
|
136
|
+
border-radius: 0;
|
|
121
137
|
white-space: nowrap;
|
|
122
138
|
}
|
|
123
139
|
|
|
@@ -128,7 +144,7 @@
|
|
|
128
144
|
}
|
|
129
145
|
|
|
130
146
|
li .Header {
|
|
131
|
-
font-weight:
|
|
147
|
+
font-weight: var(--font-weight-medium);
|
|
132
148
|
}
|
|
133
149
|
|
|
134
150
|
li:not(.keyboardHasFocus) .Item:not(.Custom):hover,
|
|
@@ -146,7 +162,7 @@
|
|
|
146
162
|
}
|
|
147
163
|
|
|
148
164
|
li .Item span.Shortcut {
|
|
149
|
-
font-size: max(0.75em, 9px);
|
|
165
|
+
font-size: var(--menu-shortcut-font-size, max(0.75em, 9px));
|
|
150
166
|
text-align: right;
|
|
151
167
|
color: var(--menu-text-color-subtle);
|
|
152
168
|
white-space: nowrap;
|
|
@@ -157,23 +173,23 @@
|
|
|
157
173
|
}
|
|
158
174
|
|
|
159
175
|
li.divider {
|
|
160
|
-
padding-block:
|
|
176
|
+
padding-block: var(--menu-item-padding-block, var(--space-xs));
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
hr {
|
|
164
180
|
display: block;
|
|
165
181
|
border: none;
|
|
166
182
|
margin: 0;
|
|
167
|
-
border-top:
|
|
183
|
+
border-top: var(--menu-border-size) var(--menu-border-style) var(--menu-border-color);
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
li:first-child[data-type="item"] {
|
|
171
|
-
margin-block-start: var(--menu-item-margin,
|
|
187
|
+
margin-block-start: var(--menu-item-margin, var(--space-xs));
|
|
172
188
|
}
|
|
173
189
|
|
|
174
|
-
@media (pointer:
|
|
190
|
+
@media (pointer: coarse) {
|
|
175
191
|
li .Item span.Shortcut {
|
|
176
192
|
display: none;
|
|
177
|
-
}
|
|
193
|
+
}
|
|
178
194
|
}
|
|
179
195
|
</style>
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { MenuItem as Item } from "./MenuTypes.js";
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
+
/** The menu item data object. */
|
|
3
4
|
item: Item;
|
|
5
|
+
/** The index of this item in the menu list. */
|
|
4
6
|
index: number;
|
|
7
|
+
/** Callback when the mouse enters the item. */
|
|
5
8
|
onmouseover?: (e: MouseEvent, item: Item, index: number) => void;
|
|
9
|
+
/** Callback when the item is selected. */
|
|
6
10
|
onselect?: (item: Item, index: number) => void;
|
|
11
|
+
/** Whether keyboard navigation is active, suppressing mouse hover styles. */
|
|
7
12
|
keyboardHasFocus?: boolean;
|
|
13
|
+
/** The border-radius shape of the item. */
|
|
8
14
|
shape?: 'default' | 'rounded' | 'pill';
|
|
9
15
|
};
|
|
10
16
|
declare const MenuItem: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -5,30 +5,20 @@
|
|
|
5
5
|
import type { ModalButton } from "./ModalTypes.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* ```svelte
|
|
8
|
+
* @description
|
|
9
|
+
* A modal component using the native `<dialog>` element. Supports trigger-based, controlled, and auto-show patterns.
|
|
10
|
+
* Uses modal tokens for styling. The `contained` prop can be set via context.
|
|
11
|
+
* @cssprop --modal-width - Width of the modal. (Default: fit-content)
|
|
12
|
+
* @cssprop --modal-min-width - Minimum width. (Default: auto)
|
|
13
|
+
* @cssprop --modal-max-width - Maximum width. (Default: 40rem)
|
|
14
|
+
* @cssprop --modal-max-height - Maximum height. (Default: 80svh)
|
|
15
|
+
* @example
|
|
17
16
|
* <Modal bind:open={showModal}>
|
|
18
17
|
* {#snippet content(close)}
|
|
19
18
|
* <p>Modal content</p>
|
|
19
|
+
* <button onclick={close}>Close</button>
|
|
20
20
|
* {/snippet}
|
|
21
21
|
* </Modal>
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* **Pattern C: Auto-show (no trigger)**
|
|
25
|
-
* ```svelte
|
|
26
|
-
* {#if shouldShow}
|
|
27
|
-
* <Modal open onclose={() => shouldShow = false}>
|
|
28
|
-
* {#snippet content(close)}...{/snippet}
|
|
29
|
-
* </Modal>
|
|
30
|
-
* {/if}
|
|
31
|
-
* ```
|
|
32
22
|
*/
|
|
33
23
|
let {
|
|
34
24
|
open = $bindable(false),
|
|
@@ -241,6 +231,31 @@
|
|
|
241
231
|
dialog.Modal[open] {
|
|
242
232
|
display: grid;
|
|
243
233
|
grid-template-rows: 1fr auto;
|
|
234
|
+
opacity: 1;
|
|
235
|
+
translate: 0 0;
|
|
236
|
+
transition:
|
|
237
|
+
opacity var(--transition-duration-fast) ease-out,
|
|
238
|
+
translate var(--transition-duration-fast) ease-out,
|
|
239
|
+
display var(--transition-duration-fast) allow-discrete,
|
|
240
|
+
overlay var(--transition-duration-fast) allow-discrete;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
dialog.Modal[open]::backdrop {
|
|
244
|
+
opacity: 1;
|
|
245
|
+
transition:
|
|
246
|
+
opacity var(--transition-duration-fast) ease-out,
|
|
247
|
+
display var(--transition-duration-fast) allow-discrete,
|
|
248
|
+
overlay var(--transition-duration-fast) allow-discrete;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@starting-style {
|
|
252
|
+
dialog.Modal[open] {
|
|
253
|
+
opacity: 0;
|
|
254
|
+
translate: 0 var(--space-xs);
|
|
255
|
+
}
|
|
256
|
+
dialog.Modal[open]::backdrop {
|
|
257
|
+
opacity: 0;
|
|
258
|
+
}
|
|
244
259
|
}
|
|
245
260
|
|
|
246
261
|
dialog.Modal.contained {
|
|
@@ -306,7 +321,8 @@
|
|
|
306
321
|
}
|
|
307
322
|
|
|
308
323
|
@media (prefers-reduced-motion: reduce) {
|
|
309
|
-
dialog.Modal
|
|
324
|
+
dialog.Modal,
|
|
325
|
+
dialog.Modal::backdrop {
|
|
310
326
|
transition: none;
|
|
311
327
|
}
|
|
312
328
|
}
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { BROWSER } from "esm-env";
|
|
4
|
+
import UIContent from "./UIContent.svelte";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* @description
|
|
8
|
+
* A base popover component using the native Popover API and CSS Anchor Positioning.
|
|
9
|
+
* Use as a foundation for dropdowns, tooltips, contextual help, etc.
|
|
10
|
+
* Supports trigger snippets, external anchors, placement with fallbacks, and light dismiss.
|
|
11
|
+
* @cssprop --popover-background - Background color. (Default: var(--surface-background))
|
|
12
|
+
* @cssprop --popover-border - Border shorthand. (Default: var(--surface-border))
|
|
13
|
+
* @cssprop --popover-border-radius - Border radius. (Default: var(--surface-border-radius))
|
|
14
|
+
* @cssprop --popover-shadow - Box shadow. (Default: var(--surface-shadow))
|
|
15
|
+
* @cssprop --popover-width - Width of the popover. (Default: max-content)
|
|
16
|
+
* @cssprop --popover-max-width - Maximum width. (Default: calc(100vw - 2rem))
|
|
17
|
+
* @cssprop --popover-max-height - Maximum height. (Default: calc(100vh - 2rem))
|
|
18
|
+
* @example
|
|
19
|
+
* <Popover placement="bottom-start">
|
|
20
|
+
* {#snippet trigger({ toggle, triggerAttrs })}
|
|
21
|
+
* <button {...triggerAttrs}>Open</button>
|
|
22
|
+
* {/snippet}
|
|
23
|
+
* <p>Popover content</p>
|
|
24
|
+
* </Popover>
|
|
8
25
|
*/
|
|
9
26
|
let {
|
|
10
27
|
open = $bindable(false),
|
|
@@ -191,7 +208,9 @@
|
|
|
191
208
|
class:unstyled
|
|
192
209
|
style={popoverStyle}
|
|
193
210
|
>
|
|
194
|
-
|
|
211
|
+
<UIContent>
|
|
212
|
+
{@render children()}
|
|
213
|
+
</UIContent>
|
|
195
214
|
</div>
|
|
196
215
|
|
|
197
216
|
<style>
|
|
@@ -218,23 +237,34 @@
|
|
|
218
237
|
}
|
|
219
238
|
|
|
220
239
|
.Popover:popover-open {
|
|
221
|
-
|
|
240
|
+
opacity: 1;
|
|
241
|
+
translate: 0 0;
|
|
242
|
+
transition:
|
|
243
|
+
opacity var(--transition-duration-fast) ease-out,
|
|
244
|
+
translate var(--transition-duration-fast) ease-out,
|
|
245
|
+
display var(--transition-duration-fast) allow-discrete;
|
|
222
246
|
}
|
|
223
247
|
|
|
224
|
-
|
|
225
|
-
|
|
248
|
+
.Popover:not(:popover-open) {
|
|
249
|
+
opacity: 0;
|
|
250
|
+
translate: 0 calc(-1 * var(--space-xxs));
|
|
251
|
+
transition:
|
|
252
|
+
opacity var(--transition-duration-fast) ease-in,
|
|
253
|
+
translate var(--transition-duration-fast) ease-in,
|
|
254
|
+
display var(--transition-duration-fast) allow-discrete;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
@starting-style {
|
|
258
|
+
.Popover:popover-open {
|
|
226
259
|
opacity: 0;
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
to {
|
|
230
|
-
opacity: 1;
|
|
231
|
-
transform: translateY(0);
|
|
260
|
+
translate: 0 calc(-1 * var(--space-xxs));
|
|
232
261
|
}
|
|
233
262
|
}
|
|
234
263
|
|
|
235
264
|
@media (prefers-reduced-motion: reduce) {
|
|
236
|
-
.Popover:popover-open
|
|
237
|
-
|
|
265
|
+
.Popover:popover-open,
|
|
266
|
+
.Popover:not(:popover-open) {
|
|
267
|
+
transition: none;
|
|
238
268
|
}
|
|
239
269
|
}
|
|
240
270
|
</style>
|
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContext, type Snippet } from "svelte";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @description
|
|
6
|
+
* A single tab panel within a TabbedContent. Registers itself with the parent TabbedContent via context.
|
|
7
|
+
* @example
|
|
8
|
+
* <TabbedContent>
|
|
9
|
+
* <TabbedContentItem label="First">
|
|
10
|
+
* <p>First tab content</p>
|
|
11
|
+
* </TabbedContentItem>
|
|
12
|
+
* </TabbedContent>
|
|
13
|
+
*/
|
|
4
14
|
let {
|
|
5
15
|
id,
|
|
6
16
|
label,
|
|
7
17
|
href,
|
|
8
18
|
children,
|
|
9
19
|
}: {
|
|
20
|
+
/** Unique identifier for this tab. Defaults to a slug of `label`. */
|
|
10
21
|
id?: string;
|
|
22
|
+
/** The label displayed in the tab bar. */
|
|
11
23
|
label: string;
|
|
24
|
+
/** Optional URL hash for this tab. */
|
|
12
25
|
href?: string;
|
|
26
|
+
/** The content of this tab panel. */
|
|
13
27
|
children: Snippet;
|
|
14
28
|
} = $props();
|
|
15
29
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { type Snippet } from "svelte";
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
+
/** Unique identifier for this tab. Defaults to a slug of `label`. */
|
|
3
4
|
id?: string;
|
|
5
|
+
/** The label displayed in the tab bar. */
|
|
4
6
|
label: string;
|
|
7
|
+
/** Optional URL hash for this tab. */
|
|
5
8
|
href?: string;
|
|
9
|
+
/** The content of this tab panel. */
|
|
6
10
|
children: Snippet;
|
|
7
11
|
};
|
|
8
12
|
declare const TabbedContentItem: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContext, type Snippet } from "svelte";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @description
|
|
6
|
+
* A table wrapper that provides containment, rounding, hover highlights, and zebra striping.
|
|
7
|
+
* Styling is provided by the table tokens in the CSS layer. The `contained` prop can be set via context.
|
|
8
|
+
* @example
|
|
9
|
+
* <Table contained rounded hoverable>
|
|
10
|
+
* <thead><tr><th>Name</th><th>Value</th></tr></thead>
|
|
11
|
+
* <tbody><tr><td>Alpha</td><td>1</td></tr><tr><td>Beta</td><td>2</td></tr></tbody>
|
|
12
|
+
* </Table>
|
|
13
|
+
*/
|
|
4
14
|
let {
|
|
5
15
|
colored,
|
|
6
16
|
contained,
|
|
@@ -10,12 +20,19 @@
|
|
|
10
20
|
fullWidth,
|
|
11
21
|
children,
|
|
12
22
|
}: {
|
|
23
|
+
/** Enable alternating row background colors. */
|
|
13
24
|
colored?: boolean;
|
|
25
|
+
/** Wrap the table in a border. Inherits from `lutra.table.contained` or `lutra.contained` context. */
|
|
14
26
|
contained?: boolean;
|
|
27
|
+
/** Round the corners of the container when contained. */
|
|
15
28
|
rounded?: boolean;
|
|
29
|
+
/** Apply a negative inline margin to align table borders with surrounding content. */
|
|
16
30
|
hang?: boolean;
|
|
31
|
+
/** Highlight rows on hover. */
|
|
17
32
|
hoverable?: boolean;
|
|
33
|
+
/** Force the table to full width. */
|
|
18
34
|
fullWidth?: boolean;
|
|
35
|
+
/** Table content (thead, tbody, etc.). */
|
|
19
36
|
children: Snippet;
|
|
20
37
|
} = $props();
|
|
21
38
|
|
|
@@ -39,3 +56,55 @@
|
|
|
39
56
|
{@render children()}
|
|
40
57
|
</table>
|
|
41
58
|
</div>
|
|
59
|
+
|
|
60
|
+
<style>
|
|
61
|
+
.table-container {
|
|
62
|
+
overflow: clip;
|
|
63
|
+
}
|
|
64
|
+
.table-container.contained {
|
|
65
|
+
border: var(--table-border-size) var(--table-border-style) var(--table-border-color);
|
|
66
|
+
}
|
|
67
|
+
.table-container.rounded {
|
|
68
|
+
border-radius: var(--table-border-radius);
|
|
69
|
+
}
|
|
70
|
+
.table-container.hang {
|
|
71
|
+
margin-inline: calc(-1 * var(--table-cell-padding-inline));
|
|
72
|
+
}
|
|
73
|
+
table {
|
|
74
|
+
border-collapse: collapse;
|
|
75
|
+
width: 100%;
|
|
76
|
+
}
|
|
77
|
+
:global(th),
|
|
78
|
+
:global(td) {
|
|
79
|
+
padding-block: var(--table-cell-padding-block);
|
|
80
|
+
padding-inline: var(--table-cell-padding-inline);
|
|
81
|
+
text-align: start;
|
|
82
|
+
vertical-align: top;
|
|
83
|
+
color: var(--table-cell-color);
|
|
84
|
+
}
|
|
85
|
+
.contained :global(th),
|
|
86
|
+
.contained :global(td) {
|
|
87
|
+
border: none;
|
|
88
|
+
}
|
|
89
|
+
table:not(.contained) :global(th),
|
|
90
|
+
table:not(.contained) :global(td) {
|
|
91
|
+
border: var(--table-border-size) var(--table-border-style) var(--table-border-color);
|
|
92
|
+
}
|
|
93
|
+
:global(th) {
|
|
94
|
+
background-color: var(--table-header-background);
|
|
95
|
+
color: var(--table-header-color);
|
|
96
|
+
font-weight: var(--table-header-font-weight);
|
|
97
|
+
}
|
|
98
|
+
:global(tbody tr) {
|
|
99
|
+
background-color: var(--table-row-background);
|
|
100
|
+
}
|
|
101
|
+
.colored :global(tbody tr:nth-child(even)) {
|
|
102
|
+
background-color: var(--table-row-background-even);
|
|
103
|
+
}
|
|
104
|
+
.hoverable :global(tbody tr:hover) {
|
|
105
|
+
background-color: var(--table-row-background-hover);
|
|
106
|
+
}
|
|
107
|
+
.fullWidth {
|
|
108
|
+
width: 100%;
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { type Snippet } from "svelte";
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
+
/** Enable alternating row background colors. */
|
|
3
4
|
colored?: boolean;
|
|
5
|
+
/** Wrap the table in a border. Inherits from `lutra.table.contained` or `lutra.contained` context. */
|
|
4
6
|
contained?: boolean;
|
|
7
|
+
/** Round the corners of the container when contained. */
|
|
5
8
|
rounded?: boolean;
|
|
9
|
+
/** Apply a negative inline margin to align table borders with surrounding content. */
|
|
6
10
|
hang?: boolean;
|
|
11
|
+
/** Highlight rows on hover. */
|
|
7
12
|
hoverable?: boolean;
|
|
13
|
+
/** Force the table to full width. */
|
|
8
14
|
fullWidth?: boolean;
|
|
15
|
+
/** Table content (thead, tbody, etc.). */
|
|
9
16
|
children: Snippet;
|
|
10
17
|
};
|
|
11
18
|
declare const Table: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import { page } from "$app/
|
|
2
|
+
import { BROWSER } from 'esm-env';
|
|
3
|
+
import { page } from "$app/state";
|
|
4
4
|
import type { TabItem } from "./MenuTypes.js";
|
|
5
5
|
import { onMount } from "svelte";
|
|
6
6
|
|
|
@@ -8,6 +8,19 @@
|
|
|
8
8
|
* @description
|
|
9
9
|
* A tabbed navigation menu used to navigate between pages or sections of content.
|
|
10
10
|
* Clicking a tab will change the URL or trigger a JavaScript event.
|
|
11
|
+
* @cssprop --tab-background-color - Background color of the tab bar. (Default: var(--menu-background-color))
|
|
12
|
+
* @cssprop --tab-background-color-hover - Background color of a tab on hover. (Default: var(--menu-background-color-hover))
|
|
13
|
+
* @cssprop --tab-background-color-active - Background color of the active tab. (Default: var(--background-selected))
|
|
14
|
+
* @cssprop --tab-text-color - Text color of tabs. (Default: var(--menu-text-color))
|
|
15
|
+
* @cssprop --tab-text-color-active - Text color of the active tab. (Default: var(--text-color-heading))
|
|
16
|
+
* @cssprop --tab-border-size - Border width. (Default: var(--menu-border-size))
|
|
17
|
+
* @cssprop --tab-border-style - Border style. (Default: var(--menu-border-style))
|
|
18
|
+
* @cssprop --tab-border-color - Border color. (Default: var(--menu-border-color))
|
|
19
|
+
* @cssprop --tab-border-radius - Border radius when rounded. (Default: var(--menu-border-radius))
|
|
20
|
+
* @cssprop --tab-gap - Gap between tabs when not contained. (Default: var(--space-md))
|
|
21
|
+
* @cssprop --tab-padding - Padding of each tab. (Default: var(--space-sm) var(--space-xs))
|
|
22
|
+
* @cssprop --tab-font-size - Font size of each tab label. (Default: var(--font-size-sm))
|
|
23
|
+
* @cssprop --tab-letter-spacing - Letter spacing of each tab label. (Default: -0.05ch)
|
|
11
24
|
* @example
|
|
12
25
|
* <Tabs contained rounded items={[
|
|
13
26
|
* {
|
|
@@ -58,21 +71,15 @@
|
|
|
58
71
|
|
|
59
72
|
let activeIndex = $derived.by(() => {
|
|
60
73
|
return items.findIndex((item, index) => {
|
|
61
|
-
console.log(item.href);
|
|
62
74
|
if(!item.href) return false;
|
|
63
|
-
// check if href ends in *
|
|
64
75
|
if(item.href.endsWith('*')) {
|
|
65
|
-
return
|
|
76
|
+
return page.url.pathname.startsWith(item.href.slice(0, -1));
|
|
66
77
|
} else {
|
|
67
|
-
return
|
|
78
|
+
return page.url.pathname.endsWith(item.href);
|
|
68
79
|
}
|
|
69
80
|
})
|
|
70
81
|
});
|
|
71
82
|
|
|
72
|
-
$effect(() => {
|
|
73
|
-
console.log(activeIndex);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
83
|
let loaded = $state(false);
|
|
77
84
|
|
|
78
85
|
onMount(async () => {
|
|
@@ -81,7 +88,7 @@
|
|
|
81
88
|
});
|
|
82
89
|
|
|
83
90
|
let underlineStyle = $derived.by(() => {
|
|
84
|
-
if(
|
|
91
|
+
if(BROWSER && underline && loaded) {
|
|
85
92
|
let active = items[activeIndex];
|
|
86
93
|
let activeElement: HTMLElement | null = document.querySelector(`#${id} li[data-index="${activeIndex}"]`);
|
|
87
94
|
if(activeElement) {
|
|
@@ -126,15 +133,14 @@
|
|
|
126
133
|
<style>
|
|
127
134
|
.Tabs {
|
|
128
135
|
display: flex;
|
|
129
|
-
|
|
130
|
-
background: var(--menu-bg);
|
|
136
|
+
background: var(--tab-background-color, var(--menu-background-color));
|
|
131
137
|
overflow: clip;
|
|
132
138
|
}
|
|
133
139
|
.Tabs.contained {
|
|
134
|
-
border: var(--menu-border);
|
|
140
|
+
border: var(--tab-border-size, var(--menu-border-size)) var(--tab-border-style, var(--menu-border-style)) var(--tab-border-color, var(--menu-border-color));
|
|
135
141
|
}
|
|
136
142
|
.Tabs.rounded {
|
|
137
|
-
border-radius: var(--border-radius);
|
|
143
|
+
border-radius: var(--tab-border-radius, var(--menu-border-radius));
|
|
138
144
|
}
|
|
139
145
|
menu, li {
|
|
140
146
|
list-style: none;
|
|
@@ -148,9 +154,9 @@
|
|
|
148
154
|
align-items: center;
|
|
149
155
|
justify-content: flex-start;
|
|
150
156
|
padding: 0;
|
|
151
|
-
gap: var(--gap,
|
|
157
|
+
gap: var(--tab-gap, var(--space-md));
|
|
152
158
|
inline-size: 100%;
|
|
153
|
-
border-block-end: var(--menu-border);
|
|
159
|
+
border-block-end: var(--tab-border-size, var(--menu-border-size)) var(--tab-border-style, var(--menu-border-style)) var(--tab-border-color, var(--menu-border-color));
|
|
154
160
|
}
|
|
155
161
|
.Tabs.contained menu {
|
|
156
162
|
gap: 0;
|
|
@@ -161,15 +167,15 @@
|
|
|
161
167
|
a,
|
|
162
168
|
button {
|
|
163
169
|
display: block;
|
|
164
|
-
padding: var(--padding,
|
|
165
|
-
color: var(--menu-text);
|
|
166
|
-
transition: all var(--
|
|
167
|
-
font-weight:
|
|
168
|
-
font-size: var(--font-size,
|
|
169
|
-
letter-spacing: -0.05ch;
|
|
170
|
+
padding: var(--tab-padding, var(--space-sm) var(--space-xs));
|
|
171
|
+
color: var(--tab-text-color, var(--menu-text-color));
|
|
172
|
+
transition: all var(--transition-duration-fast);
|
|
173
|
+
font-weight: var(--font-weight-normal);
|
|
174
|
+
font-size: var(--tab-font-size, var(--font-size-sm));
|
|
175
|
+
letter-spacing: var(--tab-letter-spacing, -0.05ch);
|
|
170
176
|
background: transparent;
|
|
171
177
|
border: none;
|
|
172
|
-
border-block-end:
|
|
178
|
+
border-block-end: var(--border-size-thick) solid transparent;
|
|
173
179
|
cursor: pointer;
|
|
174
180
|
text-decoration: none;
|
|
175
181
|
}
|
|
@@ -178,7 +184,7 @@
|
|
|
178
184
|
}
|
|
179
185
|
.Tabs.contained li {
|
|
180
186
|
flex-grow: 1;
|
|
181
|
-
border-inline-end: var(--menu-border);
|
|
187
|
+
border-inline-end: var(--tab-border-size, var(--menu-border-size)) var(--tab-border-style, var(--menu-border-style)) var(--tab-border-color, var(--menu-border-color));
|
|
182
188
|
flex-basis: auto;
|
|
183
189
|
}
|
|
184
190
|
.Tabs.contained menu li:last-of-type {
|
|
@@ -189,28 +195,30 @@
|
|
|
189
195
|
flex-grow: 1;
|
|
190
196
|
inline-size: 100%;
|
|
191
197
|
text-align: center;
|
|
192
|
-
padding-block-start: calc(
|
|
193
|
-
color: var(--menu-text);
|
|
194
|
-
font-weight:
|
|
198
|
+
padding-block-start: calc(var(--space-sm) + var(--border-size-thick));
|
|
199
|
+
color: var(--tab-text-color, var(--menu-text-color));
|
|
200
|
+
font-weight: var(--font-weight-medium);
|
|
195
201
|
}
|
|
196
202
|
a:hover,
|
|
197
|
-
button:hover
|
|
198
|
-
|
|
199
|
-
|
|
203
|
+
button:hover,
|
|
204
|
+
a:focus-visible,
|
|
205
|
+
button:focus-visible {
|
|
206
|
+
background-color: var(--tab-background-color-hover, var(--menu-background-color-hover));
|
|
207
|
+
outline: none;
|
|
200
208
|
}
|
|
201
209
|
li[aria-current="page"] a,
|
|
202
210
|
li[aria-current="page"] button {
|
|
203
|
-
background: var(--
|
|
204
|
-
color: var(--
|
|
211
|
+
background: var(--tab-background-color-active, var(--background-selected));
|
|
212
|
+
color: var(--tab-text-color-active, var(--text-color-heading));
|
|
205
213
|
opacity: 1;
|
|
206
214
|
}
|
|
207
215
|
.Underline {
|
|
208
|
-
height:
|
|
209
|
-
background-color: var(--
|
|
216
|
+
height: var(--border-size-thick);
|
|
217
|
+
background-color: var(--tab-text-color-active, var(--text-color-heading));
|
|
210
218
|
position: absolute;
|
|
211
219
|
bottom: 0;
|
|
212
220
|
left: 0;
|
|
213
|
-
transition: all
|
|
221
|
+
transition: all var(--transition-duration-fast) ease-out;
|
|
214
222
|
opacity: 0;
|
|
215
223
|
}
|
|
216
224
|
</style>
|