@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
package/src/Dock.astro ADDED
@@ -0,0 +1,79 @@
1
+ ---
2
+ import { renderFragmentLight, composeFallbackSlot } from "@xtyle/core/elements/ssr";
3
+
4
+ import type { FullTone as Tone } from "@xtyle/core";
5
+ type DockSide = "left" | "right";
6
+ type Size = "sm" | "md" | "lg";
7
+
8
+ interface Props {
9
+ side?: DockSide;
10
+ size?: Size;
11
+ tone?: Tone;
12
+ reverseEdge?: boolean;
13
+ edgeWidth?: "thin" | "thick" | "bold";
14
+ nav?: boolean;
15
+ label?: string;
16
+ "aria-label"?: string;
17
+ /** Drop the visible `label` header while keeping `label` as the dock's accessible name. */
18
+ hideHeader?: boolean;
19
+ /** Render zero-JS: emit the declarative shadow but never load the runtime to hydrate it. */
20
+ static?: boolean;
21
+ class?: string;
22
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
23
+ [key: string]: unknown;
24
+ }
25
+
26
+ const {
27
+ side = "left",
28
+ size = "md",
29
+ tone,
30
+ reverseEdge = false,
31
+ edgeWidth,
32
+ nav = false,
33
+ label,
34
+ "aria-label": ariaLabel,
35
+ hideHeader = false,
36
+ static: isStatic = false,
37
+ class: extra,
38
+ ...rest
39
+ } = Astro.props;
40
+
41
+ const hasHeader = Astro.slots.has("header");
42
+ const hasFooter = Astro.slots.has("footer");
43
+
44
+ const bindings = {
45
+ side,
46
+ size,
47
+ tone: tone ?? null,
48
+ reverseEdge,
49
+ edgeWidth: edgeWidth ?? null,
50
+ nav,
51
+ label: label ?? null,
52
+ hasAriaLabel: !!ariaLabel,
53
+ hideHeader,
54
+ };
55
+ const light = await renderFragmentLight("dock", bindings);
56
+ const headerHtml = hasHeader ? await Astro.slots.render("header") : null;
57
+ const bodyHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
58
+ const footerHtml = hasFooter ? await Astro.slots.render("footer") : "";
59
+ const composed = composeFallbackSlot(light, "header", headerHtml)
60
+ .replace("<slot></slot>", () => bodyHtml)
61
+ .replace('<slot name="footer"></slot>', () => footerHtml);
62
+ ---
63
+
64
+ <xtyle-dock
65
+ side={side}
66
+ size={size}
67
+ tone={tone}
68
+ reverse-edge={reverseEdge || undefined}
69
+ edge-width={edgeWidth}
70
+ nav={nav || undefined}
71
+ label={label}
72
+ aria-label={ariaLabel}
73
+ hide-header={hideHeader || undefined}
74
+ class={extra}
75
+ set:html={composed}
76
+ {...rest}
77
+ />
78
+
79
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
@@ -0,0 +1,17 @@
1
+ ---
2
+ interface Props {
3
+ class?: string;
4
+ /** Any other attribute (`style`, `id`, `data-*`, `aria-*`, …) passes through to the element. Set a `height` so the workspace has a definite size to fill. */
5
+ [key: string]: unknown;
6
+ }
7
+
8
+ const { class: extra, ...rest } = Astro.props;
9
+ ---
10
+
11
+ <xtyle-dock-zone class:list={[extra]} {...rest}>
12
+ <slot />
13
+ </xtyle-dock-zone>
14
+
15
+ <script>
16
+ import "@xtyle/core/elements";
17
+ </script>
@@ -0,0 +1,30 @@
1
+ ---
2
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
3
+
4
+ type EyebrowTag = "p" | "span" | "div";
5
+ type EyebrowTone = "accent" | "muted" | "subtle";
6
+ type EyebrowTracking = "normal" | "wide";
7
+
8
+ interface Props {
9
+ as?: EyebrowTag;
10
+ tone?: EyebrowTone;
11
+ tracking?: EyebrowTracking;
12
+ /** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
13
+ static?: boolean;
14
+ class?: string;
15
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
16
+ [key: string]: unknown;
17
+ }
18
+
19
+ const { as = "p", tone = "accent", tracking = "normal", static: isStatic = false, class: extra, ...rest } =
20
+ Astro.props;
21
+
22
+ const bindings = { as, tone, tracking };
23
+ const chrome = await renderFragmentLight("eyebrow", bindings);
24
+ const slotHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
25
+ const composed = chrome.replace("<slot></slot>", () => slotHtml);
26
+ ---
27
+
28
+ <xtyle-eyebrow as={as} tone={tone} tracking={tracking} class={extra} set:html={composed} {...rest} />
29
+
30
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
@@ -0,0 +1,117 @@
1
+ ---
2
+ import { renderFragmentLight, composeFallbackSlot } from "@xtyle/core/elements/ssr";
3
+
4
+ type Size = "sm" | "md" | "lg";
5
+
6
+ interface Props {
7
+ label?: string;
8
+ name?: string;
9
+ type?: string;
10
+ placeholder?: string;
11
+ value?: string;
12
+ size?: Size;
13
+ disabled?: boolean;
14
+ readonly?: boolean;
15
+ invalid?: boolean;
16
+ required?: boolean;
17
+ clearable?: boolean;
18
+ description?: string;
19
+ error?: string;
20
+ "aria-label"?: string;
21
+ /** Type-ahead suggestions: `string[]` or `{ value, label }[]`, rendered into the field's `<datalist>`
22
+ * once the element upgrades. Needs the runtime (not `static`), since the datalist is wired on the client. */
23
+ options?: ReadonlyArray<string | { value: string; label?: string }>;
24
+ /** Render the input in the monospace stack for code-shaped values. */
25
+ mono?: boolean;
26
+ /** Render zero-JS: emit the declarative shadow but never load the runtime to hydrate it. */
27
+ static?: boolean;
28
+ class?: string;
29
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
30
+ [key: string]: unknown;
31
+ }
32
+
33
+ const {
34
+ label,
35
+ name,
36
+ type = "text",
37
+ placeholder,
38
+ value,
39
+ size = "md",
40
+ disabled = false,
41
+ readonly = false,
42
+ invalid = false,
43
+ required = false,
44
+ clearable = false,
45
+ description,
46
+ error,
47
+ "aria-label": ariaLabel,
48
+ options,
49
+ mono = false,
50
+ static: isStatic = false,
51
+ class: extra,
52
+ ...rest
53
+ } = Astro.props;
54
+
55
+ const uid = Math.random().toString(36).slice(2, 8);
56
+ const inputId = `xtyle-field-${uid}`;
57
+ const descriptionId = `xtyle-field-desc-${uid}`;
58
+ const errorId = `xtyle-field-error-${uid}`;
59
+
60
+ const hasPrefix = Astro.slots.has("prefix");
61
+ const hasSuffix = Astro.slots.has("suffix");
62
+ const hasRevealIcon = Astro.slots.has("reveal-icon");
63
+ const hasClearIcon = Astro.slots.has("clear-icon");
64
+
65
+ const bindings = {
66
+ label: label ?? null,
67
+ name: name ?? null,
68
+ type,
69
+ placeholder: placeholder ?? null,
70
+ value: value ?? null,
71
+ size,
72
+ disabled,
73
+ readonly,
74
+ invalid,
75
+ required,
76
+ clearable,
77
+ mono,
78
+ description: description ?? null,
79
+ error: error ?? null,
80
+ ariaLabel: ariaLabel ?? null,
81
+ inputId,
82
+ descriptionId,
83
+ errorId,
84
+ };
85
+ const light = await renderFragmentLight("field", bindings);
86
+ const prefixHtml = hasPrefix ? await Astro.slots.render("prefix") : "";
87
+ const suffixHtml = hasSuffix ? await Astro.slots.render("suffix") : "";
88
+ const revealHtml = hasRevealIcon ? await Astro.slots.render("reveal-icon") : null;
89
+ const clearHtml = hasClearIcon ? await Astro.slots.render("clear-icon") : null;
90
+ const composed = composeFallbackSlot(composeFallbackSlot(light, "reveal-icon", revealHtml), "clear-icon", clearHtml)
91
+ .replace('<slot name="prefix"></slot>', () => prefixHtml)
92
+ .replace('<slot name="suffix"></slot>', () => suffixHtml);
93
+ ---
94
+
95
+ <xtyle-field
96
+ label={label}
97
+ name={name}
98
+ type={type}
99
+ placeholder={placeholder}
100
+ value={value}
101
+ size={size}
102
+ disabled={disabled || undefined}
103
+ readonly={readonly || undefined}
104
+ invalid={invalid || undefined}
105
+ required={required || undefined}
106
+ clearable={clearable || undefined}
107
+ mono={mono || undefined}
108
+ description={description}
109
+ error={error}
110
+ aria-label={ariaLabel}
111
+ options={options ? JSON.stringify(options) : undefined}
112
+ class={extra}
113
+ set:html={composed}
114
+ {...rest}
115
+ />
116
+
117
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
@@ -0,0 +1,71 @@
1
+ ---
2
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
3
+
4
+ type Size = "sm" | "md" | "lg";
5
+
6
+ interface Props {
7
+ label?: string;
8
+ description?: string;
9
+ error?: string;
10
+ size?: Size;
11
+ invalid?: boolean;
12
+ required?: boolean;
13
+ for?: string;
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
+ label = "",
23
+ description = "",
24
+ error = "",
25
+ size = "md",
26
+ invalid = false,
27
+ required = false,
28
+ for: htmlFor,
29
+ static: isStatic = false,
30
+ class: extra,
31
+ ...rest
32
+ } = Astro.props;
33
+
34
+ const seed = Math.random().toString(36).slice(2, 9);
35
+ const labelId = `xtyle-form-group-label-${seed}`;
36
+ const descriptionId = `xtyle-form-group-desc-${seed}`;
37
+ const errorId = `xtyle-form-group-error-${seed}`;
38
+ const controlId = `xtyle-form-group-control-${seed}`;
39
+
40
+ const bindings = {
41
+ label,
42
+ description,
43
+ error,
44
+ size,
45
+ invalid,
46
+ required,
47
+ hasFor: htmlFor != null,
48
+ controlTarget: htmlFor ?? controlId,
49
+ labelId,
50
+ descriptionId,
51
+ errorId,
52
+ };
53
+ const chrome = await renderFragmentLight("form-group", bindings);
54
+ const slotHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
55
+ const composed = chrome.replace("<slot></slot>", () => slotHtml);
56
+ ---
57
+
58
+ <xtyle-form-group
59
+ label={label}
60
+ description={description}
61
+ error={error}
62
+ size={size}
63
+ invalid={invalid || undefined}
64
+ required={required || undefined}
65
+ for={htmlFor}
66
+ class={extra}
67
+ set:html={composed}
68
+ {...rest}
69
+ />
70
+
71
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
package/src/Grid.astro ADDED
@@ -0,0 +1,57 @@
1
+ ---
2
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
3
+
4
+ type GridAlign = "start" | "center" | "end" | "stretch";
5
+
6
+ interface Props {
7
+ gap?: number;
8
+ columns?: number;
9
+ minColWidth?: string;
10
+ align?: GridAlign;
11
+ justify?: GridAlign;
12
+ inline?: 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
+ gap = 4,
22
+ columns,
23
+ minColWidth,
24
+ align,
25
+ justify,
26
+ inline = false,
27
+ static: isStatic = false,
28
+ class: extra,
29
+ ...rest
30
+ } = Astro.props;
31
+
32
+ const bindings = {
33
+ gap,
34
+ columns: columns ?? null,
35
+ minColWidth: minColWidth ?? null,
36
+ align: align ?? null,
37
+ justify: justify ?? null,
38
+ inline,
39
+ };
40
+ const chrome = await renderFragmentLight("grid", bindings);
41
+ const slotHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
42
+ const composed = chrome.replace("<slot></slot>", () => slotHtml);
43
+ ---
44
+
45
+ <xtyle-grid
46
+ gap={gap}
47
+ columns={columns ?? undefined}
48
+ min-col-width={minColWidth ?? undefined}
49
+ align={align ?? undefined}
50
+ justify={justify ?? undefined}
51
+ inline={inline || undefined}
52
+ class={extra}
53
+ set:html={composed}
54
+ {...rest}
55
+ />
56
+
57
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
@@ -0,0 +1,34 @@
1
+ ---
2
+ import { headingSizeForLevel } from "@xtyle/core";
3
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
4
+ import type { HeadingLevel, HeadingSize, HeadingTone } from "@xtyle/core";
5
+
6
+ interface Props {
7
+ level?: HeadingLevel;
8
+ size?: HeadingSize;
9
+ tone?: HeadingTone;
10
+ /** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
11
+ static?: boolean;
12
+ class?: string;
13
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ const { level = 2, size, tone = "default", static: isStatic = false, class: extra, ...rest } =
18
+ Astro.props;
19
+
20
+ const resolvedSize = size ?? headingSizeForLevel(level);
21
+
22
+ const bindings = {
23
+ level,
24
+ size: resolvedSize,
25
+ tone,
26
+ };
27
+ const chrome = await renderFragmentLight("heading", bindings);
28
+ const slotHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
29
+ const composed = chrome.replace("<slot></slot>", () => slotHtml);
30
+ ---
31
+
32
+ <xtyle-heading level={level} size={resolvedSize} tone={tone} class={extra} set:html={composed} {...rest} />
33
+
34
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
@@ -0,0 +1,116 @@
1
+ ---
2
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
3
+ import { resolveHeatmapColors, resolveHeatmapGlows, resolveHeatmapScale } from "./internal/palette.ts";
4
+ import type { HeatmapScheme } from "@xtyle/core";
5
+
6
+ interface Props {
7
+ values?: number[][];
8
+ /** A second intensity matrix (same shape as `values`) driving each cell's glow halo. */
9
+ glow?: number[][];
10
+ rows?: string[];
11
+ cols?: string[];
12
+ scheme?: HeatmapScheme;
13
+ reverse?: boolean;
14
+ max?: number;
15
+ /** The glow-channel ceiling a full-strength halo maps to; defaults to the glow data's own max. */
16
+ glowMax?: number;
17
+ /** The px blur a full-strength glow halo reaches; defaults to 7. Lower it on a dense grid, raise it on a sparse one. */
18
+ glowBlur?: number;
19
+ /** Names the glow metric so its value reaches each cell's accessible name and readout; defaults to "glow". */
20
+ glowLabel?: string;
21
+ /** Cells to ring as the current / "now" marker, each a `[rowIndex, colIndex]` pair. */
22
+ current?: number[][];
23
+ /** Tint for the current-cell ring: a semantic tone (`success` / `danger` / `warn` / `info` / `neutral`); defaults to accent. */
24
+ currentTone?: "success" | "danger" | "warn" | "info" | "neutral";
25
+ /** Pulse the current-cell ring (honors `prefers-reduced-motion`). */
26
+ currentPulse?: boolean;
27
+ /** Per-cell hover text (same shape as `values`); overrides a cell's default readout and accessible name. */
28
+ titles?: string[][];
29
+ /** Show a color-scale key (five swatches from the ramp with 0..max endpoints) below the grid. */
30
+ scale?: boolean;
31
+ showValues?: boolean;
32
+ /** Make cells actionable: each becomes a `role="button"` that fires `select` on click or Enter/Space. */
33
+ selectable?: boolean;
34
+ label?: string;
35
+ /** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
36
+ static?: boolean;
37
+ class?: string;
38
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
39
+ [key: string]: unknown;
40
+ }
41
+
42
+ const {
43
+ values = [],
44
+ glow = [],
45
+ rows = [],
46
+ cols = [],
47
+ scheme = "accent",
48
+ reverse = false,
49
+ max,
50
+ glowMax,
51
+ glowBlur,
52
+ glowLabel,
53
+ current = [],
54
+ currentTone,
55
+ currentPulse = false,
56
+ titles = [],
57
+ scale = false,
58
+ showValues = false,
59
+ selectable = false,
60
+ label,
61
+ static: isStatic = false,
62
+ class: extra,
63
+ ...rest
64
+ } = Astro.props;
65
+
66
+ const cellColors = await resolveHeatmapColors(scheme, values, reverse, max);
67
+ const cellGlows = await resolveHeatmapGlows(scheme, glow, reverse, glowMax, glowBlur);
68
+ const resolvedGlowLabel = glow.length ? (glowLabel ?? "glow") : null;
69
+ const scaleKey = scale ? await resolveHeatmapScale(scheme, values, reverse, max) : null;
70
+ const bindings = {
71
+ values,
72
+ rows,
73
+ cols,
74
+ cellColors,
75
+ cellGlows,
76
+ glowValues: glow,
77
+ glowLabel: resolvedGlowLabel,
78
+ current,
79
+ currentTone: currentTone ?? null,
80
+ currentPulse,
81
+ titles,
82
+ scale,
83
+ ...(scaleKey ?? {}),
84
+ showValues,
85
+ selectable,
86
+ title: label ?? null,
87
+ ariaLabel: label ?? null,
88
+ };
89
+ const chrome = await renderFragmentLight("heatmap", bindings);
90
+ ---
91
+
92
+ <xtyle-heatmap
93
+ values={JSON.stringify(values)}
94
+ glow={glow.length ? JSON.stringify(glow) : undefined}
95
+ rows={JSON.stringify(rows)}
96
+ cols={JSON.stringify(cols)}
97
+ current={current.length ? JSON.stringify(current) : undefined}
98
+ titles={titles.length ? JSON.stringify(titles) : undefined}
99
+ scheme={Array.isArray(scheme) ? JSON.stringify(scheme) : scheme}
100
+ reverse={reverse || undefined}
101
+ max={max ?? undefined}
102
+ glow-max={glowMax ?? undefined}
103
+ glow-blur={glowBlur ?? undefined}
104
+ glow-label={glowLabel ?? undefined}
105
+ current-tone={currentTone ?? undefined}
106
+ current-pulse={currentPulse || undefined}
107
+ scale={scale || undefined}
108
+ show-values={showValues || undefined}
109
+ selectable={selectable || undefined}
110
+ label={label}
111
+ class={extra}
112
+ set:html={chrome}
113
+ {...rest}
114
+ />
115
+
116
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
package/src/Hero.astro ADDED
@@ -0,0 +1,19 @@
1
+ ---
2
+ type HeroAlign = "center" | "start";
3
+
4
+ interface Props {
5
+ align?: HeroAlign;
6
+ split?: boolean;
7
+ class?: string;
8
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
9
+ [key: string]: unknown;
10
+ }
11
+
12
+ const { align = "center", split = false, class: extra, ...rest } = Astro.props;
13
+ ---
14
+
15
+ <xtyle-hero align={align !== "center" ? align : undefined} split={split ? "" : undefined} class={extra} {...rest}>
16
+ <slot />
17
+ </xtyle-hero>
18
+
19
+ <script>import "@xtyle/core/elements";</script>
package/src/Icon.astro ADDED
@@ -0,0 +1,53 @@
1
+ ---
2
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
3
+ import { bakeIconMark } from "./internal/palette.ts";
4
+ import { ICON_NAMES, iconClass } from "@xtyle/core";
5
+ import type { FullTone, IconName, IconSize, SeriesScheme } from "@xtyle/core";
6
+
7
+ interface Props {
8
+ name: IconName | (string & {});
9
+ size?: IconSize;
10
+ tone?: FullTone;
11
+ /** The series scheme a generated mark's `c3+` color slots draw from. */
12
+ colors?: SeriesScheme;
13
+ label?: string;
14
+ spin?: 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
+ name,
24
+ size = "md",
25
+ tone,
26
+ colors = "accents",
27
+ label,
28
+ spin = false,
29
+ static: isStatic = false,
30
+ class: extra,
31
+ ...rest
32
+ } = Astro.props;
33
+
34
+ // A functional glyph is looked up; any other name is offered to the mark generators and baked when one claims it.
35
+ const isGlyph = typeof name !== "string" || (ICON_NAMES as readonly string[]).includes(name);
36
+ const mark = isGlyph ? null : await bakeIconMark(name, colors, iconClass({ size, tone, spin }));
37
+ const composed =
38
+ mark != null ? `<span data-root data-icon>${mark}</span>` : await renderFragmentLight("icon", { name, size, tone, label, spin });
39
+ ---
40
+
41
+ <xtyle-icon
42
+ name={name}
43
+ size={size}
44
+ tone={tone}
45
+ colors={mark != null ? colors : undefined}
46
+ label={label}
47
+ spin={spin ? "" : undefined}
48
+ class={extra}
49
+ set:html={composed}
50
+ {...rest}
51
+ />
52
+
53
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
@@ -0,0 +1,56 @@
1
+ ---
2
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
3
+
4
+ type ImageFit = "cover" | "contain";
5
+ type ImageRadius = "none" | "sm" | "md" | "lg";
6
+ type ImageLoading = "lazy" | "eager";
7
+
8
+ interface Props {
9
+ src?: string;
10
+ alt?: string;
11
+ ratio?: string;
12
+ fit?: ImageFit;
13
+ radius?: ImageRadius;
14
+ loading?: ImageLoading;
15
+ lightbox?: boolean;
16
+ caption?: 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
+ src,
26
+ alt = "",
27
+ ratio,
28
+ fit = "cover",
29
+ radius = "md",
30
+ loading = "lazy",
31
+ lightbox = false,
32
+ caption,
33
+ static: isStatic = false,
34
+ class: extra,
35
+ ...rest
36
+ } = Astro.props;
37
+
38
+ const bindings = { src, alt, ratio, fit, radius, loading, caption };
39
+ const composed = await renderFragmentLight("image", bindings);
40
+ ---
41
+
42
+ <xtyle-image
43
+ src={src}
44
+ alt={alt}
45
+ ratio={ratio}
46
+ fit={fit}
47
+ radius={radius}
48
+ loading={loading}
49
+ caption={caption}
50
+ lightbox={lightbox ? "" : undefined}
51
+ class={extra}
52
+ set:html={composed}
53
+ {...rest}
54
+ />
55
+
56
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}
package/src/Kbd.astro ADDED
@@ -0,0 +1,27 @@
1
+ ---
2
+ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
3
+
4
+ import type { FullTone as KbdTone } from "@xtyle/core";
5
+ type KbdSize = "sm" | "md" | "lg";
6
+
7
+ interface Props {
8
+ size?: KbdSize;
9
+ tone?: KbdTone;
10
+ /** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
11
+ static?: boolean;
12
+ class?: string;
13
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ const { size = "md", tone, static: isStatic = false, class: extra, ...rest } = Astro.props;
18
+
19
+ const bindings = { size, tone };
20
+ const chrome = await renderFragmentLight("kbd", bindings);
21
+ const slotHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
22
+ const composed = chrome.replace("<slot></slot>", () => slotHtml);
23
+ ---
24
+
25
+ <xtyle-kbd size={size} tone={tone} class={extra} set:html={composed} {...rest} />
26
+
27
+ {!isStatic && <script>import "@xtyle/core/elements";</script>}