@dogsbay/ui 0.2.0-beta.91 → 0.2.0-beta.93
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.
|
|
3
|
+
"version": "0.2.0-beta.93",
|
|
4
4
|
"description": "Accessible UI components for Astro, inspired by Base UI and shadcn",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
13
|
"astro": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
14
|
-
"@dogsbay/primitives": "0.2.0-beta.
|
|
15
|
-
"@dogsbay/
|
|
16
|
-
"@dogsbay/
|
|
14
|
+
"@dogsbay/primitives": "0.2.0-beta.93",
|
|
15
|
+
"@dogsbay/icons": "0.2.0-beta.93",
|
|
16
|
+
"@dogsbay/elements": "0.2.0-beta.93"
|
|
17
17
|
},
|
|
18
18
|
"optionalDependencies": {
|
|
19
19
|
"shiki": "^4.0.0",
|
|
@@ -42,6 +42,15 @@ const {
|
|
|
42
42
|
...rest
|
|
43
43
|
} = Astro.props;
|
|
44
44
|
|
|
45
|
+
// AsciiDoc/docs language tokens that are not Shiki grammars → the nearest real
|
|
46
|
+
// one, so the block actually highlights (and data-language is meaningful)
|
|
47
|
+
// instead of silently falling back to plaintext. The header still shows the
|
|
48
|
+
// original label (`lang` below), only the highlighter input is aliased. #009.
|
|
49
|
+
const LANG_ALIASES: Record<string, string> = {
|
|
50
|
+
terminal: "bash",
|
|
51
|
+
};
|
|
52
|
+
const shikiLang = LANG_ALIASES[lang.toLowerCase()] ?? lang.toLowerCase();
|
|
53
|
+
|
|
45
54
|
// Show header bar based on showTitle prop:
|
|
46
55
|
// - true: show when there's a title or a declared language (default, original behavior)
|
|
47
56
|
// - false: never show
|
|
@@ -107,7 +116,7 @@ const floatingCopy = copy && !showHeader;
|
|
|
107
116
|
</div>
|
|
108
117
|
)}
|
|
109
118
|
<div class="relative overflow-x-auto [&_pre]:!m-0 [&_pre]:!rounded-none [&_pre]:!border-0 [&_pre]:px-4 [&_pre]:py-3">
|
|
110
|
-
<Code code={code} lang={
|
|
119
|
+
<Code code={code} lang={shikiLang} themes={{ light: "github-light-default", dark: theme }} defaultColor={false} />
|
|
111
120
|
{floatingCopy && (
|
|
112
121
|
<button
|
|
113
122
|
class:list={[codeBlockCopy(), "absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity"]}
|
|
@@ -177,7 +177,7 @@ function withBaseUrl(src: string | undefined): string {
|
|
|
177
177
|
<Fragment set:html={
|
|
178
178
|
`<h${node.props!.level} id="${node.props!.slug || ''}" class="group scroll-mt-20">` +
|
|
179
179
|
`${node.inline ? inlineToHtml(node.inline) : (node.html?.replace(/<h\d[^>]*>|<\/h\d>/g, '') || node.props!.text || '')}` +
|
|
180
|
-
`<a href="#${node.props!.slug || ''}" class="no-underline ml-2 opacity-0 group-hover:opacity-50 transition-opacity text-muted-foreground" aria-label="Link to this heading">¶</a>` +
|
|
180
|
+
`<a href="#${node.props!.slug || ''}" class="heading-anchor no-underline ml-2 opacity-0 group-hover:opacity-50 transition-opacity text-muted-foreground" aria-label="Link to this heading">¶</a>` +
|
|
181
181
|
`</h${node.props!.level}>`
|
|
182
182
|
} />
|
|
183
183
|
)}
|
|
@@ -295,7 +295,18 @@ function withBaseUrl(src: string | undefined): string {
|
|
|
295
295
|
{/* ── Table ──────────────────────────────────────────────── */}
|
|
296
296
|
{node.type === "table" && (
|
|
297
297
|
<Table class="my-4">
|
|
298
|
-
{
|
|
298
|
+
{(node.props?.headerRows as string[][] | undefined)?.length ? (
|
|
299
|
+
<TableHeader>
|
|
300
|
+
{(node.props!.headerRows as string[][]).map((row) => (
|
|
301
|
+
<TableRow>{row.map((cell) => <TableHead set:html={cell} />)}</TableRow>
|
|
302
|
+
))}
|
|
303
|
+
</TableHeader>
|
|
304
|
+
) : null}
|
|
305
|
+
<TableBody>
|
|
306
|
+
{((node.props?.bodyRows as string[][] | undefined) ?? []).map((row) => (
|
|
307
|
+
<TableRow>{row.map((cell) => <TableCell set:html={cell} />)}</TableRow>
|
|
308
|
+
))}
|
|
309
|
+
</TableBody>
|
|
299
310
|
</Table>
|
|
300
311
|
)}
|
|
301
312
|
{node.type === "thead" && <TableHeader>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</TableHeader>}
|
|
@@ -54,24 +54,71 @@ const paddingLeft = `${8 + level * 12}px`;
|
|
|
54
54
|
const active = item.href ? isActive(item.href) : false;
|
|
55
55
|
const hasChildren = item.children && item.children.length > 0;
|
|
56
56
|
const shouldOpen = hasChildren && hasActiveDescendant(item);
|
|
57
|
+
const open = shouldOpen || active;
|
|
58
|
+
// A branch that is ALSO a page (has an href) is a section landing
|
|
59
|
+
// page; it uses the button-driven disclosure below and needs a
|
|
60
|
+
// stable id linking its toggle button to its submenu.
|
|
61
|
+
const submenuId = item.href
|
|
62
|
+
? `nav-sub-${item.href.replace(/[^a-z0-9]+/gi, "-")}-${level}`
|
|
63
|
+
: undefined;
|
|
57
64
|
|
|
58
65
|
return (
|
|
59
66
|
<li data-sidebar="nav-tree-item">
|
|
60
|
-
{hasChildren ? (
|
|
67
|
+
{hasChildren && item.href ? (
|
|
68
|
+
/*
|
|
69
|
+
Section landing page: APG "disclosure navigation" pattern — a
|
|
70
|
+
real link (navigates) + a SEPARATE toggle <button> (expands),
|
|
71
|
+
as siblings. Nesting a focusable <a> inside the interactive
|
|
72
|
+
<summary> is an axe `nested-interactive` violation, and native
|
|
73
|
+
<details> can't show a header link when collapsed without that
|
|
74
|
+
nesting. Progressive enhancement: the submenu's server state
|
|
75
|
+
(hidden unless open) is correct with no JS — the link still
|
|
76
|
+
works and the active section is expanded — and the inline
|
|
77
|
+
script wires the toggle button when JS is available.
|
|
78
|
+
*/
|
|
79
|
+
<Fragment>
|
|
80
|
+
<div
|
|
81
|
+
class:list={[
|
|
82
|
+
"flex w-full min-w-0 items-center gap-2 rounded-md text-sm text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
83
|
+
level === 0 ? "h-8" : "h-7",
|
|
84
|
+
active && "bg-sidebar-accent font-medium text-sidebar-accent-foreground",
|
|
85
|
+
]}
|
|
86
|
+
style={`padding-left: ${paddingLeft};`}
|
|
87
|
+
>
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
data-nav-toggle
|
|
91
|
+
aria-controls={submenuId}
|
|
92
|
+
aria-expanded={open ? "true" : "false"}
|
|
93
|
+
aria-label={`Toggle ${item.label} section`}
|
|
94
|
+
class="shrink-0 rounded outline-none ring-sidebar-ring focus-visible:ring-2"
|
|
95
|
+
>
|
|
96
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4 shrink-0 transition-transform duration-200" data-chevron aria-hidden="true"><polyline points="9 18 15 12 9 6" /></svg>
|
|
97
|
+
</button>
|
|
98
|
+
{item.icon && <span class="shrink-0 [&>svg]:size-4" set:html={item.icon} />}
|
|
99
|
+
<a
|
|
100
|
+
href={item.href}
|
|
101
|
+
class="min-w-0 flex-1 truncate text-inherit no-underline outline-none ring-sidebar-ring focus-visible:ring-2"
|
|
102
|
+
data-nav-href={item.href}
|
|
103
|
+
data-active={active || undefined}
|
|
104
|
+
>{item.label}</a>
|
|
105
|
+
</div>
|
|
106
|
+
<div id={submenuId} data-nav-submenu hidden={!open}>
|
|
107
|
+
<Astro.self items={item.children!} currentPath={currentPath} level={level + 1} />
|
|
108
|
+
</div>
|
|
109
|
+
</Fragment>
|
|
110
|
+
) : hasChildren ? (
|
|
61
111
|
<details open={shouldOpen || active}>
|
|
62
112
|
<summary
|
|
63
113
|
class:list={[
|
|
64
114
|
"flex w-full min-w-0 cursor-pointer items-center gap-2 rounded-md text-sm text-sidebar-foreground outline-none [list-style:none] ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&::-webkit-details-marker]:hidden",
|
|
65
115
|
level === 0 ? "h-8" : "h-7",
|
|
66
|
-
active && "bg-sidebar-accent font-medium text-sidebar-accent-foreground",
|
|
67
116
|
]}
|
|
68
117
|
style={`padding-left: ${paddingLeft};`}
|
|
69
|
-
data-nav-href={item.href || undefined}
|
|
70
|
-
data-active={active || undefined}
|
|
71
118
|
>
|
|
72
119
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4 shrink-0 transition-transform duration-200" data-chevron aria-hidden="true"><polyline points="9 18 15 12 9 6" /></svg>
|
|
73
120
|
{item.icon && <span class="shrink-0 [&>svg]:size-4" set:html={item.icon} />}
|
|
74
|
-
<span class="truncate">{item.label}</span>
|
|
121
|
+
<span class="min-w-0 flex-1 truncate">{item.label}</span>
|
|
75
122
|
</summary>
|
|
76
123
|
<Astro.self items={item.children!} currentPath={currentPath} level={level + 1} />
|
|
77
124
|
</details>
|
|
@@ -100,7 +147,32 @@ const paddingLeft = `${8 + level * 12}px`;
|
|
|
100
147
|
</ul>
|
|
101
148
|
|
|
102
149
|
<style is:global>
|
|
103
|
-
details[open] > summary [data-chevron]
|
|
150
|
+
details[open] > summary [data-chevron],
|
|
151
|
+
[data-nav-toggle][aria-expanded="true"] [data-chevron] {
|
|
104
152
|
transform: rotate(90deg);
|
|
105
153
|
}
|
|
106
154
|
</style>
|
|
155
|
+
|
|
156
|
+
<script>
|
|
157
|
+
// Wire the section-landing disclosure toggles (APG disclosure-nav).
|
|
158
|
+
// The link navigates on its own; this button just expands/collapses
|
|
159
|
+
// the sibling submenu. Server-rendered state is already correct, so
|
|
160
|
+
// with no JS the link still works and the active section is open.
|
|
161
|
+
// Idempotent + re-run after view transitions.
|
|
162
|
+
function wireNavToggles() {
|
|
163
|
+
document
|
|
164
|
+
.querySelectorAll<HTMLButtonElement>("[data-nav-toggle]:not([data-wired])")
|
|
165
|
+
.forEach((btn) => {
|
|
166
|
+
btn.dataset.wired = "1";
|
|
167
|
+
const id = btn.getAttribute("aria-controls");
|
|
168
|
+
const submenu = id ? document.getElementById(id) : null;
|
|
169
|
+
btn.addEventListener("click", () => {
|
|
170
|
+
const isOpen = btn.getAttribute("aria-expanded") === "true";
|
|
171
|
+
btn.setAttribute("aria-expanded", String(!isOpen));
|
|
172
|
+
if (submenu) submenu.hidden = isOpen;
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
wireNavToggles();
|
|
177
|
+
document.addEventListener("astro:page-load", wireNavToggles);
|
|
178
|
+
</script>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { tv } from "tailwind-variants";
|
|
3
3
|
|
|
4
4
|
const tableHead = tv({
|
|
5
|
-
base: "
|
|
5
|
+
base: "px-2 py-2 text-left align-bottom font-semibold text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
interface Props {
|