@xtyle/astro 0.5.0 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtyle/astro",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Zero-JS Astro components that emit semantic HTML against the xtyle component classes; the SSR binding of the component contract.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -12,7 +12,7 @@
12
12
  "README.md"
13
13
  ],
14
14
  "dependencies": {
15
- "@xtyle/core": "^0.5.0"
15
+ "@xtyle/core": "^0.6.0"
16
16
  },
17
17
  "peerDependencies": {
18
18
  "astro": "^6.0.0"
package/src/Card.astro CHANGED
@@ -9,6 +9,8 @@ interface Props {
9
9
  action?: boolean;
10
10
  compact?: boolean;
11
11
  tone?: Tone;
12
+ /** How far the surface lifts: `sm` a whisper, `md` the eased default, `lg` a pronounced shadow. */
13
+ depthStrength?: "sm" | "md" | "lg";
12
14
  /** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
13
15
  static?: boolean;
14
16
  class?: string;
@@ -16,10 +18,10 @@ interface Props {
16
18
  [key: string]: unknown;
17
19
  }
18
20
 
19
- const { overlay = false, interactive = false, action = false, compact = false, tone, static: isStatic = false, class: extra, ...rest } =
21
+ const { overlay = false, interactive = false, action = false, compact = false, tone, depthStrength, static: isStatic = false, class: extra, ...rest } =
20
22
  Astro.props;
21
23
 
22
- const bindings = { overlay, interactive, action, compact, tone: tone ?? null };
24
+ const bindings = { overlay, interactive, action, compact, tone: tone ?? null, depthStrength: depthStrength ?? null };
23
25
  const chrome = await renderFragmentLight("card", bindings);
24
26
  const headerHtml = Astro.slots.has("header") ? await Astro.slots.render("header") : "";
25
27
  const bodyHtml = Astro.slots.has("default") ? await Astro.slots.render("default") : "";
@@ -36,6 +38,7 @@ const composed = chrome
36
38
  action={action || undefined}
37
39
  compact={compact || undefined}
38
40
  tone={tone}
41
+ depth-strength={depthStrength}
39
42
  class={extra}
40
43
  set:html={composed}
41
44
  {...rest}
@@ -0,0 +1,17 @@
1
+ ---
2
+ interface Props {
3
+ class?: string;
4
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
5
+ [key: string]: unknown;
6
+ }
7
+
8
+ const { class: extra, ...rest } = Astro.props;
9
+ ---
10
+
11
+ <xtyle-empty class:list={["xtyle-empty", extra]} {...rest}>
12
+ <slot />
13
+ </xtyle-empty>
14
+
15
+ <script>
16
+ import "@xtyle/core/elements";
17
+ </script>
package/src/Image.astro CHANGED
@@ -4,6 +4,7 @@ import { renderFragmentLight } from "@xtyle/core/elements/ssr";
4
4
  type ImageFit = "cover" | "contain";
5
5
  type ImageRadius = "none" | "sm" | "md" | "lg";
6
6
  type ImageLoading = "lazy" | "eager";
7
+ type ImageTrigger = "frame" | "button";
7
8
 
8
9
  interface Props {
9
10
  src?: string;
@@ -13,6 +14,7 @@ interface Props {
13
14
  radius?: ImageRadius;
14
15
  loading?: ImageLoading;
15
16
  lightbox?: boolean;
17
+ trigger?: ImageTrigger;
16
18
  caption?: string;
17
19
  /** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
18
20
  static?: boolean;
@@ -29,6 +31,7 @@ const {
29
31
  radius = "md",
30
32
  loading = "lazy",
31
33
  lightbox = false,
34
+ trigger = "frame",
32
35
  caption,
33
36
  static: isStatic = false,
34
37
  class: extra,
@@ -48,6 +51,7 @@ const composed = await renderFragmentLight("image", bindings);
48
51
  loading={loading}
49
52
  caption={caption}
50
53
  lightbox={lightbox ? "" : undefined}
54
+ trigger={trigger === "button" ? "button" : undefined}
51
55
  class={extra}
52
56
  set:html={composed}
53
57
  {...rest}
@@ -1,9 +1,10 @@
1
1
  ---
2
2
  import { renderFragmentLight, composeFallbackSlot } from "@xtyle/core/elements/ssr";
3
3
 
4
- import type { FullTone as Tone } from "@xtyle/core";
4
+ import { rampGradientStops, type FullTone as Tone, type RampScheme } from "@xtyle/core";
5
5
  type ProgressVariant = "linear" | "circular";
6
6
  type ProgressSize = "sm" | "md" | "lg";
7
+ type ProgressRampMode = "solid" | "gradient";
7
8
 
8
9
  interface Props {
9
10
  variant?: ProgressVariant;
@@ -16,12 +17,22 @@ interface Props {
16
17
  showValue?: boolean;
17
18
  /** How `showValue` renders the readout: `percent` (33%), `value` (123), or `value-max` (123/456). */
18
19
  valueFormat?: "percent" | "value" | "value-max";
20
+ /** A unit appended to the `value` / `value-max` readout (e.g. `GB`); the `percent` format ignores it. */
21
+ unit?: string;
19
22
  /** Tint the readout with the active tone instead of the muted default. */
20
23
  colorizeValue?: boolean;
21
24
  /** `end` (after the bar) or `inset` (centered in the track, contrast-flipping as the fill crosses). */
22
25
  valuePosition?: "end" | "inset";
23
26
  /** Report `role="meter"` (a capacity measurement) instead of `role="progressbar"` (a task). */
24
27
  meter?: boolean;
28
+ /** Color the fill by its own value along a ramp instead of a flat `tone`: a built-in scheme
29
+ * (`accent` / `thermal` / `status`) or an explicit list of stop colors. */
30
+ ramp?: RampScheme | string[];
31
+ /** How a `ramp` paints: `solid` (one sampled color, needs the runtime) or `gradient` (a pure-CSS
32
+ * sweep, zero-JS, linear only). Defaults to `solid`. */
33
+ rampMode?: ProgressRampMode;
34
+ /** Flip the ramp end for end (hot-to-cold). */
35
+ reverse?: boolean;
25
36
  "aria-label"?: string;
26
37
  /** Render zero-JS: emit the resolved light-DOM markup but never load the runtime to hydrate it. */
27
38
  static?: boolean;
@@ -40,15 +51,28 @@ const {
40
51
  indeterminate = false,
41
52
  showValue = false,
42
53
  valueFormat = "percent",
54
+ unit,
43
55
  colorizeValue = false,
44
56
  valuePosition = "end",
45
57
  meter = false,
58
+ ramp,
59
+ rampMode = "solid",
60
+ reverse = false,
46
61
  "aria-label": ariaLabel,
47
62
  static: isStatic = false,
48
63
  class: extra,
49
64
  ...rest
50
65
  } = Astro.props;
51
66
 
67
+ // Gradient ramps are pure CSS (var()-referenced stops), so they render server-side with zero JS;
68
+ // a solid ramp's color is sampled off the live cascade, so SSR leaves the tone and the runtime paints it.
69
+ const gradientRamp = ramp && rampMode === "gradient" && variant !== "circular";
70
+ const rampBindings = ramp
71
+ ? gradientRamp
72
+ ? { ramp: true, rampMode: "gradient", rampStops: rampGradientStops(ramp, { reverse }) }
73
+ : { ramp: true, rampMode: "solid" }
74
+ : {};
75
+
52
76
  const bindings = {
53
77
  variant,
54
78
  tone,
@@ -59,12 +83,14 @@ const bindings = {
59
83
  indeterminate,
60
84
  showValue,
61
85
  valueFormat,
86
+ unit,
62
87
  colorizeValue,
63
88
  valuePosition,
64
89
  pulse: null,
65
90
  role: meter ? "meter" : "progressbar",
66
91
  ariaLabel: ariaLabel ?? null,
67
92
  ariaLabelledby: null,
93
+ ...rampBindings,
68
94
  };
69
95
  const light = await renderFragmentLight("progress", bindings);
70
96
  const valueHtml = Astro.slots.has("value") ? await Astro.slots.render("value") : null;
@@ -84,9 +110,13 @@ const composed = composeFallbackSlot(light, "value", valueHtml) + thresholdHtml;
84
110
  indeterminate={indeterminate || undefined}
85
111
  show-value={showValue || undefined}
86
112
  value-format={valueFormat !== "percent" ? valueFormat : undefined}
113
+ unit={unit || undefined}
87
114
  colorize-value={colorizeValue || undefined}
88
115
  value-position={valuePosition !== "end" ? valuePosition : undefined}
89
116
  meter={meter || undefined}
117
+ ramp={ramp ? (Array.isArray(ramp) ? JSON.stringify(ramp) : ramp) : undefined}
118
+ ramp-mode={ramp && rampMode !== "solid" ? rampMode : undefined}
119
+ reverse={reverse || undefined}
90
120
  aria-label={ariaLabel}
91
121
  class={extra}
92
122
  set:html={composed}
@@ -0,0 +1,44 @@
1
+ ---
2
+ interface Props {
3
+ value?: number;
4
+ max?: number;
5
+ size?: "sm" | "md" | "lg";
6
+ /** The icon to rate with: `star` (default), any functional glyph, or a mark spec (`taco--…`). */
7
+ icon?: string;
8
+ /** Read-only display (fixed, fractional). Omit for an interactive slider (focusable, click / keys). */
9
+ readonly?: boolean;
10
+ /** Snap interactive input to half steps. */
11
+ allowHalf?: boolean;
12
+ /** The series scheme a colorful mark draws its palette from. */
13
+ colors?: string;
14
+ /** Fill tone for a monochrome icon: a register hue (`accent`, `success`, `red`, …). */
15
+ tone?: string;
16
+ /** Form field name; when set, the value posts through a hidden input. */
17
+ name?: string;
18
+ /** Accessible label (also the no-JS fallback text). */
19
+ label?: string;
20
+ class?: string;
21
+ /** Any other attribute (`id`, `title`, `data-*`, …) passes through to the element. */
22
+ [key: string]: unknown;
23
+ }
24
+
25
+ const { value = 0, max = 5, size, icon, readonly, allowHalf, colors, tone, name, label, class: extra, ...rest } = Astro.props;
26
+ ---
27
+
28
+ <xtyle-rating
29
+ value={value}
30
+ max={max}
31
+ size={size}
32
+ icon={icon}
33
+ colors={colors}
34
+ tone={tone}
35
+ name={name}
36
+ readonly={readonly ? "" : undefined}
37
+ allowhalf={allowHalf ? "" : undefined}
38
+ label={label}
39
+ class:list={["xtyle-rating", extra]}
40
+ {...rest}>{label ?? `${value} out of ${max} stars`}</xtyle-rating>
41
+
42
+ <script>
43
+ import "@xtyle/core/elements";
44
+ </script>
@@ -0,0 +1,19 @@
1
+ ---
2
+ interface Props {
3
+ /** Zero-based index of the current step. */
4
+ current?: number;
5
+ class?: string;
6
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
7
+ [key: string]: unknown;
8
+ }
9
+
10
+ const { current = 0, class: extra, ...rest } = Astro.props;
11
+ ---
12
+
13
+ <xtyle-steps current={current} class:list={["xtyle-steps", extra]} {...rest}>
14
+ <slot />
15
+ </xtyle-steps>
16
+
17
+ <script>
18
+ import "@xtyle/core/elements";
19
+ </script>
@@ -0,0 +1,17 @@
1
+ ---
2
+ interface Props {
3
+ class?: string;
4
+ /** Any other attribute (`id`, `title`, `data-*`, `aria-*`, …) passes through to the element. */
5
+ [key: string]: unknown;
6
+ }
7
+
8
+ const { class: extra, ...rest } = Astro.props;
9
+ ---
10
+
11
+ <xtyle-timeline class:list={["xtyle-timeline", extra]} {...rest}>
12
+ <slot />
13
+ </xtyle-timeline>
14
+
15
+ <script>
16
+ import "@xtyle/core/elements";
17
+ </script>