@dogsbay/ui 0.2.0-beta.127 → 0.2.0-beta.129

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": "@dogsbay/ui",
3
- "version": "0.2.0-beta.127",
3
+ "version": "0.2.0-beta.129",
4
4
  "description": "Accessible UI components for Astro, inspired by Base UI and shadcn",
5
5
  "type": "module",
6
6
  "exports": {
@@ -22,9 +22,9 @@
22
22
  "katex": "^0.16.47",
23
23
  "maplibre-gl": "^5.24.0",
24
24
  "shiki": "^4.3.1",
25
- "@dogsbay/elements": "0.2.0-beta.127",
26
- "@dogsbay/icons": "0.2.0-beta.127",
27
- "@dogsbay/primitives": "0.2.0-beta.127"
25
+ "@dogsbay/elements": "0.2.0-beta.129",
26
+ "@dogsbay/icons": "0.2.0-beta.129",
27
+ "@dogsbay/primitives": "0.2.0-beta.129"
28
28
  },
29
29
  "files": [
30
30
  "src",
@@ -6,12 +6,15 @@
6
6
  * Composes with the same variant tokens as Alert.
7
7
  *
8
8
  * Usage:
9
- * <CollapsibleAlert variant="warning" title="Warning" open>
9
+ * <CollapsibleAlert variant="warning" title="Warning" icon="lucide:rocket" open>
10
10
  * <p>Body content here.</p>
11
11
  * </CollapsibleAlert>
12
+ *
13
+ * A title with markup goes in the `title` slot: `<Fragment slot="title">Run <code>init</code></Fragment>`.
12
14
  */
13
15
  import { tv, type VariantProps } from "tailwind-variants";
14
16
  import { contentVariants, icons, chevronSvg } from "./variants.js";
17
+ import { resolveIcon } from "./icon.js";
15
18
 
16
19
  const wrapper = tv({
17
20
  base: "relative w-full rounded-lg border overflow-hidden [&>summary]:list-none [&>summary::-webkit-details-marker]:hidden",
@@ -80,20 +83,23 @@ interface Props {
80
83
  title?: string;
81
84
  /** Whether the details starts open */
82
85
  open?: boolean;
86
+ /** An icon name in place of the variant's (`lucide:rocket`, `compass`, an emoji shortcode); unknown names keep the variant's. */
87
+ icon?: string;
83
88
  class?: string;
84
89
  /** id, data-*, aria-*: passed to the <details> (an `id` is a link target) */
85
90
  [key: string]: unknown;
86
91
  }
87
92
 
88
- // `icon` is accepted (the serializer passes it) but not drawn: the variant sets the icon
89
- const { variant = "note", title, open = false, class: className, icon: _icon, ...rest } = Astro.props;
93
+ const { variant = "note", title, open = false, class: className, icon: iconName, ...rest } = Astro.props;
90
94
  const v = variant || "note";
91
95
 
92
96
  // `plain` is chrome — a disclosure, nothing more. No role at all:
93
97
  // role="note"/"status" on collapsed context misinforms assistive tech
94
98
  // (and "status" would make it a live region).
95
99
  const role = v === "plain" ? undefined : contentVariants.has(v) ? "note" : "status";
96
- const icon = contentVariants.has(v) ? icons[v] : null;
100
+ // The author's icon, as Alert draws it; else the variant's (`plain` has none)
101
+ const icon = (iconName ? resolveIcon(iconName) : null) ?? (contentVariants.has(v) ? icons[v] : null);
102
+ const fallbackTitle = title || v.charAt(0).toUpperCase() + v.slice(1);
97
103
  ---
98
104
 
99
105
  {/*
@@ -114,7 +120,7 @@ const icon = contentVariants.has(v) ? icons[v] : null;
114
120
  titleBg[v],
115
121
  ]}>
116
122
  {icon && <span class:list={["shrink-0 [&>svg]:size-4", iconColor[v]]} set:html={icon} />}
117
- <span class="flex-1 text-foreground" data-part="title">{title || v.charAt(0).toUpperCase() + v.slice(1)}</span>
123
+ <span class="flex-1 text-foreground" data-part="title"><slot name="title">{fallbackTitle}</slot></span>
118
124
  <span class="shrink-0 text-muted-foreground group-open/collapsible:rotate-180 transition-transform duration-200" set:html={chevronSvg} />
119
125
  </summary>
120
126
  <div class:list={["px-4 py-3 text-sm [&_p]:leading-relaxed", bodyBg[v]]} role={role}>
package/src/alert/icon.ts CHANGED
@@ -1,30 +1,23 @@
1
1
  /**
2
- * Resolve an icon shortcode for the Alert component.
2
+ * Resolve an icon name for Alert and CollapsibleAlert.
3
3
  *
4
- * Accepts two formats:
5
- * - `library:name` — e.g. "lucide:rocket", "material:check-circle", "simple:github"
6
- * - bare shortcode — treated as emoji (e.g. "rocket" → 🚀)
4
+ * The same names as Icon.astro and dogsbay-ssg (`@dogsbay/icons` resolveIcon):
5
+ * - `pack:name` — e.g. "lucide:rocket", "material:check-circle", "simple:github"
6
+ * - a bare name — an emoji shortcode first ("rocket" → 🚀), then a Lucide icon ("compass")
7
7
  *
8
8
  * Returns an inline SVG string or a span with the emoji character. Returns
9
- * null when the shortcode can't be resolved (caller should fall back to the
9
+ * null when the name can't be resolved (caller should fall back to the
10
10
  * variant's default icon).
11
11
  */
12
- import { createIconRegistry } from "@dogsbay/icons";
13
-
14
- const registry = createIconRegistry();
12
+ import { resolveIcon as resolveName } from "@dogsbay/icons";
15
13
 
16
14
  export function resolveIcon(shortcode: string): string | null {
17
- const colonIdx = shortcode.indexOf(":");
18
- const [library, name] = colonIdx >= 0
19
- ? [shortcode.slice(0, colonIdx), shortcode.slice(colonIdx + 1)]
20
- : ["emoji", shortcode];
21
-
22
- const resolved = registry.resolve(library, name);
15
+ const resolved = resolveName(shortcode);
23
16
  if (!resolved) return null;
24
17
 
25
18
  // Emoji resolve to Unicode characters; wrap for consistent sizing/positioning
26
19
  // with the SVG icons in the Alert layout.
27
- if (library === "emoji") {
20
+ if (!resolved.startsWith("<")) {
28
21
  return `<span aria-hidden="true" style="font-size:1em;line-height:1;display:inline-block;width:1em;text-align:center;">${resolved}</span>`;
29
22
  }
30
23