ardo 3.5.0 → 3.6.1

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 (70) hide show
  1. package/README.md +1 -1
  2. package/dist/{DocPage-EIVMae_6.js → DocPage-Yt8MMpBg.js} +351 -67
  3. package/dist/DocPage-Yt8MMpBg.js.map +1 -0
  4. package/dist/assets/src/ui/components/Accordion.css.ts.vanilla-BPEoNgJt.css +103 -0
  5. package/dist/assets/src/ui/components/Badge.css.ts.vanilla-D9jsj0rg.css +44 -0
  6. package/dist/assets/src/ui/components/Card.css.ts.vanilla-CO6uiEzC.css +97 -0
  7. package/dist/assets/src/ui/theme/{dark.css.ts.vanilla-CSJkJvIz.css → dark.css.ts.vanilla-yFCWJiX4.css} +3 -0
  8. package/dist/assets/src/ui/theme/{light.css.ts.vanilla-CFz9jeJK.css → light.css.ts.vanilla-DDKnXFOi.css} +3 -0
  9. package/dist/{brand-icons-Di8w0Nu9.js → brand-icons-DBTSSnty.js} +1 -1
  10. package/dist/{brand-icons-Di8w0Nu9.js.map → brand-icons-DBTSSnty.js.map} +1 -1
  11. package/dist/config/index.d.ts +2 -2
  12. package/dist/config/index.d.ts.map +1 -1
  13. package/dist/config/index.js +5 -0
  14. package/dist/config/index.js.map +1 -1
  15. package/dist/{contract.css-eFQbUr4z.d.ts → contract.css-BwTjjNXQ.d.ts} +4 -1
  16. package/dist/contract.css-BwTjjNXQ.d.ts.map +1 -0
  17. package/dist/{favicon-Cx-inut3.js → favicon-DN3ymUVm.js} +1 -1
  18. package/dist/{favicon-Cx-inut3.js.map → favicon-DN3ymUVm.js.map} +1 -1
  19. package/dist/{generator-CYSyo4Vz.js → generator-Cc4WGRdf.js} +1 -1
  20. package/dist/{generator-CYSyo4Vz.js.map → generator-Cc4WGRdf.js.map} +1 -1
  21. package/dist/icons/index.d.ts +5 -6
  22. package/dist/icons/index.d.ts.map +1 -1
  23. package/dist/icons/index.js +1 -1
  24. package/dist/{index-CuMTHUxX.d.ts → index-BSWG2TdH.d.ts} +6 -8
  25. package/dist/index-BSWG2TdH.d.ts.map +1 -0
  26. package/dist/{index-BcekgOfA.d.ts → index-Dzu13I_t.d.ts} +138 -47
  27. package/dist/index-Dzu13I_t.d.ts.map +1 -0
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.js +3 -3
  30. package/dist/mdx/provider.d.ts +1 -1
  31. package/dist/mdx/provider.d.ts.map +1 -1
  32. package/dist/mdx/provider.js +6 -1
  33. package/dist/mdx/provider.js.map +1 -1
  34. package/dist/runtime/index.d.ts +2 -2
  35. package/dist/runtime/index.js +1 -1
  36. package/dist/{sidebar-utils-C06DJsx4.js → sidebar-utils-tTBVAPLE.js} +1 -1
  37. package/dist/{sidebar-utils-C06DJsx4.js.map → sidebar-utils-tTBVAPLE.js.map} +1 -1
  38. package/dist/theme/index.d.ts +7 -1
  39. package/dist/theme/index.d.ts.map +1 -1
  40. package/dist/theme/index.js +9 -0
  41. package/dist/theme/index.js.map +1 -1
  42. package/dist/typedoc/components/index.d.ts +8 -8
  43. package/dist/typedoc/components/index.d.ts.map +1 -1
  44. package/dist/typedoc/components/index.js.map +1 -1
  45. package/dist/typedoc/index.d.ts +1 -1
  46. package/dist/typedoc/index.d.ts.map +1 -1
  47. package/dist/typedoc/index.js +3 -3
  48. package/dist/typedoc/index.js.map +1 -1
  49. package/dist/{types-Ck2Vm7NB.d.ts → types-DZKj8kWR.d.ts} +1 -1
  50. package/dist/types-DZKj8kWR.d.ts.map +1 -0
  51. package/dist/{types-B75OhnGa.d.ts → types-iGO1oGpR.d.ts} +49 -4
  52. package/dist/types-iGO1oGpR.d.ts.map +1 -0
  53. package/dist/ui/index.d.ts +2 -2
  54. package/dist/ui/index.js +3 -3
  55. package/dist/ui/styles.css +206 -0
  56. package/dist/ui/styles.js +4 -2
  57. package/dist/{ui-B6X8gAvz.js → ui-mBEFGR-s.js} +316 -138
  58. package/dist/ui-mBEFGR-s.js.map +1 -0
  59. package/dist/vite/index.d.ts +1 -1
  60. package/dist/vite/index.d.ts.map +1 -1
  61. package/dist/vite/index.js +543 -33
  62. package/dist/vite/index.js.map +1 -1
  63. package/package.json +15 -15
  64. package/dist/DocPage-EIVMae_6.js.map +0 -1
  65. package/dist/contract.css-eFQbUr4z.d.ts.map +0 -1
  66. package/dist/index-BcekgOfA.d.ts.map +0 -1
  67. package/dist/index-CuMTHUxX.d.ts.map +0 -1
  68. package/dist/types-B75OhnGa.d.ts.map +0 -1
  69. package/dist/types-Ck2Vm7NB.d.ts.map +0 -1
  70. package/dist/ui-B6X8gAvz.js.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Modern, open documentation for React teams.
