@xtyle/astro 0.5.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/README.md +42 -0
- package/package.json +25 -0
- package/src/Accordion.astro +79 -0
- package/src/Alert.astro +57 -0
- package/src/AppShell.astro +97 -0
- package/src/Avatar.astro +71 -0
- package/src/AvatarGroup.astro +44 -0
- package/src/Badge.astro +73 -0
- package/src/Bar.astro +83 -0
- package/src/Breadcrumb.astro +54 -0
- package/src/Button.astro +91 -0
- package/src/Card.astro +44 -0
- package/src/CardLink.astro +60 -0
- package/src/Carousel.astro +39 -0
- package/src/Checkbox.astro +68 -0
- package/src/CheckboxGroup.astro +54 -0
- package/src/Cluster.astro +46 -0
- package/src/Code.astro +42 -0
- package/src/ColorPicker.astro +184 -0
- package/src/Dialog.astro +69 -0
- package/src/Dock.astro +79 -0
- package/src/DockZone.astro +17 -0
- package/src/Eyebrow.astro +30 -0
- package/src/Field.astro +117 -0
- package/src/FormGroup.astro +71 -0
- package/src/Grid.astro +57 -0
- package/src/Heading.astro +34 -0
- package/src/Heatmap.astro +116 -0
- package/src/Hero.astro +19 -0
- package/src/Icon.astro +53 -0
- package/src/Image.astro +56 -0
- package/src/Kbd.astro +27 -0
- package/src/Link.astro +56 -0
- package/src/Menu.astro +38 -0
- package/src/NumberInput.astro +86 -0
- package/src/Pagination.astro +53 -0
- package/src/Panel.astro +68 -0
- package/src/Parallax.astro +18 -0
- package/src/Pie.astro +65 -0
- package/src/Progress.astro +96 -0
- package/src/Radio.astro +71 -0
- package/src/RadioGroup.astro +44 -0
- package/src/Section.astro +61 -0
- package/src/Segment.astro +15 -0
- package/src/Segmented.astro +95 -0
- package/src/Select.astro +79 -0
- package/src/Separator.astro +36 -0
- package/src/Skeleton.astro +25 -0
- package/src/Slider.astro +93 -0
- package/src/Sparkline.astro +79 -0
- package/src/Spinner.astro +37 -0
- package/src/Splitter.astro +87 -0
- package/src/Stack.astro +42 -0
- package/src/Stat.astro +70 -0
- package/src/Statusbar.astro +56 -0
- package/src/Swatch.astro +69 -0
- package/src/Switch.astro +89 -0
- package/src/Table.astro +46 -0
- package/src/Tabs.astro +94 -0
- package/src/Text.astro +54 -0
- package/src/Textarea.astro +81 -0
- package/src/Toast.astro +62 -0
- package/src/ToastRegion.astro +39 -0
- package/src/Toc.astro +35 -0
- package/src/Toolbar.astro +68 -0
- package/src/Tooltip.astro +68 -0
- package/src/Tree.astro +78 -0
- package/src/internal/palette.ts +92 -0
package/src/Swatch.astro
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { formatColor, parseColor, type ColorFormat } from "@xtyle/core";
|
|
3
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
4
|
+
|
|
5
|
+
type SwatchSize = "sm" | "md" | "lg";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
color: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
value?: string;
|
|
11
|
+
size?: SwatchSize;
|
|
12
|
+
interactive?: boolean;
|
|
13
|
+
selected?: boolean;
|
|
14
|
+
details?: boolean;
|
|
15
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
16
|
+
static?: boolean;
|
|
17
|
+
class?: string;
|
|
18
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
color,
|
|
24
|
+
label,
|
|
25
|
+
value,
|
|
26
|
+
size = "md",
|
|
27
|
+
interactive = false,
|
|
28
|
+
selected = false,
|
|
29
|
+
details = false,
|
|
30
|
+
static: isStatic = false,
|
|
31
|
+
class: extra,
|
|
32
|
+
...rest
|
|
33
|
+
} = Astro.props;
|
|
34
|
+
|
|
35
|
+
const detailsId = `xtyle-swatch-details-${crypto.randomUUID().slice(0, 8)}`;
|
|
36
|
+
|
|
37
|
+
const DETAIL_FORMATS: ColorFormat[] = ["hex", "rgb", "hsl", "oklch"];
|
|
38
|
+
const rgb = details ? parseColor(color ?? "") : null;
|
|
39
|
+
const showsDetails = !!rgb;
|
|
40
|
+
const detailRows = rgb ? DETAIL_FORMATS.map((format) => ({ model: format, value: formatColor(rgb, format) })) : [];
|
|
41
|
+
|
|
42
|
+
const bindings = {
|
|
43
|
+
color,
|
|
44
|
+
label: label ?? null,
|
|
45
|
+
value: value ?? null,
|
|
46
|
+
size,
|
|
47
|
+
interactive,
|
|
48
|
+
selected,
|
|
49
|
+
showsDetails,
|
|
50
|
+
detailRows,
|
|
51
|
+
detailsId,
|
|
52
|
+
};
|
|
53
|
+
const light = await renderFragmentLight("swatch", bindings);
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
<xtyle-swatch
|
|
57
|
+
color={color}
|
|
58
|
+
label={label ?? undefined}
|
|
59
|
+
value={value ?? undefined}
|
|
60
|
+
size={size}
|
|
61
|
+
interactive={interactive || undefined}
|
|
62
|
+
selected={selected || undefined}
|
|
63
|
+
details={details || undefined}
|
|
64
|
+
class={extra}
|
|
65
|
+
{...rest}
|
|
66
|
+
set:html={light}
|
|
67
|
+
/>
|
|
68
|
+
|
|
69
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
package/src/Switch.astro
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
3
|
+
|
|
4
|
+
import type { FullTone as Tone } from "@xtyle/core";
|
|
5
|
+
type Size = "sm" | "md" | "lg";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
checked?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
size?: Size;
|
|
11
|
+
tone?: Tone;
|
|
12
|
+
shape?: "pill" | "square";
|
|
13
|
+
orientation?: "horizontal" | "vertical";
|
|
14
|
+
reverse?: boolean;
|
|
15
|
+
labelSide?: "start" | "end";
|
|
16
|
+
label?: string;
|
|
17
|
+
labelledby?: string;
|
|
18
|
+
onLabel?: string;
|
|
19
|
+
offLabel?: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
value?: string;
|
|
22
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
23
|
+
static?: boolean;
|
|
24
|
+
class?: string;
|
|
25
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
checked = false,
|
|
31
|
+
disabled = false,
|
|
32
|
+
size = "md",
|
|
33
|
+
tone = "accent",
|
|
34
|
+
shape = "pill",
|
|
35
|
+
orientation = "horizontal",
|
|
36
|
+
reverse = false,
|
|
37
|
+
labelSide = "start",
|
|
38
|
+
label,
|
|
39
|
+
labelledby,
|
|
40
|
+
onLabel,
|
|
41
|
+
offLabel,
|
|
42
|
+
name,
|
|
43
|
+
value,
|
|
44
|
+
static: isStatic = false,
|
|
45
|
+
class: extra,
|
|
46
|
+
...rest
|
|
47
|
+
} = Astro.props;
|
|
48
|
+
|
|
49
|
+
const elementId = `xtyle-switch-${Math.random().toString(36).slice(2, 8)}`;
|
|
50
|
+
|
|
51
|
+
const bindings = {
|
|
52
|
+
checked,
|
|
53
|
+
disabled,
|
|
54
|
+
size,
|
|
55
|
+
tone,
|
|
56
|
+
shape,
|
|
57
|
+
orientation,
|
|
58
|
+
reverse,
|
|
59
|
+
labelSide,
|
|
60
|
+
label: label ?? null,
|
|
61
|
+
labelledby: labelledby ?? null,
|
|
62
|
+
onLabel: onLabel ?? null,
|
|
63
|
+
offLabel: offLabel ?? null,
|
|
64
|
+
elementId,
|
|
65
|
+
};
|
|
66
|
+
const light = await renderFragmentLight("switch", bindings);
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
<xtyle-switch
|
|
70
|
+
checked={checked || undefined}
|
|
71
|
+
disabled={disabled || undefined}
|
|
72
|
+
size={size}
|
|
73
|
+
tone={tone}
|
|
74
|
+
shape={shape !== "pill" ? shape : undefined}
|
|
75
|
+
orientation={orientation !== "horizontal" ? orientation : undefined}
|
|
76
|
+
reverse={reverse || undefined}
|
|
77
|
+
label-side={labelSide !== "start" ? labelSide : undefined}
|
|
78
|
+
label={label}
|
|
79
|
+
labelledby={labelledby}
|
|
80
|
+
on-label={onLabel}
|
|
81
|
+
off-label={offLabel}
|
|
82
|
+
name={name}
|
|
83
|
+
value={value}
|
|
84
|
+
class={extra}
|
|
85
|
+
set:html={light}
|
|
86
|
+
{...rest}
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
package/src/Table.astro
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
type TableVariant = "default" | "striped" | "bordered";
|
|
3
|
+
type TableSize = "normal" | "compact";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
variant?: TableVariant;
|
|
7
|
+
size?: TableSize;
|
|
8
|
+
hover?: boolean;
|
|
9
|
+
sticky?: boolean;
|
|
10
|
+
/** Cap the wrapper's height so it scrolls internally — required for `sticky` to have a scrollport to stick within. Any CSS length. */
|
|
11
|
+
maxHeight?: string;
|
|
12
|
+
ariaLabel?: string;
|
|
13
|
+
class?: string;
|
|
14
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
variant = "default",
|
|
20
|
+
size = "normal",
|
|
21
|
+
hover = false,
|
|
22
|
+
sticky = false,
|
|
23
|
+
maxHeight,
|
|
24
|
+
ariaLabel,
|
|
25
|
+
class: extra,
|
|
26
|
+
...rest
|
|
27
|
+
} = Astro.props;
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<xtyle-table
|
|
31
|
+
variant={variant}
|
|
32
|
+
size={size}
|
|
33
|
+
hover={hover ? "" : undefined}
|
|
34
|
+
sticky={sticky ? "" : undefined}
|
|
35
|
+
max-height={maxHeight || undefined}
|
|
36
|
+
style={maxHeight ? `--xtyle-table-max-height: ${maxHeight}` : undefined}
|
|
37
|
+
aria-label={ariaLabel || undefined}
|
|
38
|
+
class:list={["xtyle-table-wrap", extra]}
|
|
39
|
+
{...rest}
|
|
40
|
+
>
|
|
41
|
+
<slot />
|
|
42
|
+
</xtyle-table>
|
|
43
|
+
|
|
44
|
+
<script>
|
|
45
|
+
import "@xtyle/core/elements";
|
|
46
|
+
</script>
|
package/src/Tabs.astro
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { type TabItemData } from "@xtyle/core/markup";
|
|
3
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
4
|
+
|
|
5
|
+
type Size = "sm" | "md" | "lg";
|
|
6
|
+
type TabsVariant = "underline" | "pill" | "enclosed";
|
|
7
|
+
type TabsActivation = "automatic" | "manual";
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
items?: TabItemData[];
|
|
11
|
+
variant?: TabsVariant;
|
|
12
|
+
size?: Size;
|
|
13
|
+
activation?: TabsActivation;
|
|
14
|
+
value?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
labelledby?: string;
|
|
17
|
+
/** Pin the tablist while the active panel scrolls beneath it (app-surface tabs); off for inline tabs. */
|
|
18
|
+
sticky?: boolean;
|
|
19
|
+
/** Render only the tab strip (no panel region) so the consumer owns the content; the element still
|
|
20
|
+
* drives selection, roving focus, and a11y, and tabs omit `aria-controls` since they own no panels. */
|
|
21
|
+
tablist?: boolean;
|
|
22
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
23
|
+
static?: boolean;
|
|
24
|
+
class?: string;
|
|
25
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
items,
|
|
31
|
+
variant = "underline",
|
|
32
|
+
size = "md",
|
|
33
|
+
activation = "automatic",
|
|
34
|
+
value,
|
|
35
|
+
label,
|
|
36
|
+
labelledby,
|
|
37
|
+
sticky = false,
|
|
38
|
+
tablist = false,
|
|
39
|
+
static: isStatic = false,
|
|
40
|
+
class: extra,
|
|
41
|
+
...rest
|
|
42
|
+
} = Astro.props;
|
|
43
|
+
|
|
44
|
+
const tabItems = items ?? [];
|
|
45
|
+
const uid = `xtyle-tabs-${Math.random().toString(36).slice(2, 9)}`;
|
|
46
|
+
|
|
47
|
+
const bindings = {
|
|
48
|
+
tabs: tabItems.map((item, i) => ({
|
|
49
|
+
key: item.value ?? String(i),
|
|
50
|
+
label: item.label,
|
|
51
|
+
panel: item.panel ?? "",
|
|
52
|
+
disabled: item.disabled,
|
|
53
|
+
})),
|
|
54
|
+
activeId: value ?? null,
|
|
55
|
+
variant,
|
|
56
|
+
size,
|
|
57
|
+
sticky,
|
|
58
|
+
tablist,
|
|
59
|
+
label: label ?? null,
|
|
60
|
+
labelledby: labelledby ?? null,
|
|
61
|
+
uid,
|
|
62
|
+
};
|
|
63
|
+
// Two authoring modes. items-mode (the common case) renders the whole chrome light from `bindings`
|
|
64
|
+
// and ships no children. The advanced slotted mode pairs the consumer's `slot="tab"`/`slot="panel"`
|
|
65
|
+
// children by order, so they must survive *individually* (with their slot attributes) — Astro's
|
|
66
|
+
// `<slot name>` passthrough keeps them intact, and the element maps them on connect.
|
|
67
|
+
const useItems = tabItems.length > 0;
|
|
68
|
+
const light = useItems ? await renderFragmentLight("tabs", bindings) : "";
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
{useItems ? (
|
|
72
|
+
<xtyle-tabs
|
|
73
|
+
variant={variant}
|
|
74
|
+
size={size}
|
|
75
|
+
activation={activation}
|
|
76
|
+
value={value}
|
|
77
|
+
label={label}
|
|
78
|
+
labelledby={labelledby}
|
|
79
|
+
sticky={sticky}
|
|
80
|
+
tablist={tablist || undefined}
|
|
81
|
+
items={JSON.stringify(items)}
|
|
82
|
+
class={extra}
|
|
83
|
+
set:html={light}
|
|
84
|
+
{...rest}
|
|
85
|
+
/>
|
|
86
|
+
) : (
|
|
87
|
+
<xtyle-tabs variant={variant} size={size} activation={activation} value={value} label={label} labelledby={labelledby} sticky={sticky} tablist={tablist || undefined} class={extra} {...rest}>
|
|
88
|
+
<slot name="tab" />
|
|
89
|
+
<slot name="panel" />
|
|
90
|
+
<slot />
|
|
91
|
+
</xtyle-tabs>
|
|
92
|
+
)}
|
|
93
|
+
|
|
94
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
package/src/Text.astro
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
3
|
+
|
|
4
|
+
type TextAs = "p" | "span";
|
|
5
|
+
type TextSize = "xs" | "sm" | "body" | "lg";
|
|
6
|
+
type TextWeight = "normal" | "medium" | "semibold" | "bold";
|
|
7
|
+
type TextLeading = "tight" | "snug" | "loose";
|
|
8
|
+
type TextTone = "default" | "muted" | "subtle" | "accent";
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
as?: TextAs;
|
|
12
|
+
size?: TextSize;
|
|
13
|
+
weight?: TextWeight;
|
|
14
|
+
leading?: TextLeading;
|
|
15
|
+
tone?: TextTone;
|
|
16
|
+
mono?: boolean;
|
|
17
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
18
|
+
static?: boolean;
|
|
19
|
+
class?: string;
|
|
20
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
as = "p",
|
|
26
|
+
size = "body",
|
|
27
|
+
weight = "normal",
|
|
28
|
+
leading = "snug",
|
|
29
|
+
tone = "default",
|
|
30
|
+
mono = false,
|
|
31
|
+
static: isStatic = false,
|
|
32
|
+
class: extra,
|
|
33
|
+
...rest
|
|
34
|
+
} = Astro.props;
|
|
35
|
+
|
|
36
|
+
const bindings = { as, size, weight, leading, tone, mono };
|
|
37
|
+
const chrome = await renderFragmentLight("text", bindings);
|
|
38
|
+
const slotHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
|
|
39
|
+
const composed = chrome.replace("<slot></slot>", () => slotHtml);
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
<xtyle-text
|
|
43
|
+
as={as}
|
|
44
|
+
size={size}
|
|
45
|
+
weight={weight}
|
|
46
|
+
leading={leading}
|
|
47
|
+
tone={tone}
|
|
48
|
+
mono={mono || undefined}
|
|
49
|
+
class={extra}
|
|
50
|
+
set:html={composed}
|
|
51
|
+
{...rest}
|
|
52
|
+
/>
|
|
53
|
+
|
|
54
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
3
|
+
|
|
4
|
+
type Size = "sm" | "md" | "lg";
|
|
5
|
+
type TextareaResize = "none" | "vertical" | "horizontal" | "both";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
label?: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
rows?: number;
|
|
11
|
+
resize?: TextareaResize;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
size?: Size;
|
|
14
|
+
name?: string;
|
|
15
|
+
invalid?: boolean;
|
|
16
|
+
error?: string;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
required?: boolean;
|
|
19
|
+
/** Render the control in the monospace stack for code-shaped text. */
|
|
20
|
+
mono?: boolean;
|
|
21
|
+
/** Render zero-JS: emit the declarative shadow but never load the runtime to hydrate it. */
|
|
22
|
+
static?: boolean;
|
|
23
|
+
class?: string;
|
|
24
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
label,
|
|
30
|
+
value,
|
|
31
|
+
rows = 3,
|
|
32
|
+
resize = "vertical",
|
|
33
|
+
placeholder,
|
|
34
|
+
size = "md",
|
|
35
|
+
name,
|
|
36
|
+
invalid = false,
|
|
37
|
+
error,
|
|
38
|
+
disabled = false,
|
|
39
|
+
required = false,
|
|
40
|
+
mono = false,
|
|
41
|
+
static: isStatic = false,
|
|
42
|
+
class: extra,
|
|
43
|
+
...rest
|
|
44
|
+
} = Astro.props;
|
|
45
|
+
|
|
46
|
+
const seed = Math.random().toString(36).slice(2, 9);
|
|
47
|
+
const fieldId = `xtyle-textarea-${seed}`;
|
|
48
|
+
const errorId = `xtyle-textarea-error-${seed}`;
|
|
49
|
+
|
|
50
|
+
const bindings = {
|
|
51
|
+
fieldId,
|
|
52
|
+
errorId,
|
|
53
|
+
label: label ?? null,
|
|
54
|
+
error: error ?? null,
|
|
55
|
+
size,
|
|
56
|
+
resize,
|
|
57
|
+
invalid,
|
|
58
|
+
mono,
|
|
59
|
+
};
|
|
60
|
+
const light = await renderFragmentLight("textarea", bindings);
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
<xtyle-textarea
|
|
64
|
+
label={label}
|
|
65
|
+
value={value}
|
|
66
|
+
rows={rows}
|
|
67
|
+
resize={resize}
|
|
68
|
+
placeholder={placeholder}
|
|
69
|
+
size={size}
|
|
70
|
+
name={name}
|
|
71
|
+
invalid={invalid || undefined}
|
|
72
|
+
error={error}
|
|
73
|
+
disabled={disabled || undefined}
|
|
74
|
+
required={required || undefined}
|
|
75
|
+
mono={mono || undefined}
|
|
76
|
+
class={extra}
|
|
77
|
+
set:html={light}
|
|
78
|
+
{...rest}
|
|
79
|
+
/>
|
|
80
|
+
|
|
81
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
package/src/Toast.astro
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { renderFragmentLight, composeFallbackSlot } from "@xtyle/core/elements/ssr";
|
|
3
|
+
import type { FullTone } from "@xtyle/core";
|
|
4
|
+
|
|
5
|
+
type ToastSeverity = "success" | "warn" | "danger" | "info";
|
|
6
|
+
type ToastVariant = "soft" | "solid";
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
/** Color — any semantic role, accent variant, or named hue. Defaults to the severity color. */
|
|
10
|
+
tone?: FullTone;
|
|
11
|
+
/** Meaning — drives the glyph + politeness, independent of color. Omit for a color-only toast. */
|
|
12
|
+
severity?: ToastSeverity;
|
|
13
|
+
variant?: ToastVariant;
|
|
14
|
+
closable?: boolean;
|
|
15
|
+
closeLabel?: string;
|
|
16
|
+
actionLabel?: string;
|
|
17
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
18
|
+
static?: boolean;
|
|
19
|
+
class?: string;
|
|
20
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
tone,
|
|
26
|
+
severity,
|
|
27
|
+
variant = "soft",
|
|
28
|
+
closable = true,
|
|
29
|
+
closeLabel,
|
|
30
|
+
actionLabel,
|
|
31
|
+
static: isStatic = false,
|
|
32
|
+
class: extra,
|
|
33
|
+
...rest
|
|
34
|
+
} = Astro.props;
|
|
35
|
+
|
|
36
|
+
const bindings = {
|
|
37
|
+
tone,
|
|
38
|
+
severity,
|
|
39
|
+
variant,
|
|
40
|
+
closable,
|
|
41
|
+
closeLabel: closeLabel ?? "Dismiss",
|
|
42
|
+
actionLabel: actionLabel ?? null,
|
|
43
|
+
};
|
|
44
|
+
const light = await renderFragmentLight("toast", bindings);
|
|
45
|
+
const iconHtml = Astro.slots.has("icon") ? await Astro.slots.render("icon") : null;
|
|
46
|
+
const messageHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
|
|
47
|
+
const composed = composeFallbackSlot(light, "icon", iconHtml).replace("<slot></slot>", () => messageHtml);
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
<xtyle-toast
|
|
51
|
+
tone={tone}
|
|
52
|
+
severity={severity}
|
|
53
|
+
variant={variant}
|
|
54
|
+
closable={closable || undefined}
|
|
55
|
+
close-label={closeLabel}
|
|
56
|
+
action-label={actionLabel}
|
|
57
|
+
class={extra}
|
|
58
|
+
set:html={composed}
|
|
59
|
+
{...rest}
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { toastRegionMarkup, toastRegionHostCss } from "@xtyle/core/markup";
|
|
3
|
+
import { toastCss } from "@xtyle/core/css";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
placement?: string;
|
|
7
|
+
max?: number;
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Render zero-JS: emit the declarative shadow but never load the runtime to hydrate it. */
|
|
10
|
+
static?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
placement = "bottom-right",
|
|
18
|
+
max,
|
|
19
|
+
label,
|
|
20
|
+
static: isStatic = false,
|
|
21
|
+
class: extra,
|
|
22
|
+
...rest
|
|
23
|
+
} = Astro.props;
|
|
24
|
+
|
|
25
|
+
const shadow = `<style>${toastRegionHostCss}${toastCss}</style>${toastRegionMarkup({ placement, label })}`;
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
<xtyle-toast-region
|
|
29
|
+
placement={placement}
|
|
30
|
+
max={max}
|
|
31
|
+
label={label}
|
|
32
|
+
class={extra}
|
|
33
|
+
{...rest}
|
|
34
|
+
>
|
|
35
|
+
<template shadowrootmode="open" set:html={shadow}></template>
|
|
36
|
+
<slot />
|
|
37
|
+
</xtyle-toast-region>
|
|
38
|
+
|
|
39
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
package/src/Toc.astro
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { type TocItem } from "@xtyle/core/markup";
|
|
3
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
items: TocItem[];
|
|
7
|
+
label?: string;
|
|
8
|
+
sticky?: boolean;
|
|
9
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
10
|
+
static?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { items, label = "On this page", sticky = false, static: isStatic = false, class: extra, ...rest } = Astro.props;
|
|
17
|
+
|
|
18
|
+
const bindings = {
|
|
19
|
+
items: items ?? [],
|
|
20
|
+
label,
|
|
21
|
+
sticky,
|
|
22
|
+
};
|
|
23
|
+
const light = await renderFragmentLight("toc", bindings);
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
<xtyle-toc
|
|
27
|
+
items={items ? JSON.stringify(items) : undefined}
|
|
28
|
+
label={label}
|
|
29
|
+
sticky={sticky || undefined}
|
|
30
|
+
class={extra}
|
|
31
|
+
{...rest}
|
|
32
|
+
set:html={light}
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
3
|
+
|
|
4
|
+
type Size = "sm" | "md" | "lg";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
heading?: string;
|
|
8
|
+
href?: string;
|
|
9
|
+
size?: Size;
|
|
10
|
+
landmark?: boolean;
|
|
11
|
+
sticky?: boolean;
|
|
12
|
+
bare?: boolean;
|
|
13
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
14
|
+
static?: boolean;
|
|
15
|
+
class?: string;
|
|
16
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
heading,
|
|
22
|
+
href,
|
|
23
|
+
size = "md",
|
|
24
|
+
landmark = false,
|
|
25
|
+
sticky = false,
|
|
26
|
+
bare = false,
|
|
27
|
+
static: isStatic = false,
|
|
28
|
+
class: extra,
|
|
29
|
+
...rest
|
|
30
|
+
} = Astro.props;
|
|
31
|
+
|
|
32
|
+
const hasStart = Astro.slots.has("start");
|
|
33
|
+
const hasCenter = Astro.slots.has("center");
|
|
34
|
+
const hasEnd = Astro.slots.has("end");
|
|
35
|
+
|
|
36
|
+
const bindings = {
|
|
37
|
+
heading: heading ?? null,
|
|
38
|
+
href: href ?? null,
|
|
39
|
+
size,
|
|
40
|
+
landmark,
|
|
41
|
+
sticky,
|
|
42
|
+
bare,
|
|
43
|
+
};
|
|
44
|
+
const light = await renderFragmentLight("toolbar", bindings);
|
|
45
|
+
const startHtml = hasStart ? await Astro.slots.render("start") : "";
|
|
46
|
+
const centerHtml = hasCenter ? await Astro.slots.render("center") : "";
|
|
47
|
+
const endHtml = hasEnd ? await Astro.slots.render("end") : "";
|
|
48
|
+
const defaultHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
|
|
49
|
+
const composed = light
|
|
50
|
+
.replace('<slot name="start"></slot>', () => startHtml)
|
|
51
|
+
.replace('<slot name="center"></slot>', () => centerHtml)
|
|
52
|
+
.replace('<slot name="end"></slot>', () => endHtml)
|
|
53
|
+
.replace("<slot></slot>", () => defaultHtml);
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
<xtyle-toolbar
|
|
57
|
+
heading={heading}
|
|
58
|
+
href={href}
|
|
59
|
+
size={size}
|
|
60
|
+
landmark={landmark || undefined}
|
|
61
|
+
sticky={sticky || undefined}
|
|
62
|
+
bare={bare || undefined}
|
|
63
|
+
class={extra}
|
|
64
|
+
set:html={composed}
|
|
65
|
+
{...rest}
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|