@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.
Files changed (68) hide show
  1. package/README.md +42 -0
  2. package/package.json +25 -0
  3. package/src/Accordion.astro +79 -0
  4. package/src/Alert.astro +57 -0
  5. package/src/AppShell.astro +97 -0
  6. package/src/Avatar.astro +71 -0
  7. package/src/AvatarGroup.astro +44 -0
  8. package/src/Badge.astro +73 -0
  9. package/src/Bar.astro +83 -0
  10. package/src/Breadcrumb.astro +54 -0
  11. package/src/Button.astro +91 -0
  12. package/src/Card.astro +44 -0
  13. package/src/CardLink.astro +60 -0
  14. package/src/Carousel.astro +39 -0
  15. package/src/Checkbox.astro +68 -0
  16. package/src/CheckboxGroup.astro +54 -0
  17. package/src/Cluster.astro +46 -0
  18. package/src/Code.astro +42 -0
  19. package/src/ColorPicker.astro +184 -0
  20. package/src/Dialog.astro +69 -0
  21. package/src/Dock.astro +79 -0
  22. package/src/DockZone.astro +17 -0
  23. package/src/Eyebrow.astro +30 -0
  24. package/src/Field.astro +117 -0
  25. package/src/FormGroup.astro +71 -0
  26. package/src/Grid.astro +57 -0
  27. package/src/Heading.astro +34 -0
  28. package/src/Heatmap.astro +116 -0
  29. package/src/Hero.astro +19 -0
  30. package/src/Icon.astro +53 -0
  31. package/src/Image.astro +56 -0
  32. package/src/Kbd.astro +27 -0
  33. package/src/Link.astro +56 -0
  34. package/src/Menu.astro +38 -0
  35. package/src/NumberInput.astro +86 -0
  36. package/src/Pagination.astro +53 -0
  37. package/src/Panel.astro +68 -0
  38. package/src/Parallax.astro +18 -0
  39. package/src/Pie.astro +65 -0
  40. package/src/Progress.astro +96 -0
  41. package/src/Radio.astro +71 -0
  42. package/src/RadioGroup.astro +44 -0
  43. package/src/Section.astro +61 -0
  44. package/src/Segment.astro +15 -0
  45. package/src/Segmented.astro +95 -0
  46. package/src/Select.astro +79 -0
  47. package/src/Separator.astro +36 -0
  48. package/src/Skeleton.astro +25 -0
  49. package/src/Slider.astro +93 -0
  50. package/src/Sparkline.astro +79 -0
  51. package/src/Spinner.astro +37 -0
  52. package/src/Splitter.astro +87 -0
  53. package/src/Stack.astro +42 -0
  54. package/src/Stat.astro +70 -0
  55. package/src/Statusbar.astro +56 -0
  56. package/src/Swatch.astro +69 -0
  57. package/src/Switch.astro +89 -0
  58. package/src/Table.astro +46 -0
  59. package/src/Tabs.astro +94 -0
  60. package/src/Text.astro +54 -0
  61. package/src/Textarea.astro +81 -0
  62. package/src/Toast.astro +62 -0
  63. package/src/ToastRegion.astro +39 -0
  64. package/src/Toc.astro +35 -0
  65. package/src/Toolbar.astro +68 -0
  66. package/src/Tooltip.astro +68 -0
  67. package/src/Tree.astro +78 -0
  68. 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
+ }