4
4
 
5
- Ardo is a React-first static documentation framework built on React 19, React Router 7, Vite 8, MDX, TypeScript, and Vanilla Extract. It is for teams that want VitePress-style simplicity without leaving React or moving their docs into a hosted platform.
5
+ Ardo is a React-first static documentation framework built on React 19, React Router 8, Vite 8, MDX, TypeScript, and Vanilla Extract. It is for teams that want VitePress-style simplicity without leaving React or moving their docs into a hosted platform.
6
6
 
7
7
  ## Why use it?
8
8
 
@@ -1,15 +1,18 @@
1
- import { d as useArdoSidebar, f as useArdoSiteConfig, n as getPrevNextLinks, p as useArdoTOC, r as ArdoContext, s as useArdoConfig, u as useArdoPageData } from "./sidebar-utils-C06DJsx4.js";
2
- import { t as ARDO_FAVICON_DATA_URL } from "./favicon-Cx-inut3.js";
3
- import { Children, createContext, isValidElement, use, useEffect, useMemo, useRef, useState } from "react";
1
+ import { d as useArdoSidebar, f as useArdoSiteConfig, n as getPrevNextLinks, p as useArdoTOC, r as ArdoContext, s as useArdoConfig, u as useArdoPageData } from "./sidebar-utils-tTBVAPLE.js";
2
+ import { t as ARDO_FAVICON_DATA_URL } from "./favicon-DN3ymUVm.js";
3
+ import { Children, cloneElement, createContext, isValidElement, use, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import { Link, Links, Meta, Scripts, ScrollRestoration, useLocation } from "react-router";
6
6
  import "./assets/src/ui/Layout.css.ts.vanilla-ClOa1YZm.css";
7
7
  import "./assets/src/ui/Footer.css.ts.vanilla-DGTyff5Y.css";
8
8
  import { BookOpen as BookOpenIcon, Box as BoxIcon, Check as CheckIcon, ChevronDown as ChevronDownIcon, CircleX as XCircleIcon, Code2 as CodeIcon, Copy as CopyIcon, FileCode2 as FileCodeIcon, FileText as FileTextIcon, Info as InfoIcon, Lightbulb as LightbulbIcon, MessageCircle as MessageCircleIcon, Monitor as MonitorIcon, Moon as MoonIcon, Package as PackageIcon, Search as SearchIcon, Settings as SettingsIcon, Sun as SunIcon, TriangleAlert as AlertTriangleIcon, Wrench as WrenchIcon, X as XIcon } from "lucide-react";
9
+ import "./assets/src/ui/components/Accordion.css.ts.vanilla-BPEoNgJt.css";
10
+ import "./assets/src/ui/components/Badge.css.ts.vanilla-D9jsj0rg.css";
11
+ import { createRuntimeFn } from "@vanilla-extract/recipes/createRuntimeFn";
12
+ import "./assets/src/ui/components/Card.css.ts.vanilla-CO6uiEzC.css";
9
13
  import "./assets/src/ui/components/CopyButton.css.ts.vanilla-CO2awD6S.css";
10
14
  import "./assets/src/ui/components/CodeBlock.css.ts.vanilla-DYyQRTxk.css";
11
15
  import "./assets/src/ui/components/Container.css.ts.vanilla-B8_jKj0Q.css";
12
- import { createRuntimeFn } from "@vanilla-extract/recipes/createRuntimeFn";
13
16
  import "./assets/src/ui/components/Steps.css.ts.vanilla-CisaxeNj.css";
14
17
  import "./assets/src/ui/components/Tabs.css.ts.vanilla-C4-vJSnf.css";
15
18
  import "./assets/src/ui/Breadcrumb.css.ts.vanilla-Dpgq-C_p.css";
@@ -168,6 +171,288 @@ function useBareContent() {
168
171
  return use(BareContentContext);
169
172
  }
170
173
  //#endregion
174
+ //#region src/ui/components/Accordion.css.ts
175
+ var accordion = "_18rgqvr1";
176
+ var accordionGroup = "_18rgqvr0";
177
+ var chevron = "_18rgqvr6";
178
+ var content = "_18rgqvr7";
179
+ var contentInner = "_18rgqvr8";
180
+ var heading = "_18rgqvr2";
181
+ var leadingIcon = "_18rgqvr4";
182
+ var title = "_18rgqvr5";
183
+ var trigger = "_18rgqvr3";
184
+ //#endregion
185
+ //#region src/ui/components/Icon.tsx
186
+ const iconRegistry = /* @__PURE__ */ new Map();
187
+ /**
188
+ * Register icons for use with the Icon component.
189
+ * Only registered icons are included in your bundle.
190
+ *
191
+ * @example
192
+ * ```tsx
193
+ * // In your app's entry point or layout:
194
+ * import { registerIcons } from "ardo/ui"
195
+ * import { Zap, Rocket, Code } from "lucide-react"
196
+ *
197
+ * registerIcons({ Zap, Rocket, Code })
198
+ * ```
199
+ */
200
+ function registerIcons(icons) {
201
+ for (const [name, icon] of Object.entries(icons)) iconRegistry.set(name, icon);
202
+ }
203
+ /**
204
+ * Get all registered icon names (useful for documentation).
205
+ */
206
+ function getRegisteredIconNames() {
207
+ return [...iconRegistry.keys()];
208
+ }
209
+ /**
210
+ * Renders a registered icon by name.
211
+ * Icons must be registered first using `registerIcons()`.
212
+ *
213
+ * @example
214
+ * ```tsx
215
+ * // First register icons in your app:
216
+ * import { registerIcons } from "ardo/ui"
217
+ * import { Zap, Rocket } from "lucide-react"
218
+ * registerIcons({ Zap, Rocket })
219
+ *
220
+ * // Then use in MDX:
221
+ * <Icon name="Zap" size={24} />
222
+ * <Icon name="Rocket" className="text-brand" />
223
+ * ```
224
+ *
225
+ * @see https://lucide.dev/icons for available icon names
226
+ */
227
+ function ArdoIcon({ name, ...props }) {
228
+ const IconComp = iconRegistry.get(name);
229
+ if (!IconComp) {
230
+ console.warn(`[Ardo] Icon "${name}" not found. Did you register it with registerIcons()?`);
231
+ return null;
232
+ }
233
+ return /* @__PURE__ */ jsx(IconComp, { ...props });
234
+ }
235
+ //#endregion
236
+ //#region src/ui/components/Accordion.tsx
237
+ const AccordionGroupContext = createContext(null);
238
+ function AccordionIcon({ icon }) {
239
+ return /* @__PURE__ */ jsx("span", {
240
+ className: leadingIcon,
241
+ "aria-hidden": "true",
242
+ children: typeof icon === "string" ? /* @__PURE__ */ jsx(ArdoIcon, {
243
+ name: icon,
244
+ size: 18
245
+ }) : icon
246
+ });
247
+ }
248
+ function fallbackValue(index) {
249
+ return `ardo-accordion-${index}`;
250
+ }
251
+ function resolveAccordionGroupChildren(children) {
252
+ let accordionIndex = 0;
253
+ let defaultOpenValue;
254
+ const normalizedChildren = Children.map(children, (child) => {
255
+ if (!isValidElement(child) || child.type !== ArdoAccordion) return child;
256
+ const value = child.props.value ?? fallbackValue(accordionIndex);
257
+ accordionIndex += 1;
258
+ if (defaultOpenValue == null && child.props.defaultOpen === true) defaultOpenValue = value;
259
+ return child.props.value == null ? cloneElement(child, { value }) : child;
260
+ });
261
+ return {
262
+ defaultOpenValue,
263
+ normalizedChildren
264
+ };
265
+ }
266
+ /**
267
+ * Group container for accordion items.
268
+ */
269
+ function ArdoAccordionGroup({ children, onlyOneOpen = false, className }) {
270
+ const { defaultOpenValue, normalizedChildren } = useMemo(() => resolveAccordionGroupChildren(children), [children]);
271
+ const [openItem, setOpenItem] = useState(() => onlyOneOpen ? defaultOpenValue : void 0);
272
+ return /* @__PURE__ */ jsx(AccordionGroupContext, {
273
+ value: useMemo(() => ({
274
+ onlyOneOpen,
275
+ openItem,
276
+ setOpenItem
277
+ }), [onlyOneOpen, openItem]),
278
+ children: /* @__PURE__ */ jsx("div", {
279
+ className: className == null ? accordionGroup : `${accordionGroup} ${className}`,
280
+ children: normalizedChildren
281
+ })
282
+ });
283
+ }
284
+ /**
285
+ * Collapsible documentation content section.
286
+ */
287
+ function ArdoAccordion({ title: title$1, children, defaultOpen = false, icon, headingLevel = 3, value, className }) {
288
+ const generatedId = useId();
289
+ const context = use(AccordionGroupContext);
290
+ const resolvedValue = value ?? generatedId;
291
+ const [isOpen, setIsOpen] = useState(defaultOpen);
292
+ const groupedOpen = context?.onlyOneOpen === true ? context.openItem === resolvedValue : isOpen;
293
+ const open = !context?.onlyOneOpen ? isOpen : groupedOpen;
294
+ const accordionClassName = className == null ? accordion : `${accordion} ${className}`;
295
+ const contentId = `${generatedId}-content`;
296
+ const triggerId = `${generatedId}-trigger`;
297
+ const hasIcon = icon != null;
298
+ const Heading = `h${headingLevel}`;
299
+ const toggleOpen = () => {
300
+ if (context?.onlyOneOpen === true) {
301
+ context.setOpenItem(open ? void 0 : resolvedValue);
302
+ return;
303
+ }
304
+ setIsOpen((current) => !current);
305
+ };
306
+ return /* @__PURE__ */ jsxs("section", {
307
+ className: accordionClassName,
308
+ "data-open": open ? "true" : "false",
309
+ children: [/* @__PURE__ */ jsx(Heading, {
310
+ className: heading,
311
+ children: /* @__PURE__ */ jsxs("button", {
312
+ id: triggerId,
313
+ type: "button",
314
+ className: trigger,
315
+ "aria-expanded": open,
316
+ "aria-controls": contentId,
317
+ onClick: toggleOpen,
318
+ children: [
319
+ hasIcon && /* @__PURE__ */ jsx(AccordionIcon, { icon }),
320
+ /* @__PURE__ */ jsx("span", {
321
+ className: title,
322
+ children: title$1
323
+ }),
324
+ /* @__PURE__ */ jsx("span", {
325
+ className: chevron,
326
+ "aria-hidden": "true"
327
+ })
328
+ ]
329
+ })
330
+ }), /* @__PURE__ */ jsx("div", {
331
+ id: contentId,
332
+ role: "region",
333
+ "aria-labelledby": triggerId,
334
+ className: content,
335
+ "aria-hidden": !open,
336
+ inert: !open || void 0,
337
+ children: /* @__PURE__ */ jsx("div", {
338
+ className: contentInner,
339
+ children
340
+ })
341
+ })]
342
+ });
343
+ }
344
+ //#endregion
345
+ //#region src/ui/components/Badge.css.ts
346
+ var badge = createRuntimeFn({
347
+ defaultClassName: "ghbjl60",
348
+ variantClassNames: { variant: {
349
+ "default": "ghbjl61",
350
+ success: "ghbjl62",
351
+ warning: "ghbjl63",
352
+ danger: "ghbjl64",
353
+ info: "ghbjl65"
354
+ } },
355
+ defaultVariants: { variant: "default" },
356
+ compoundVariants: []
357
+ });
358
+ //#endregion
359
+ //#region src/ui/components/Badge.tsx
360
+ /**
361
+ * Inline status label for documentation content.
362
+ */
363
+ function ArdoBadge({ variant = "default", icon: icon$1, children }) {
364
+ return /* @__PURE__ */ jsxs("span", {
365
+ className: badge({ variant }),
366
+ children: [icon$1 != null && /* @__PURE__ */ jsx("span", {
367
+ className: "ghbjl66",
368
+ "aria-hidden": "true",
369
+ children: icon$1
370
+ }), children]
371
+ });
372
+ }
373
+ //#endregion
374
+ //#region src/ui/components/Card.css.ts
375
+ var card = "_8dzbm61";
376
+ var cardGroup = "_8dzbm60";
377
+ var cardHeader = "_8dzbm63";
378
+ var cardIcon = "_8dzbm64";
379
+ var cardLink = "_8dzbm62 _8dzbm61";
380
+ var cardTitle = "_8dzbm65";
381
+ //#endregion
382
+ //#region src/ui/components/Card.tsx
383
+ function isExternalHref(href) {
384
+ return href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//");
385
+ }
386
+ function CardIcon({ icon }) {
387
+ return /* @__PURE__ */ jsx("span", {
388
+ className: cardIcon,
389
+ "aria-hidden": "true",
390
+ children: typeof icon === "string" ? /* @__PURE__ */ jsx(ArdoIcon, {
391
+ name: icon,
392
+ size: 20
393
+ }) : icon
394
+ });
395
+ }
396
+ function CardContent({ title, icon, children }) {
397
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
398
+ className: cardHeader,
399
+ children: [icon != null && /* @__PURE__ */ jsx(CardIcon, { icon }), /* @__PURE__ */ jsx("h3", {
400
+ className: cardTitle,
401
+ children: title
402
+ })]
403
+ }), children != null && /* @__PURE__ */ jsx("span", {
404
+ className: "_8dzbm66",
405
+ children
406
+ })] });
407
+ }
408
+ /**
409
+ * General-purpose documentation card.
410
+ *
411
+ * Cards can be static content blocks or clickable navigation items when `href` is provided.
412
+ */
413
+ function ArdoCard({ title, icon, children, href, className }) {
414
+ const cardClassName = className == null ? card : `${card} ${className}`;
415
+ const cardLinkClassName = className == null ? cardLink : `${cardLink} ${className}`;
416
+ if (href == null || href === "") return /* @__PURE__ */ jsx("div", {
417
+ className: cardClassName,
418
+ children: /* @__PURE__ */ jsx(CardContent, {
419
+ title,
420
+ icon,
421
+ children
422
+ })
423
+ });
424
+ if (isExternalHref(href)) return /* @__PURE__ */ jsx("a", {
425
+ className: cardLinkClassName,
426
+ href,
427
+ target: "_blank",
428
+ rel: "noopener noreferrer",
429
+ children: /* @__PURE__ */ jsx(CardContent, {
430
+ title,
431
+ icon,
432
+ children
433
+ })
434
+ });
435
+ return /* @__PURE__ */ jsx(Link, {
436
+ className: cardLinkClassName,
437
+ to: href,
438
+ children: /* @__PURE__ */ jsx(CardContent, {
439
+ title,
440
+ icon,
441
+ children
442
+ })
443
+ });
444
+ }
445
+ /**
446
+ * Responsive grid for documentation cards.
447
+ */
448
+ function ArdoCardGroup({ children, cols = 2, className }) {
449
+ return /* @__PURE__ */ jsx("div", {
450
+ className: className == null ? cardGroup : `${cardGroup} ${className}`,
451
+ "data-cols": cols,
452
+ children
453
+ });
454
+ }
455
+ //#endregion
171
456
  //#region src/ui/components/CodeBlock.css.ts
