@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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
3
|
+
|
|
4
|
+
type Placement = "top" | "bottom" | "left" | "right";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
text?: string;
|
|
8
|
+
placement?: Placement;
|
|
9
|
+
open?: boolean;
|
|
10
|
+
tone?: string;
|
|
11
|
+
variant?: "soft" | "solid";
|
|
12
|
+
mode?: "hint" | "rich";
|
|
13
|
+
size?: "sm" | "md";
|
|
14
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
15
|
+
static?: boolean;
|
|
16
|
+
class?: string;
|
|
17
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
text,
|
|
23
|
+
placement = "top",
|
|
24
|
+
open = false,
|
|
25
|
+
tone,
|
|
26
|
+
variant,
|
|
27
|
+
mode,
|
|
28
|
+
size,
|
|
29
|
+
static: isStatic = false,
|
|
30
|
+
class: extra,
|
|
31
|
+
...rest
|
|
32
|
+
} = Astro.props;
|
|
33
|
+
|
|
34
|
+
const hasContent = Astro.slots.has("content");
|
|
35
|
+
const contentId = `xtyle-tooltip-${Math.random().toString(36).slice(2, 8)}`;
|
|
36
|
+
|
|
37
|
+
const bindings = {
|
|
38
|
+
text: text ?? null,
|
|
39
|
+
placement,
|
|
40
|
+
contentId,
|
|
41
|
+
open,
|
|
42
|
+
tone: tone ?? null,
|
|
43
|
+
variant: variant ?? null,
|
|
44
|
+
mode: mode ?? null,
|
|
45
|
+
size: size ?? null,
|
|
46
|
+
};
|
|
47
|
+
const light = await renderFragmentLight("tooltip", bindings);
|
|
48
|
+
const triggerHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
|
|
49
|
+
const contentHtml = hasContent ? await Astro.slots.render("content") : "";
|
|
50
|
+
const composed = light
|
|
51
|
+
.replace('<slot name="content"></slot>', () => contentHtml)
|
|
52
|
+
.replace("<slot></slot>", () => triggerHtml);
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
<xtyle-tooltip
|
|
56
|
+
text={text}
|
|
57
|
+
placement={placement}
|
|
58
|
+
open={open || undefined}
|
|
59
|
+
tone={tone}
|
|
60
|
+
variant={variant}
|
|
61
|
+
mode={mode}
|
|
62
|
+
size={size}
|
|
63
|
+
class={extra}
|
|
64
|
+
set:html={composed}
|
|
65
|
+
{...rest}
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
package/src/Tree.astro
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { firstSelectedValue } from "@xtyle/core/markup";
|
|
3
|
+
import { renderFragmentLight } from "@xtyle/core/elements/ssr";
|
|
4
|
+
|
|
5
|
+
type Size = "sm" | "md" | "lg";
|
|
6
|
+
|
|
7
|
+
interface TreeNode {
|
|
8
|
+
label: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
href?: string;
|
|
11
|
+
expanded?: boolean;
|
|
12
|
+
locked?: boolean;
|
|
13
|
+
selected?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
badge?: string;
|
|
16
|
+
children?: TreeNode[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
items?: TreeNode[];
|
|
21
|
+
size?: Size;
|
|
22
|
+
label?: string;
|
|
23
|
+
labelledby?: string;
|
|
24
|
+
/** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
|
|
25
|
+
static?: boolean;
|
|
26
|
+
class?: string;
|
|
27
|
+
/** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
items = [],
|
|
33
|
+
size = "md",
|
|
34
|
+
label,
|
|
35
|
+
labelledby,
|
|
36
|
+
static: isStatic = false,
|
|
37
|
+
class: extra,
|
|
38
|
+
...rest
|
|
39
|
+
} = Astro.props;
|
|
40
|
+
|
|
41
|
+
const nodeKey = (node: TreeNode): string => node.value ?? node.label;
|
|
42
|
+
const hasChildren = (node: TreeNode): boolean => !!(node.children && node.children.length);
|
|
43
|
+
|
|
44
|
+
const expandedKeys: string[] = [];
|
|
45
|
+
const seedExpanded = (nodes: TreeNode[]): void => {
|
|
46
|
+
for (const node of nodes) {
|
|
47
|
+
if (hasChildren(node)) {
|
|
48
|
+
const locked = (node.locked ?? false) && hasChildren(node);
|
|
49
|
+
if (locked || node.expanded) expandedKeys.push(nodeKey(node));
|
|
50
|
+
seedExpanded(node.children as TreeNode[]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
seedExpanded(items);
|
|
55
|
+
|
|
56
|
+
const bindings = {
|
|
57
|
+
items,
|
|
58
|
+
size,
|
|
59
|
+
label: label ?? null,
|
|
60
|
+
labelledby: labelledby ?? null,
|
|
61
|
+
selectedValue: firstSelectedValue(items),
|
|
62
|
+
expandedKeys,
|
|
63
|
+
rovingValue: null,
|
|
64
|
+
};
|
|
65
|
+
const light = await renderFragmentLight("tree", bindings);
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
<xtyle-tree
|
|
69
|
+
items={items ? JSON.stringify(items) : undefined}
|
|
70
|
+
size={size}
|
|
71
|
+
label={label}
|
|
72
|
+
labelledby={labelledby}
|
|
73
|
+
class={extra}
|
|
74
|
+
{...rest}
|
|
75
|
+
set:html={light}
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
{!isStatic && <script>import "@xtyle/core/elements";</script>}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { derive, seriesPalette, seriesColorsFor, rampColor, glowFilter, resolveIconMark, composeIconThemed, type SeriesScheme, type RampScheme } from "@xtyle/core";
|
|
2
|
+
import { resolveAlgorithm } from "@xtyle/core/host";
|
|
3
|
+
|
|
4
|
+
function matrixCeiling(matrix: number[][], explicit?: number): number {
|
|
5
|
+
if (explicit && explicit > 0) return explicit;
|
|
6
|
+
return Math.max(1, ...matrix.flatMap((row) => row.map((v) => (Number.isFinite(v) ? v : 0))));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Baking colors at build time needs a register; the runtime theme isn't known yet, so SSR uses the
|
|
10
|
+
* default one and the upgraded element re-resolves against the live cascade. Memoized per build. */
|
|
11
|
+
let cached: Promise<Record<string, string>> | null = null;
|
|
12
|
+
async function defaultRegister(): Promise<Record<string, string>> {
|
|
13
|
+
cached ??= (async () => derive(await resolveAlgorithm("xtyle-default"), {}))();
|
|
14
|
+
return cached;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Bakes a generated icon mark for SSR: series slots resolve against the default register while
|
|
18
|
+
* token fills stay `var(--…)`, so a static (un-hydrated) mark still recolors with the theme and the
|
|
19
|
+
* upgraded element re-resolves its series off the live cascade. Returns null for a non-spec name. */
|
|
20
|
+
export async function bakeIconMark(
|
|
21
|
+
name: string,
|
|
22
|
+
scheme: SeriesScheme | string[],
|
|
23
|
+
className?: string,
|
|
24
|
+
): Promise<string | null> {
|
|
25
|
+
const parsed = resolveIconMark(name);
|
|
26
|
+
if (!parsed) return null;
|
|
27
|
+
return composeIconThemed(parsed.composition, { register: await defaultRegister(), scheme, className, part: "icon" });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function resolveSeriesColors(
|
|
31
|
+
scheme: SeriesScheme | string[],
|
|
32
|
+
count: number,
|
|
33
|
+
reverse: boolean,
|
|
34
|
+
): Promise<string[]> {
|
|
35
|
+
if (Array.isArray(scheme)) return seriesPalette(scheme, count, {}, { reverse });
|
|
36
|
+
return seriesPalette(scheme, count, await defaultRegister(), { reverse });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The by-name companion to `resolveSeriesColors` for SSR: a per-item resolver that honors each
|
|
40
|
+
* item's semantic `tone` under the `statuses` scheme, so a static outcome chart pins by meaning even
|
|
41
|
+
* when a zero-value category is filtered out. Positional for every other scheme. */
|
|
42
|
+
export async function resolveSeriesColorsFor(
|
|
43
|
+
scheme: SeriesScheme | string[],
|
|
44
|
+
items: readonly { tone?: string }[],
|
|
45
|
+
reverse: boolean,
|
|
46
|
+
): Promise<string[]> {
|
|
47
|
+
if (Array.isArray(scheme)) return seriesColorsFor(scheme, items, {}, { reverse });
|
|
48
|
+
return seriesColorsFor(scheme, items, await defaultRegister(), { reverse });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Bakes each cell's intensity color against the default register for the zero-JS SSR grid; the
|
|
52
|
+
* upgraded element re-resolves against the live cascade. */
|
|
53
|
+
export async function resolveHeatmapColors(
|
|
54
|
+
scheme: RampScheme | string[],
|
|
55
|
+
values: number[][],
|
|
56
|
+
reverse: boolean,
|
|
57
|
+
max?: number,
|
|
58
|
+
): Promise<string[][]> {
|
|
59
|
+
const register = Array.isArray(scheme) ? {} : await defaultRegister();
|
|
60
|
+
const ceiling = matrixCeiling(values, max);
|
|
61
|
+
return values.map((row) => row.map((v) => rampColor(scheme, (Number.isFinite(v) ? v : 0) / ceiling, register, { reverse })));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Bakes each cell's secondary-glow drop-shadow against the default register for the zero-JS SSR
|
|
65
|
+
* grid; the upgraded element re-resolves against the live cascade. */
|
|
66
|
+
export async function resolveHeatmapGlows(
|
|
67
|
+
scheme: RampScheme | string[],
|
|
68
|
+
glow: number[][],
|
|
69
|
+
reverse: boolean,
|
|
70
|
+
glowMax?: number,
|
|
71
|
+
glowBlur?: number,
|
|
72
|
+
): Promise<(string | null)[][]> {
|
|
73
|
+
if (!glow.length) return [];
|
|
74
|
+
const register = Array.isArray(scheme) ? {} : await defaultRegister();
|
|
75
|
+
const color = rampColor(scheme, 1, register, { reverse });
|
|
76
|
+
const ceiling = matrixCeiling(glow, glowMax);
|
|
77
|
+
const maxBlur = glowBlur && glowBlur > 0 ? glowBlur : undefined;
|
|
78
|
+
return glow.map((row) => row.map((v) => glowFilter((Number.isFinite(v) ? v : 0) / ceiling, color, maxBlur)));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Bakes the scale key against the default register for SSR; the upgraded element re-resolves against
|
|
82
|
+
* the live cascade. */
|
|
83
|
+
export async function resolveHeatmapScale(
|
|
84
|
+
scheme: RampScheme | string[],
|
|
85
|
+
values: number[][],
|
|
86
|
+
reverse: boolean,
|
|
87
|
+
max?: number,
|
|
88
|
+
): Promise<{ scaleColors: string[]; scaleLow: number; scaleHigh: number }> {
|
|
89
|
+
const register = Array.isArray(scheme) ? {} : await defaultRegister();
|
|
90
|
+
const scaleColors = [0, 0.25, 0.5, 0.75, 1].map((t) => rampColor(scheme, t, register, { reverse }));
|
|
91
|
+
return { scaleColors, scaleLow: 0, scaleHigh: matrixCeiling(values, max) };
|
|
92
|
+
}
|