contain-css-svelte 1.1.19 → 1.2.0
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/Card.svelte +22 -8
- package/dist/Card.svelte.d.ts +4 -5
- package/dist/controls/Button.svelte +19 -5
- package/dist/controls/Button.svelte.d.ts +4 -4
- package/dist/controls/ButtonLink.svelte +17 -14
- package/dist/controls/ButtonLink.svelte.d.ts +4 -4
- package/dist/controls/Checkbox.svelte +15 -8
- package/dist/controls/Checkbox.svelte.d.ts +4 -4
- package/dist/controls/CircleButton.svelte +14 -7
- package/dist/controls/CircleButton.svelte.d.ts +4 -4
- package/dist/controls/Input.svelte +14 -3
- package/dist/controls/Input.svelte.d.ts +4 -3
- package/dist/controls/Option.svelte +4 -3
- package/dist/controls/Option.svelte.d.ts +3 -2
- package/dist/controls/RadioButton.svelte +14 -7
- package/dist/controls/RadioButton.svelte.d.ts +4 -4
- package/dist/controls/Select.svelte +15 -3
- package/dist/controls/Select.svelte.d.ts +4 -3
- package/dist/controls/Slider.svelte +5 -11
- package/dist/controls/Slider.svelte.d.ts +3 -3
- package/dist/controls/TabItem.svelte +24 -5
- package/dist/controls/TabItem.svelte.d.ts +4 -4
- package/dist/controls/Toggle.svelte +21 -5
- package/dist/controls/Toggle.svelte.d.ts +4 -4
- package/dist/dropdowns/DropdownMenu.svelte +18 -6
- package/dist/dropdowns/DropdownMenu.svelte.d.ts +4 -4
- package/dist/layout/Accordion.svelte +17 -2
- package/dist/layout/Accordion.svelte.d.ts +5 -3
- package/dist/layout/Bar.svelte +27 -15
- package/dist/layout/Bar.svelte.d.ts +4 -4
- package/dist/layout/Column.svelte.d.ts +3 -3
- package/dist/layout/ColumnContainer.svelte +12 -9
- package/dist/layout/ColumnContainer.svelte.d.ts +4 -4
- package/dist/layout/Columns.svelte +4 -3
- package/dist/layout/Columns.svelte.d.ts +7 -3
- package/dist/layout/Container.svelte +23 -8
- package/dist/layout/Container.svelte.d.ts +7 -5
- package/dist/layout/DataList.svelte +15 -7
- package/dist/layout/DataList.svelte.d.ts +5 -4
- package/dist/layout/DataListItem.svelte +14 -8
- package/dist/layout/DataListItem.svelte.d.ts +4 -4
- package/dist/layout/Fieldset.svelte +16 -8
- package/dist/layout/Fieldset.svelte.d.ts +6 -3
- package/dist/layout/Form.svelte +17 -8
- package/dist/layout/Form.svelte.d.ts +8 -6
- package/dist/layout/FormItem.svelte +12 -7
- package/dist/layout/FormItem.svelte.d.ts +4 -3
- package/dist/layout/FormProvider.svelte +3 -0
- package/dist/layout/GridLayout.svelte +14 -9
- package/dist/layout/GridLayout.svelte.d.ts +4 -4
- package/dist/layout/GridRow.svelte +6 -10
- package/dist/layout/GridRow.svelte.d.ts +3 -2
- package/dist/layout/Hero.svelte +14 -8
- package/dist/layout/Hero.svelte.d.ts +4 -4
- package/dist/layout/Inline.svelte +16 -15
- package/dist/layout/Inline.svelte.d.ts +4 -4
- package/dist/layout/MenuList.svelte +13 -6
- package/dist/layout/MenuList.svelte.d.ts +4 -4
- package/dist/layout/Page.svelte +14 -8
- package/dist/layout/Page.svelte.d.ts +11 -3
- package/dist/layout/ResponsiveText.svelte +4 -0
- package/dist/layout/Row.svelte.d.ts +3 -3
- package/dist/layout/RowContainer.svelte +12 -9
- package/dist/layout/RowContainer.svelte.d.ts +4 -4
- package/dist/layout/Sidebar.svelte +17 -6
- package/dist/layout/Sidebar.svelte.d.ts +12 -4
- package/dist/layout/SplitPane.svelte +8 -14
- package/dist/layout/SplitPane.svelte.d.ts +16 -2
- package/dist/layout/Stack.svelte +16 -15
- package/dist/layout/Stack.svelte.d.ts +4 -4
- package/dist/layout/TabBar.svelte +12 -2
- package/dist/layout/TabBar.svelte.d.ts +17 -10
- package/dist/layout/Table.svelte +5 -1
- package/dist/layout/Tile.svelte +40 -27
- package/dist/layout/Tile.svelte.d.ts +32 -10
- package/dist/misc/Code.svelte +2 -0
- package/dist/misc/Progress.svelte +25 -8
- package/dist/misc/Progress.svelte.d.ts +15 -8
- package/dist/misc/Tag.svelte +97 -44
- package/dist/misc/Tag.svelte.d.ts +17 -5
- package/dist/overlays/Dialog.svelte +18 -5
- package/dist/overlays/Dialog.svelte.d.ts +5 -3
- package/dist/overlays/Tooltip.svelte +21 -3
- package/dist/overlays/Tooltip.svelte.d.ts +5 -3
- package/dist/styleProps.d.ts +67 -0
- package/dist/styleProps.js +76 -0
- package/dist/types.d.ts +40 -1
- package/dist/types.js +1 -1
- package/dist/typography/Text.svelte +4 -11
- package/dist/typography/TextLayout.svelte +4 -7
- package/dist/typography/TextLayout.svelte.d.ts +4 -3
- package/dist/util.d.ts +60 -3
- package/dist/util.js +101 -11
- package/package.json +1 -1
package/dist/misc/Tag.svelte
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
|
-
<script lang="ts">import {
|
|
2
|
-
|
|
3
|
-
let
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<script lang="ts">import { elementProps } from "../util";
|
|
2
|
+
import { COLOR_VARS, PADDING_VARS, RADIUS_VARS, TYPOGRAPHY_VARS, } from "../styleProps";
|
|
3
|
+
let { children, primary, warning, danger, success, info, onclose = null, closeLabel = "Remove", class: className, ...restProps } = $props();
|
|
4
|
+
/* The shorthands tag's own CSS backs, one group per mixin it
|
|
5
|
+
includes. The Props type is derived from this same array, so what the
|
|
6
|
+
component accepts and what it emits cannot drift apart. */
|
|
7
|
+
const TAG_VARS = [
|
|
8
|
+
...COLOR_VARS,
|
|
9
|
+
...PADDING_VARS,
|
|
10
|
+
...RADIUS_VARS,
|
|
11
|
+
...TYPOGRAPHY_VARS,
|
|
12
|
+
];
|
|
13
|
+
const el = $derived(elementProps(restProps, "tag", TAG_VARS));
|
|
10
14
|
</script>
|
|
11
15
|
|
|
12
16
|
<span
|
|
13
|
-
{
|
|
14
|
-
class="tag"
|
|
17
|
+
class={["tag", className]}
|
|
15
18
|
class:closable={!!onclose}
|
|
16
|
-
{...restProps}
|
|
17
19
|
class:primary
|
|
18
20
|
class:warning
|
|
19
21
|
class:danger
|
|
20
22
|
class:success
|
|
21
23
|
class:info
|
|
24
|
+
{...el}
|
|
22
25
|
>
|
|
23
|
-
{@render children?.()}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</button>
|
|
29
|
-
{/if}
|
|
26
|
+
{@render children?.()}{#if onclose}<button
|
|
27
|
+
class="close-button"
|
|
28
|
+
aria-label={closeLabel}
|
|
29
|
+
onclick={onclose}><span aria-hidden="true">×</span></button
|
|
30
|
+
>{/if}
|
|
30
31
|
</span>
|
|
31
32
|
|
|
32
33
|
<style>/* Logical, not top/bottom/left/right: margin-block/margin-inline already take
|
|
@@ -161,48 +162,100 @@ let style = $derived(injectVars(restProps, "tag", [
|
|
|
161
162
|
margin-inline-end: var(--space);
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
/* A closable tag lays its label and button out in flow rather than absolutely
|
|
166
|
+
positioning the button over the top-right corner. The old approach needed a
|
|
167
|
+
literal in the markup to stop the button covering the last character,
|
|
168
|
+
which still overlapped once a tag wrapped to two lines and put the button's
|
|
169
|
+
hit area outside the padding. As a flex item the button reserves its own
|
|
170
|
+
space at any length, and the gap scales with the tag's font-size. */
|
|
164
171
|
.tag.closable {
|
|
165
|
-
|
|
172
|
+
display: inline-flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
gap: var(--tag-close-button-gap, 0.35em);
|
|
166
175
|
}
|
|
167
176
|
|
|
168
|
-
.tag button {
|
|
177
|
+
.tag .close-button {
|
|
169
178
|
background: transparent;
|
|
170
179
|
color: inherit;
|
|
171
180
|
box-shadow: none;
|
|
172
181
|
border: none;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
padding: 0;
|
|
183
|
+
margin: 0;
|
|
184
|
+
/* Square, so the focus ring and pointer target read as a button rather
|
|
185
|
+
than tracking the width of the glyph. */
|
|
186
|
+
inline-size: var(--tag-close-button-size, 1.25em);
|
|
187
|
+
block-size: var(--tag-close-button-size, 1.25em);
|
|
188
|
+
position: relative;
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
justify-content: center;
|
|
192
|
+
border-radius: var(--tag-close-button-border-radius, 50%);
|
|
193
|
+
font-size: inherit;
|
|
194
|
+
line-height: 1;
|
|
195
|
+
flex: none;
|
|
176
196
|
cursor: var(--tag-close-button-cursor, var(--button-cursor, var(--cursor, pointer)));
|
|
177
197
|
transition: filter var(--tag-close-button-transition, var(--button-transition, var(--transition, 300ms))), background-color var(--tag-close-button-transition, var(--button-transition, var(--transition, 300ms))), border-color var(--tag-close-button-transition, var(--button-transition, var(--transition, 300ms))), box-shadow var(--tag-close-button-transition, var(--button-transition, var(--transition, 300ms))), transform var(--tag-close-button-transition, var(--button-transition, var(--transition, 300ms)));
|
|
178
198
|
}
|
|
179
199
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
/* The affordance is a scrim mixed from the tag's own FOREGROUND, not from
|
|
201
|
+
`clickable()`'s fill.
|
|
202
|
+
|
|
203
|
+
clickable() derives its hover fill from --_background-color, which this
|
|
204
|
+
button inherits from the tag. On a red tag that produced 90% red + 10%
|
|
205
|
+
white -- a muddy circle a shade off the tag it sits on, reading as a
|
|
206
|
+
rendering artifact rather than a control. Mixing from currentColor
|
|
207
|
+
instead inverts correctly against any tag colour: a light scrim on a
|
|
208
|
+
saturated tag, a dark one on the default pale tag, with no per-variant
|
|
209
|
+
rules. */
|
|
210
|
+
.tag .close-button::before {
|
|
211
|
+
content: "";
|
|
212
|
+
position: absolute;
|
|
213
|
+
inset: 0;
|
|
214
|
+
border-radius: inherit;
|
|
215
|
+
background-color: transparent;
|
|
216
|
+
transition: background-color var(--tag-close-button-transition, var(--transition, 150ms));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.tag .close-button:hover::before {
|
|
220
|
+
background-color: var(--tag-close-button-hover-bg, color-mix(in oklab, transparent, currentColor 18%));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.tag .close-button:active::before {
|
|
224
|
+
background-color: var(--tag-close-button-active-bg, color-mix(in oklab, transparent, currentColor 30%));
|
|
185
225
|
}
|
|
186
226
|
|
|
187
|
-
.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
227
|
+
/* WCAG 2.5.8 wants a 24x24 CSS px target. The glyph is sized in `em` so it
|
|
228
|
+
stays proportional to a tag that is deliberately tiny (0.75rem), which
|
|
229
|
+
left a 15x15 target. This expands the POINTER target without changing
|
|
230
|
+
the visual size or the tag's height. */
|
|
231
|
+
.tag .close-button::after {
|
|
232
|
+
content: "";
|
|
233
|
+
position: absolute;
|
|
234
|
+
top: 50%;
|
|
235
|
+
left: 50%;
|
|
236
|
+
translate: -50% -50%;
|
|
237
|
+
inline-size: max(100%, var(--tag-close-button-target-size, 24px));
|
|
238
|
+
block-size: max(100%, var(--tag-close-button-target-size, 24px));
|
|
192
239
|
}
|
|
193
240
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
241
|
+
/* focus-ring()'s 3px spread shadow plus its 2px offset is sized for a button
|
|
242
|
+
standing on a page; on a 15px control inside a 26px tag it ballooned well
|
|
243
|
+
outside the tag.
|
|
244
|
+
|
|
245
|
+
The room available is exactly the tag's padding-block (0.2em, ~2.4px at
|
|
246
|
+
the default tag font-size) -- the button is as tall as the tag's line box,
|
|
247
|
+
so there is nothing else to grow into. Hence a 2px ring at no offset: it
|
|
248
|
+
reads clearly, hugs the circle, and clears the tag's edge. The scrim stays
|
|
249
|
+
lit under focus so keyboard focus reads the same as pointer hover (the
|
|
250
|
+
`focusable-as-hover` idea, with this component's own fill). */
|
|
251
|
+
.tag .close-button:focus-visible {
|
|
252
|
+
outline: var(--tag-close-button-focus-color, var(--focus-color, currentColor)) solid var(--tag-close-button-focus-width, 2px);
|
|
253
|
+
outline-offset: var(--tag-close-button-focus-offset, 0px);
|
|
254
|
+
box-shadow: none;
|
|
200
255
|
}
|
|
201
256
|
|
|
202
|
-
.tag button:focus-visible {
|
|
203
|
-
|
|
204
|
-
outline-offset: var(--focus-outline-offset, 2px);
|
|
205
|
-
box-shadow: var(--focus-ring-box-shadow, 0 0 0 3px var(--focus-shadow-color, rgba(100, 150, 250, 0.5)));
|
|
257
|
+
.tag .close-button:focus-visible::before {
|
|
258
|
+
background-color: var(--tag-close-button-hover-bg, color-mix(in oklab, transparent, currentColor 18%));
|
|
206
259
|
}
|
|
207
260
|
|
|
208
261
|
.tag:first-child {
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
1
2
|
import type { HTMLAttributes } from "svelte/elements";
|
|
2
|
-
import type { TagStyleProps } from "../types";
|
|
3
|
-
type
|
|
4
|
-
|
|
3
|
+
import type { ContainProps, TagStyleProps } from "../types";
|
|
4
|
+
import { type StyleProps } from "../styleProps";
|
|
5
|
+
declare const Tag: import("svelte").Component<ContainProps<HTMLAttributes<HTMLSpanElement>, {
|
|
6
|
+
children?: Snippet;
|
|
5
7
|
primary?: boolean;
|
|
6
8
|
warning?: boolean;
|
|
7
9
|
danger?: boolean;
|
|
8
10
|
success?: boolean;
|
|
9
11
|
info?: boolean;
|
|
10
12
|
onclose?: (() => void) | null;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Accessible name for the close button.
|
|
15
|
+
*
|
|
16
|
+
* The default describes the *widget* ("close a tag"), which is rarely
|
|
17
|
+
* what the action means to a user. A tag is a filter chip in one app and
|
|
18
|
+
* a removable label in another, so say what pressing it does here:
|
|
19
|
+
* `closeLabel="Remove Fiction"`, `closeLabel="Stop searching by author"`.
|
|
20
|
+
* Including the tag's own text is what makes a list of close buttons
|
|
21
|
+
* distinguishable to a screen reader.
|
|
22
|
+
*/
|
|
23
|
+
closeLabel?: string;
|
|
24
|
+
}, TagStyleProps & StyleProps<readonly ["bg", "fg", "padding", "borderRadius", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textTransform", "textDecoration", "fontVariant"]>>, {}, "">;
|
|
13
25
|
type Tag = ReturnType<typeof Tag>;
|
|
14
26
|
export default Tag;
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
<script lang="ts">import CircleButton from "../controls/CircleButton.svelte";
|
|
2
|
-
import { copyCSSVariables,
|
|
3
|
-
|
|
2
|
+
import { copyCSSVariables, splitProps } from "../util";
|
|
3
|
+
import { COLOR_VARS, PADDING_VARS, RADIUS_VARS, TYPOGRAPHY_CONTAINER_VARS, } from "../styleProps";
|
|
4
|
+
let { open = true, modal = true, dismissible = false, children, onClose, onclose: oncloseProp = null, class: className, ...restProps } = $props();
|
|
4
5
|
let onclose = $derived(oncloseProp || onClose);
|
|
5
|
-
|
|
6
|
+
/* The <section> is the variable carrier that copyCSSVariables reads through,
|
|
7
|
+
so it takes the style while the <dialog> takes the attributes -- a
|
|
8
|
+
caller's `aria-*` and `data-*` belong on the dialog itself. */
|
|
9
|
+
/* The shorthands this component's own CSS backs, one group per mixin
|
|
10
|
+
it includes. The Props type is derived from this same array, so what
|
|
11
|
+
the component accepts and what it emits cannot drift apart. */
|
|
12
|
+
const DIALOG_VARS = [
|
|
13
|
+
...COLOR_VARS,
|
|
14
|
+
...PADDING_VARS,
|
|
15
|
+
...RADIUS_VARS,
|
|
16
|
+
...TYPOGRAPHY_CONTAINER_VARS,
|
|
17
|
+
];
|
|
18
|
+
const el = $derived(splitProps(restProps, "dialog", DIALOG_VARS));
|
|
6
19
|
// Handle backdrop click to close modal (click outside behavior)
|
|
7
20
|
// Clicks on the dialog element itself (the backdrop) close the dialog
|
|
8
21
|
function handleBackdropClick(event) {
|
|
@@ -52,9 +65,9 @@ let dialogElement;
|
|
|
52
65
|
let ref;
|
|
53
66
|
</script>
|
|
54
67
|
|
|
55
|
-
<section {style}>
|
|
68
|
+
<section style={el.style}>
|
|
56
69
|
<div class="variable-placeholder" bind:this={ref}></div>
|
|
57
|
-
<dialog bind:this={dialogElement} {onclose} {...
|
|
70
|
+
<dialog bind:this={dialogElement} {onclose} class={className} {...el.attrs}>
|
|
58
71
|
<div class="close-bar">
|
|
59
72
|
<div class="close-button">
|
|
60
73
|
<CircleButton onclick={onclose}>×</CircleButton>
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { type StyleProps } from "../styleProps";
|
|
1
2
|
import type { Snippet } from "svelte";
|
|
2
|
-
type
|
|
3
|
+
import type { HTMLDialogAttributes } from "svelte/elements";
|
|
4
|
+
import type { ContainProps } from "../types";
|
|
5
|
+
declare const Dialog: import("svelte").Component<ContainProps<HTMLDialogAttributes, {
|
|
3
6
|
open?: boolean;
|
|
4
7
|
modal?: boolean;
|
|
5
8
|
dismissible?: boolean;
|
|
6
9
|
children?: Snippet;
|
|
7
10
|
onclose?: (() => void) | null;
|
|
8
11
|
onClose?: (() => void) | null;
|
|
9
|
-
}
|
|
10
|
-
declare const Dialog: import("svelte").Component<PropsType, {}, "">;
|
|
12
|
+
}, StyleProps<readonly ["bg", "fg", "padding", "borderRadius", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textTransform", "textDecoration", "fontVariant", "lineWidth"]>>, {}, "">;
|
|
11
13
|
type Dialog = ReturnType<typeof Dialog>;
|
|
12
14
|
export default Dialog;
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
<script lang="ts">import { onDestroy, tick } from "svelte";
|
|
2
|
+
import { elementProps } from "../util";
|
|
3
|
+
import { COLOR_VARS, PADDING_VARS, RADIUS_VARS, TYPOGRAPHY_CONTAINER_VARS, } from "../styleProps";
|
|
2
4
|
let tooltipDiv = $state();
|
|
3
5
|
let targetDiv = $state();
|
|
4
6
|
let tooltipMeasurementDiv = $state();
|
|
5
|
-
let { tooltipText = "", vertical = "bottom", horizontal = "right", children, tooltip, block = false, } = $props();
|
|
7
|
+
let { tooltipText = "", vertical = "bottom", horizontal = "right", children, tooltip, block = false, class: className, ...restProps } = $props();
|
|
8
|
+
/* The wrapper is the element a caller is pointing at -- the tooltip itself
|
|
9
|
+
is a popover the component owns and positions. */
|
|
10
|
+
/* The shorthands this component's own CSS backs, one group per mixin
|
|
11
|
+
it includes. The Props type is derived from this same array, so what
|
|
12
|
+
the component accepts and what it emits cannot drift apart. */
|
|
13
|
+
const TOOLTIP_VARS = [
|
|
14
|
+
...COLOR_VARS,
|
|
15
|
+
...PADDING_VARS,
|
|
16
|
+
...RADIUS_VARS,
|
|
17
|
+
...TYPOGRAPHY_CONTAINER_VARS,
|
|
18
|
+
];
|
|
19
|
+
/* The variables land on the wrapper and reach the popover by inheritance:
|
|
20
|
+
the tooltip is a descendant of it, and custom properties inherit. */
|
|
21
|
+
const el = $derived(elementProps(restProps, "tooltip", TOOLTIP_VARS));
|
|
6
22
|
// svelte-ignore state_referenced_locally
|
|
7
23
|
let renderedVertical = $state(vertical);
|
|
8
24
|
// svelte-ignore state_referenced_locally
|
|
@@ -206,11 +222,12 @@ async function showPopover() {
|
|
|
206
222
|
{#if block}
|
|
207
223
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
208
224
|
<div
|
|
209
|
-
class="tooltip-wrapper"
|
|
225
|
+
class={["tooltip-wrapper", className]}
|
|
210
226
|
onmouseenter={() => showPopover()}
|
|
211
227
|
onmouseleave={() => hidePopover()}
|
|
212
228
|
onfocusin={() => showPopover()}
|
|
213
229
|
onfocusout={() => hidePopover()}
|
|
230
|
+
{...el}
|
|
214
231
|
>
|
|
215
232
|
<div class="tooltip-target" bind:this={targetDiv}>
|
|
216
233
|
{@render children?.()}
|
|
@@ -241,11 +258,12 @@ async function showPopover() {
|
|
|
241
258
|
{:else}
|
|
242
259
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
243
260
|
<span
|
|
244
|
-
class="tooltip-wrapper"
|
|
261
|
+
class={["tooltip-wrapper", className]}
|
|
245
262
|
onmouseenter={() => showPopover()}
|
|
246
263
|
onmouseleave={() => hidePopover()}
|
|
247
264
|
onfocusin={() => showPopover()}
|
|
248
265
|
onfocusout={() => hidePopover()}
|
|
266
|
+
{...el}
|
|
249
267
|
>
|
|
250
268
|
<span class="tooltip-target" bind:this={targetDiv}>
|
|
251
269
|
{@render children?.()}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
2
|
+
import type { ContainProps } from "../types";
|
|
3
|
+
import { type StyleProps } from "../styleProps";
|
|
4
|
+
declare const Tooltip: import("svelte").Component<ContainProps<HTMLAttributes<HTMLElement>, {
|
|
2
5
|
tooltipText?: string;
|
|
3
6
|
vertical?: string;
|
|
4
7
|
horizontal?: string;
|
|
5
8
|
children?: import("svelte").Snippet;
|
|
6
9
|
tooltip?: import("svelte").Snippet;
|
|
7
10
|
block?: boolean;
|
|
8
|
-
}
|
|
9
|
-
declare const Tooltip: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
}, StyleProps<readonly ["bg", "fg", "padding", "borderRadius", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textTransform", "textDecoration", "fontVariant", "lineWidth"]>>, {}, "">;
|
|
10
12
|
type Tooltip = ReturnType<typeof Tooltip>;
|
|
11
13
|
export default Tooltip;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The style-prop shorthands, grouped to mirror the SCSS mixins that make them
|
|
3
|
+
* readable.
|
|
4
|
+
*
|
|
5
|
+
* The problem this solves: which shorthands a component accepted used to be a
|
|
6
|
+
* hand-maintained list in each component, drifting from the mixins its CSS
|
|
7
|
+
* actually included. Tag exposed `fontSize` while the other 23 components
|
|
8
|
+
* whose CSS includes a typography mixin exposed none of it -- `--button-font-
|
|
9
|
+
* weight` resolved perfectly well, there was just no prop for it. In the other
|
|
10
|
+
* direction, FormItem injected three variables no stylesheet read at all.
|
|
11
|
+
*
|
|
12
|
+
* So each group below names one mixin, and a component's prop list is the
|
|
13
|
+
* union of the groups for the mixins its own CSS includes. "Which shorthands
|
|
14
|
+
* does this component take" stops being a decision and becomes a consequence.
|
|
15
|
+
*
|
|
16
|
+
* The prop types are derived from these same arrays via `StyleProps<>`, so the
|
|
17
|
+
* type and the runtime list cannot disagree -- adding a name to the array is
|
|
18
|
+
* what adds the prop.
|
|
19
|
+
*
|
|
20
|
+
* A shorthand is only safe when the element the component renders has no HTML
|
|
21
|
+
* attribute of that name: `ContainProps` resolves the clash by dropping the
|
|
22
|
+
* attribute, which is right for a deprecated or meaningless one and wrong for
|
|
23
|
+
* `<progress max>` or `<option label>`. That is why the size group is applied
|
|
24
|
+
* per component rather than being folded into the others, and why Progress's
|
|
25
|
+
* accessible-name prop is `progressLabel`.
|
|
26
|
+
*/
|
|
27
|
+
/** Every style prop takes a CSS value, or null/undefined to leave it unset. */
|
|
28
|
+
export type StyleProps<T extends readonly string[]> = {
|
|
29
|
+
[K in T[number]]?: string | null;
|
|
30
|
+
};
|
|
31
|
+
/** `@include color-props(<prefix>, ...)` */
|
|
32
|
+
export declare const COLOR_VARS: readonly ["bg", "fg"];
|
|
33
|
+
/** `@include padding-props(...)`, and the box-props family that includes it */
|
|
34
|
+
export declare const PADDING_VARS: readonly ["padding"];
|
|
35
|
+
/** The border-radius the box-props family sets alongside padding */
|
|
36
|
+
export declare const RADIUS_VARS: readonly ["borderRadius"];
|
|
37
|
+
/** `@include margin-props(<prefix>, ...)` */
|
|
38
|
+
export declare const MARGIN_VARS: readonly ["marginBlock", "marginInline"];
|
|
39
|
+
/** `@include gap-props(<prefix>, ...)` */
|
|
40
|
+
export declare const GAP_VARS: readonly ["gap"];
|
|
41
|
+
/**
|
|
42
|
+
* `@include typography-props(...)` and its `-bare` / `-bold` variants.
|
|
43
|
+
*
|
|
44
|
+
* `fontSize` was the only one of these ever exposed as a prop, and only on
|
|
45
|
+
* Tag. The rest resolved in CSS the whole time.
|
|
46
|
+
*/
|
|
47
|
+
export declare const TYPOGRAPHY_VARS: readonly ["fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textTransform", "textDecoration", "fontVariant"];
|
|
48
|
+
/**
|
|
49
|
+
* `@include typography-container-props(...)`, which is typography-props plus
|
|
50
|
+
* the readable measure it imposes on prose children.
|
|
51
|
+
*/
|
|
52
|
+
export declare const TYPOGRAPHY_CONTAINER_VARS: readonly ["fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textTransform", "textDecoration", "fontVariant", "lineWidth"];
|
|
53
|
+
/**
|
|
54
|
+
* `@include box-size-props(<prefix>, ...)`.
|
|
55
|
+
*
|
|
56
|
+
* Deliberately NOT part of any other group: `width` and `height` are real HTML
|
|
57
|
+
* attributes on `<input>`, `<img>`, `<canvas>` and `<iframe>`, so a component
|
|
58
|
+
* rendering one of those must not shadow them. Applied per component.
|
|
59
|
+
*/
|
|
60
|
+
export declare const SIZE_VARS: readonly ["width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight"];
|
|
61
|
+
export type ColorStyleProps = StyleProps<typeof COLOR_VARS>;
|
|
62
|
+
export type PaddingStyleProps = StyleProps<typeof PADDING_VARS>;
|
|
63
|
+
export type RadiusStyleProps = StyleProps<typeof RADIUS_VARS>;
|
|
64
|
+
export type GapStyleProps = StyleProps<typeof GAP_VARS>;
|
|
65
|
+
export type TypographyStyleProps = StyleProps<typeof TYPOGRAPHY_VARS>;
|
|
66
|
+
export type TypographyContainerStyleProps = StyleProps<typeof TYPOGRAPHY_CONTAINER_VARS>;
|
|
67
|
+
export type SizeStyleProps = StyleProps<typeof SIZE_VARS>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The style-prop shorthands, grouped to mirror the SCSS mixins that make them
|
|
3
|
+
* readable.
|
|
4
|
+
*
|
|
5
|
+
* The problem this solves: which shorthands a component accepted used to be a
|
|
6
|
+
* hand-maintained list in each component, drifting from the mixins its CSS
|
|
7
|
+
* actually included. Tag exposed `fontSize` while the other 23 components
|
|
8
|
+
* whose CSS includes a typography mixin exposed none of it -- `--button-font-
|
|
9
|
+
* weight` resolved perfectly well, there was just no prop for it. In the other
|
|
10
|
+
* direction, FormItem injected three variables no stylesheet read at all.
|
|
11
|
+
*
|
|
12
|
+
* So each group below names one mixin, and a component's prop list is the
|
|
13
|
+
* union of the groups for the mixins its own CSS includes. "Which shorthands
|
|
14
|
+
* does this component take" stops being a decision and becomes a consequence.
|
|
15
|
+
*
|
|
16
|
+
* The prop types are derived from these same arrays via `StyleProps<>`, so the
|
|
17
|
+
* type and the runtime list cannot disagree -- adding a name to the array is
|
|
18
|
+
* what adds the prop.
|
|
19
|
+
*
|
|
20
|
+
* A shorthand is only safe when the element the component renders has no HTML
|
|
21
|
+
* attribute of that name: `ContainProps` resolves the clash by dropping the
|
|
22
|
+
* attribute, which is right for a deprecated or meaningless one and wrong for
|
|
23
|
+
* `<progress max>` or `<option label>`. That is why the size group is applied
|
|
24
|
+
* per component rather than being folded into the others, and why Progress's
|
|
25
|
+
* accessible-name prop is `progressLabel`.
|
|
26
|
+
*/
|
|
27
|
+
/** `@include color-props(<prefix>, ...)` */
|
|
28
|
+
export const COLOR_VARS = ["bg", "fg"];
|
|
29
|
+
/** `@include padding-props(...)`, and the box-props family that includes it */
|
|
30
|
+
export const PADDING_VARS = ["padding"];
|
|
31
|
+
/** The border-radius the box-props family sets alongside padding */
|
|
32
|
+
export const RADIUS_VARS = ["borderRadius"];
|
|
33
|
+
/** `@include margin-props(<prefix>, ...)` */
|
|
34
|
+
export const MARGIN_VARS = ["marginBlock", "marginInline"];
|
|
35
|
+
/** `@include gap-props(<prefix>, ...)` */
|
|
36
|
+
export const GAP_VARS = ["gap"];
|
|
37
|
+
/**
|
|
38
|
+
* `@include typography-props(...)` and its `-bare` / `-bold` variants.
|
|
39
|
+
*
|
|
40
|
+
* `fontSize` was the only one of these ever exposed as a prop, and only on
|
|
41
|
+
* Tag. The rest resolved in CSS the whole time.
|
|
42
|
+
*/
|
|
43
|
+
export const TYPOGRAPHY_VARS = [
|
|
44
|
+
"fontFamily",
|
|
45
|
+
"fontSize",
|
|
46
|
+
"fontWeight",
|
|
47
|
+
"lineHeight",
|
|
48
|
+
"letterSpacing",
|
|
49
|
+
"textAlign",
|
|
50
|
+
"textTransform",
|
|
51
|
+
"textDecoration",
|
|
52
|
+
"fontVariant",
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* `@include typography-container-props(...)`, which is typography-props plus
|
|
56
|
+
* the readable measure it imposes on prose children.
|
|
57
|
+
*/
|
|
58
|
+
export const TYPOGRAPHY_CONTAINER_VARS = [
|
|
59
|
+
...TYPOGRAPHY_VARS,
|
|
60
|
+
"lineWidth",
|
|
61
|
+
];
|
|
62
|
+
/**
|
|
63
|
+
* `@include box-size-props(<prefix>, ...)`.
|
|
64
|
+
*
|
|
65
|
+
* Deliberately NOT part of any other group: `width` and `height` are real HTML
|
|
66
|
+
* attributes on `<input>`, `<img>`, `<canvas>` and `<iframe>`, so a component
|
|
67
|
+
* rendering one of those must not shadow them. Applied per component.
|
|
68
|
+
*/
|
|
69
|
+
export const SIZE_VARS = [
|
|
70
|
+
"width",
|
|
71
|
+
"minWidth",
|
|
72
|
+
"maxWidth",
|
|
73
|
+
"height",
|
|
74
|
+
"minHeight",
|
|
75
|
+
"maxHeight",
|
|
76
|
+
];
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Common CSS variable props that can be passed to components.
|
|
3
|
-
* These are converted to CSS custom properties via
|
|
3
|
+
* These are converted to CSS custom properties via elementProps().
|
|
4
4
|
*/
|
|
5
5
|
/** Base style props supported by most components */
|
|
6
6
|
export interface BaseStyleProps {
|
|
@@ -88,3 +88,42 @@ export interface DropdownMenuStyleProps extends BaseStyleProps {
|
|
|
88
88
|
triggerFg?: string | null;
|
|
89
89
|
triggerPadding?: string | null;
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Props that let a caller set CSS custom properties directly on a component.
|
|
93
|
+
*
|
|
94
|
+
* NOTE: writing `<Tag --tag-bg="red">` in a template does NOT go through this
|
|
95
|
+
* type -- Svelte intercepts `--*` attributes on components itself and renders
|
|
96
|
+
* `<svelte-css-wrapper style="display: contents; --tag-bg: red;">` around the
|
|
97
|
+
* component. This type covers the remaining path, an object spread
|
|
98
|
+
* (`<Tag {...{"--tag-bg": "red"}}>`), which Svelte cannot detect statically and
|
|
99
|
+
* therefore passes through as an ordinary prop.
|
|
100
|
+
*/
|
|
101
|
+
export type CssVarProps = {
|
|
102
|
+
[key: `--${string}`]: string | number | null | undefined;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* The standard prop type for a Contain CSS component.
|
|
106
|
+
*
|
|
107
|
+
* Composes the three things every component's props are made of, and -- the
|
|
108
|
+
* reason this exists rather than a bare `&` chain -- removes the element
|
|
109
|
+
* attributes that the style props and the component's own props shadow.
|
|
110
|
+
* `width`, `height` and `align` are real HTML attributes, so intersecting
|
|
111
|
+
* `BaseStyleProps` with `HTMLInputAttributes` the old way produced
|
|
112
|
+
* `(string | null) & (string | number | undefined)` for `width`: a type neither
|
|
113
|
+
* side meant, which silently accepted and rejected the wrong values.
|
|
114
|
+
*
|
|
115
|
+
* @typeParam Attributes - the element's attribute type, e.g. `HTMLButtonAttributes`
|
|
116
|
+
* @typeParam Own - the component's own props (snippets, variant booleans, ...)
|
|
117
|
+
* @typeParam Style - the component's style props, e.g. `BaseStyleProps`
|
|
118
|
+
* @typeParam Owned - attributes the component controls and a caller must not
|
|
119
|
+
* set, e.g. `"type"` on Slider's range input. Spreading rest props last means
|
|
120
|
+
* a caller's value would otherwise win over the component's own.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* type Props = ContainProps<
|
|
124
|
+
* HTMLButtonAttributes,
|
|
125
|
+
* { primary?: boolean; children?: Snippet },
|
|
126
|
+
* BaseStyleProps
|
|
127
|
+
* >;
|
|
128
|
+
*/
|
|
129
|
+
export type ContainProps<Attributes, Own = {}, Style = {}, Owned extends keyof Attributes | string = never> = Own & Style & Omit<Attributes, keyof Own | keyof Style | Owned> & CssVarProps;
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<script lang="ts">import {
|
|
2
|
-
let { children, primary = false, secondary = false, info = false, success = false, warning = false, danger = false, muted = false, bold = false, italic = false, color, amount,
|
|
1
|
+
<script lang="ts">import { elementProps } from "../util";
|
|
2
|
+
let { children, primary = false, secondary = false, info = false, success = false, warning = false, danger = false, muted = false, bold = false, italic = false, color, amount, class: className, ...restProps } = $props();
|
|
3
3
|
// Choose one tone deterministically; explicit color takes precedence.
|
|
4
4
|
const tone = $derived(danger
|
|
5
5
|
? "danger"
|
|
@@ -30,17 +30,10 @@ const foreground = $derived.by(() => {
|
|
|
30
30
|
return mixed;
|
|
31
31
|
return `var(--${tone}-text-fg, ${mixed})`;
|
|
32
32
|
});
|
|
33
|
-
const
|
|
34
|
-
const style = $derived(injectVars(restProps, "text", []) + (inlineStyle ?? ""));
|
|
33
|
+
const el = $derived(elementProps(restProps, "text"));
|
|
35
34
|
</script>
|
|
36
35
|
|
|
37
|
-
<span
|
|
38
|
-
{...elementProps}
|
|
39
|
-
{style}
|
|
40
|
-
style:color={foreground}
|
|
41
|
-
class:bold
|
|
42
|
-
class:italic
|
|
43
|
-
>
|
|
36
|
+
<span class={className} class:bold class:italic style:color={foreground} {...el}>
|
|
44
37
|
{@render children?.()}
|
|
45
38
|
</span>
|
|
46
39
|
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
<script lang="ts">import {
|
|
2
|
-
let { id = "",
|
|
3
|
-
const
|
|
4
|
-
"marginBlock",
|
|
5
|
-
"marginInline",
|
|
6
|
-
]));
|
|
1
|
+
<script lang="ts">import { elementProps } from "../util";
|
|
2
|
+
let { id = "", children, class: className, ...restProps } = $props();
|
|
3
|
+
const el = $derived(elementProps(restProps, "text-layout", ["marginBlock", "marginInline"]));
|
|
7
4
|
</script>
|
|
8
5
|
|
|
9
|
-
<div {id} {
|
|
6
|
+
<div {id} class={className} {...el}>
|
|
10
7
|
{@render children?.()}
|
|
11
8
|
</div>
|
|
12
9
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
2
|
+
import type { ContainProps, MarginStyleProps } from "../types";
|
|
3
|
+
type Props = ContainProps<HTMLAttributes<HTMLDivElement>, {
|
|
3
4
|
id?: string;
|
|
4
5
|
children?: import("svelte").Snippet;
|
|
5
|
-
}
|
|
6
|
+
}, MarginStyleProps>;
|
|
6
7
|
declare const TextLayout: import("svelte").Component<Props, {}, "">;
|
|
7
8
|
type TextLayout = ReturnType<typeof TextLayout>;
|
|
8
9
|
export default TextLayout;
|