172
457
  var codeBlock = "_1l68ra30";
173
458
  var codeGroup = "_1l68ra35";
@@ -471,57 +756,6 @@ function ArdoNote({ title, children }) {
471
756
  });
472
757
  }
473
758
  //#endregion
474
- //#region src/ui/components/Icon.tsx
475
- const iconRegistry = /* @__PURE__ */ new Map();
476
- /**
477
- * Register icons for use with the Icon component.
478
- * Only registered icons are included in your bundle.
479
- *
480
- * @example
481
- * ```tsx
482
- * // In your app's entry point or layout:
483
- * import { registerIcons } from "ardo/ui"
484
- * import { Zap, Rocket, Code } from "lucide-react"
485
- *
486
- * registerIcons({ Zap, Rocket, Code })
487
- * ```
488
- */
489
- function registerIcons(icons) {
490
- for (const [name, icon] of Object.entries(icons)) iconRegistry.set(name, icon);
491
- }
492
- /**
493
- * Get all registered icon names (useful for documentation).
494
- */
495
- function getRegisteredIconNames() {
496
- return [...iconRegistry.keys()];
497
- }
498
- /**
499
- * Renders a registered icon by name.
500
- * Icons must be registered first using `registerIcons()`.
501
- *
502
- * @example
503
- * ```tsx
504
- * // First register icons in your app:
505
- * import { registerIcons } from "ardo/ui"
506
- * import { Zap, Rocket } from "lucide-react"
507
- * registerIcons({ Zap, Rocket })
508
- *
509
- * // Then use in MDX:
510
- * <Icon name="Zap" size={24} />
511
- * <Icon name="Rocket" className="text-brand" />
512
- * ```
513
- *
514
- * @see https://lucide.dev/icons for available icon names
515
- */
516
- function ArdoIcon({ name, ...props }) {
517
- const IconComp = iconRegistry.get(name);
518
- if (!IconComp) {
519
- console.warn(`[Ardo] Icon "${name}" not found. Did you register it with registerIcons()?`);
520
- return null;
521
- }
522
- return /* @__PURE__ */ jsx(IconComp, { ...props });
523
- }
524
- //#endregion
525
759
  //#region src/ui/components/Steps.css.ts
526
760
  var steps = "go9pz30";
527
761
  //#endregion
@@ -566,27 +800,38 @@ function useTabsContext() {
566
800
  * Tabs container component for organizing content into tabbed panels.
567
801
  */
568
802
  function ArdoTabs({ defaultValue, children }) {
803
+ const tabsId = useId();
569
804
  const [activeTab, setActiveTab] = useState(() => defaultValue ?? findFirstTabValue(children));
570
805
  const tabIndexRef = useRef(0);
571
806
  const panelIndexRef = useRef(0);
572
807
  tabIndexRef.current = 0;
573
808
  panelIndexRef.current = 0;
574
- const getTabValue = (value) => {
809
+ const getTabValue = useCallback((value) => {
575
810
  const index = tabIndexRef.current++;
576
811
  return value ?? `${AUTO_TAB_PREFIX}${index}`;
577
- };
578
- const getPanelValue = (value) => {
812
+ }, []);
813
+ const getPanelValue = useCallback((value) => {
579
814
  const index = panelIndexRef.current++;
580
815
  return value ?? `${AUTO_TAB_PREFIX}${index}`;
581
- };
816
+ }, []);
582
817
  const effectiveTab = defaultValue ?? activeTab;
818
+ const getTabId = useCallback((value) => `${tabsId}-tab-${toDomIdSegment(value)}`, [tabsId]);
819
+ const getPanelId = useCallback((value) => `${tabsId}-panel-${toDomIdSegment(value)}`, [tabsId]);
583
820
  return /* @__PURE__ */ jsx(TabsContext, {
584
821
  value: useMemo(() => ({
585
822
  activeTab: effectiveTab,
586
823
  setActiveTab,
587
- getTabValue,
588
- getPanelValue
589
- }), [effectiveTab]),
824
+ getPanelId,
825
+ getPanelValue,
826
+ getTabId,
827
+ getTabValue
828
+ }), [
829
+ effectiveTab,
830
+ getPanelId,
831
+ getPanelValue,
832
+ getTabId,
833
+ getTabValue
834
+ ]),
590
835
  children: /* @__PURE__ */ jsx("div", {
591
836
  className: tabs,
592
837
  children
@@ -600,6 +845,7 @@ function ArdoTabList({ children }) {
600
845
  return /* @__PURE__ */ jsx("div", {
601
846
  className: tabList,
602
847
  role: "tablist",
848
+ onKeyDown: handleTabListKeyDown,
603
849
  children
604
850
  });
605
851
  }
@@ -607,13 +853,17 @@ function ArdoTabList({ children }) {
607
853
  * Individual tab button.
608
854
  */
609
855
  function ArdoTab({ value, children }) {
610
- const { activeTab, setActiveTab, getTabValue } = useTabsContext();
856
+ const { activeTab, setActiveTab, getPanelId, getTabId, getTabValue } = useTabsContext();
611
857
  const resolvedValue = getTabValue(value);
612
858
  const isActive = activeTab === resolvedValue;
613
859
  return /* @__PURE__ */ jsx("button", {
614
860
  type: "button",
615
861
  role: "tab",
862
+ id: getTabId(resolvedValue),
863
+ "aria-controls": getPanelId(resolvedValue),
616
864
  "aria-selected": isActive,
865
+ tabIndex: isActive ? 0 : -1,
866
+ "data-ardo-tab-value": resolvedValue,
617
867
  className: [tab, isActive && "active"].filter(Boolean).join(" "),
618
868
  onClick: () => {
619
869
  setActiveTab(resolvedValue);
@@ -625,10 +875,14 @@ function ArdoTab({ value, children }) {
625
875
  * Content panel for a tab.
626
876
  */
627
877
  function ArdoTabPanel({ value, children }) {
628
- const { activeTab, getPanelValue } = useTabsContext();
629
- if (!(activeTab === getPanelValue(value))) return null;
878
+ const { activeTab, getPanelId, getPanelValue, getTabId } = useTabsContext();
879
+ const resolvedValue = getPanelValue(value);
880
+ if (!(activeTab === resolvedValue)) return null;
630
881
  return /* @__PURE__ */ jsx("div", {
631
882
  role: "tabpanel",
883
+ id: getPanelId(resolvedValue),
884
+ "aria-labelledby": getTabId(resolvedValue),
885
+ tabIndex: 0,
632
886
  className: tabPanel,
633
887
  children
634
888
  });
@@ -657,6 +911,36 @@ function getFirstTabValueFromChild(child) {
657
911
  const nestedValue = findFirstTabValue(nestedChildren);
658
912
  return nestedValue === "" ? null : nestedValue;
659
913
  }
914
+ function handleTabListKeyDown(event) {
915
+ if (!isTabNavigationKey(event.key)) return;
916
+ const tabs = getTabsFromList(event.currentTarget);
917
+ if (tabs.length === 0) return;
918
+ if (!(event.target instanceof HTMLButtonElement)) return;
919
+ const currentIndex = tabs.indexOf(event.target);
920
+ if (currentIndex === -1) return;
921
+ event.preventDefault();
922
+ const nextTab = tabs[getNextTabIndex(event.key, currentIndex, tabs.length)];
923
+ nextTab.focus();
924
+ nextTab.click();
925
+ }
926
+ function isTabNavigationKey(key) {
927
+ return key === "ArrowLeft" || key === "ArrowRight" || key === "Home" || key === "End";
928
+ }
929
+ function getTabsFromList(tabList) {
930
+ return [...tabList.querySelectorAll("[role=\"tab\"]")];
931
+ }
932
+ function getNextTabIndex(key, currentIndex, tabCount) {
933
+ switch (key) {
934
+ case "ArrowLeft": return (currentIndex - 1 + tabCount) % tabCount;
935
+ case "ArrowRight": return (currentIndex + 1) % tabCount;
936
+ case "Home": return 0;
937
+ case "End": return tabCount - 1;
938
+ default: return currentIndex;
939
+ }
940
+ }
941
+ function toDomIdSegment(value) {
942
+ return Array.from(value, (char) => char.charCodeAt(0).toString(36)).join("-");
943
+ }
660
944
  //#endregion
661
945
  //#region src/ui/Breadcrumb.css.ts
662
946
  var breadcrumb = "_19g8fxh0";
@@ -1134,6 +1418,6 @@ function ArdoDocLayout({ content }) {
1134
1418
  return /* @__PURE__ */ jsx(ArdoDocPage, { children: content });
1135
1419
  }
1136
1420
  //#endregion
1137
- export { footerLink as $, home as A, MonitorIcon as B, ArdoCopyButton as C, ArdoBareContent as D, codeWrapper as E, ChevronDownIcon as F, SunIcon as G, PackageIcon as H, CodeIcon as I, footer as J, WrenchIcon as K, FileCodeIcon as L, layout as M, BookOpenIcon as N, ArdoLayout as O, BoxIcon as P, footerCopyright as Q, FileTextIcon as R, ArdoCodeGroup as S, codeTitle as T, SearchIcon as U, MoonIcon as V, SettingsIcon as W, footerBuildTime as X, footerArdoLink as Y, footerContainer as Z, ArdoInfo as _, ArdoContent as a, ArdoWarning as b, ArdoTabPanel as c, ArdoSteps as d, footerMessage as et, ArdoIcon as f, ArdoDanger as g, ArdoContainer as h, ArdoTOC as i, homeMain as j, ArdoRootLayout as k, ArdoTabPanels as l, registerIcons as m, ArdoDocLayout as n, footerPrimary as nt, ArdoTab as o, getRegisteredIconNames as p, XIcon as q, ArdoDocPage as r, footerSeparator as rt, ArdoTabList as s, ArdoDocContent as t, footerOwl as tt, ArdoTabs as u, ArdoNote as v, codeBlock as w, ArdoCodeBlock as x, ArdoTip as y, MessageCircleIcon as z };
1421
+ export { footer as $, getRegisteredIconNames as A, ChevronDownIcon as B, codeWrapper as C, ArdoAccordion as D, ArdoBadge as E, home as F, MonitorIcon as G, FileCodeIcon as H, homeMain as I, SearchIcon as J, MoonIcon as K, layout as L, ArdoBareContent as M, ArdoLayout as N, ArdoAccordionGroup as O, ArdoRootLayout as P, XIcon as Q, BookOpenIcon as R, codeTitle as S, ArdoCardGroup as T, FileTextIcon as U, CodeIcon as V, MessageCircleIcon as W, SunIcon as X, SettingsIcon as Y, WrenchIcon as Z, ArdoWarning as _, ArdoContent as a, footerMessage as at, ArdoCopyButton as b, ArdoTabPanel as c, footerSeparator as ct, ArdoSteps as d, footerArdoLink as et, ArdoContainer as f, ArdoTip as g, ArdoNote as h, ArdoTOC as i, footerLink as it, registerIcons as j, ArdoIcon as k, ArdoTabPanels as l, ArdoInfo as m, ArdoDocLayout as n, footerContainer as nt, ArdoTab as o, footerOwl as ot, ArdoDanger as p, PackageIcon as q, ArdoDocPage as r, footerCopyright as rt, ArdoTabList as s, footerPrimary as st, ArdoDocContent as t, footerBuildTime as tt, ArdoTabs as u, ArdoCodeBlock as v, ArdoCard as w, codeBlock as x, ArdoCodeGroup as y, BoxIcon as z };
1138
1422
 
1139
- //# sourceMappingURL=DocPage-EIVMae_6.js.map
1423
+ //# sourceMappingURL=DocPage-Yt8MMpBg.js.map