@eduardoalvarez/arrecife 0.7.0 → 0.9.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 (56) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +115 -41
  3. package/dist/brand/index.cjs +2 -2
  4. package/dist/brand/index.js +3 -3
  5. package/dist/chart/index.cjs +155 -2
  6. package/dist/chart/index.d.cts +136 -4
  7. package/dist/chart/index.d.ts +136 -4
  8. package/dist/chart/index.js +155 -5
  9. package/dist/{chunk-TA7TLWW4.js → chunk-5A5GH2PF.js} +1 -1
  10. package/dist/{chunk-727HCBD4.js → chunk-6IGD5REB.js} +1 -1
  11. package/dist/{chunk-2WPWEIMD.js → chunk-FAAGZG7A.js} +1 -1
  12. package/dist/{chunk-OMKSESQB.js → chunk-FGFNK72B.js} +3 -3
  13. package/dist/chunk-HOADZ6GS.js +72 -0
  14. package/dist/chunk-LXRGQKMG.js +145 -0
  15. package/dist/{chunk-JN3IS5OS.js → chunk-MPZBF2TZ.js} +2 -2
  16. package/dist/{chunk-WGNIRIN7.js → chunk-TRPBID2W.js} +1 -1
  17. package/dist/{chunk-E6KFUSKB.js → chunk-XXDATT3A.js} +1 -1
  18. package/dist/doctor.mjs +95 -13
  19. package/dist/form/index.cjs +2 -2
  20. package/dist/form/index.d.cts +1 -1
  21. package/dist/form/index.d.ts +1 -1
  22. package/dist/form/index.js +4 -4
  23. package/dist/icons/index.cjs +2 -2
  24. package/dist/icons/index.d.cts +2 -2
  25. package/dist/icons/index.d.ts +2 -2
  26. package/dist/icons/index.js +2 -2
  27. package/dist/{index-DlAO2JZs.d.cts → index-BbRplw_B.d.cts} +15 -4
  28. package/dist/{index-DlAO2JZs.d.ts → index-BbRplw_B.d.ts} +15 -4
  29. package/dist/index.cjs +264 -264
  30. package/dist/index.d.cts +212 -126
  31. package/dist/index.d.ts +212 -126
  32. package/dist/index.js +153 -236
  33. package/dist/{label-MgHFKnFy.d.ts → label-DJ4HuD-R.d.cts} +3 -2
  34. package/dist/{label-MgHFKnFy.d.cts → label-DJ4HuD-R.d.ts} +3 -2
  35. package/dist/og/index.js +1 -1
  36. package/dist/shiki/index.js +1 -1
  37. package/dist/social/data.cjs +161 -0
  38. package/dist/social/data.d.cts +161 -0
  39. package/dist/social/data.d.ts +161 -0
  40. package/dist/social/data.js +2 -0
  41. package/dist/social/index.cjs +124 -38
  42. package/dist/social/index.d.cts +1 -1
  43. package/dist/social/index.d.ts +1 -1
  44. package/dist/social/index.js +2 -1
  45. package/dist/tokens/index.cjs +3 -3
  46. package/dist/tokens/index.d.cts +5 -5
  47. package/dist/tokens/index.d.ts +5 -5
  48. package/dist/tokens/index.js +2 -2
  49. package/dist/tokens/theme.css +46 -19
  50. package/dist/variants/index.cjs +1 -1
  51. package/dist/variants/index.d.cts +2 -2
  52. package/dist/variants/index.d.ts +2 -2
  53. package/dist/variants/index.js +1 -1
  54. package/llms.txt +264 -140
  55. package/package.json +6 -1
  56. package/dist/chunk-45HVCTB7.js +0 -70
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ import { DayPicker } from 'react-day-picker';
13
13
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
14
14
  import * as DialogPrimitive from '@radix-ui/react-dialog';
15
15
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
16
- export { L as Label, a as LabelProps } from './label-MgHFKnFy.js';
16
+ export { L as Label, a as LabelProps } from './label-DJ4HuD-R.js';
17
17
  import * as PopoverPrimitive from '@radix-ui/react-popover';
18
18
  import * as ProgressPrimitive from '@radix-ui/react-progress';
19
19
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
@@ -28,7 +28,7 @@ import { F as Face, P as Pose } from './catalog-D13txprv.js';
28
28
  export { A as ASSETS_PATH, B as Background, a as Fin, f as faceList, b as faceUsage, c as faces, d as fins, p as poseList, e as poses } from './catalog-D13txprv.js';
29
29
  export { Isotype, IsotypeProps, Logo, LogoProps, Mascot, MascotFace, MascotFaceProps, MascotProps } from './brand/index.js';
30
30
  import { ClassValue } from 'clsx';
31
- export { i as social } from './index-DlAO2JZs.js';
31
+ export { i as social } from './index-BbRplw_B.js';
32
32
  import '@radix-ui/react-label';
33
33
 
34
34
  /**
@@ -49,7 +49,7 @@ import '@radix-ui/react-label';
49
49
  * `--ease-standard`, so it introduces neither a new timing nor a new curve.
50
50
  * Whoever asked for less motion still sees the panel appear where it will stay.
51
51
  *
52
- * See `docs/decisions.md` § 20.
52
+ * See `docs/decisions/0.6.md` § 20.
53
53
  *
54
54
  * The chevron, by contrast, rotates with no transition: `transition-standard`
55
55
  * only covers color and border, so `rotate` snaps even with the class in place.
@@ -112,7 +112,7 @@ declare function Alert({ className, variant, emphasis, title, icon, children, ..
112
112
  * «Borrar el artículo», not «Aceptar».
113
113
  *
114
114
  * `destructive` is for the destructive button that has none of that around it:
115
- * a table row, a toolbar. See `docs/decisions.md` § 21.
115
+ * a table row, a toolbar. See `docs/decisions/0.6.md` § 21.
116
116
  */
117
117
  declare const AlertDialog: react.FC<AlertDialogPrimitive.AlertDialogProps>;
118
118
  declare const AlertDialogTrigger: react.ForwardRefExoticComponent<AlertDialogPrimitive.AlertDialogTriggerProps & react.RefAttributes<HTMLButtonElement>>;
@@ -267,7 +267,8 @@ declare function Checkbox({ className, ...props }: CheckboxProps): react.JSX.Ele
267
267
  type CodeProps = ComponentPropsWithoutRef<'code'>;
268
268
  declare function Code({ className, ...props }: CodeProps): react.JSX.Element;
269
269
 
270
- type DateFieldProps = Omit<ComponentPropsWithoutRef<'input'>, 'type'> & {
270
+ /** `ComponentProps` carries `ref`, which React 19 passes as a prop. See `InputProps`. */
271
+ type DateFieldProps = Omit<ComponentProps<'input'>, 'type'> & {
271
272
  invalid?: boolean | undefined;
272
273
  /** Adds the time to the field. It is the native `datetime-local`. */
273
274
  withTime?: boolean | undefined;
@@ -316,7 +317,29 @@ declare function DropdownMenuSeparator({ className, ...props }: ComponentPropsWi
316
317
  declare function DropdownMenuSubTrigger({ className, children, ...props }: ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger>): react.JSX.Element;
317
318
  declare function DropdownMenuSubContent({ className, ...props }: ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>): react.JSX.Element;
318
319
 
319
- type InputProps = ComponentPropsWithoutRef<'input'> & {
320
+ /**
321
+ * `ComponentProps` and not `ComponentPropsWithoutRef`, and the difference is a
322
+ * bug and not a preference.
323
+ *
324
+ * `WithoutRef` is what React 18 required: `ref` was not a prop there, it arrived
325
+ * through `forwardRef`, and a type that included it promised something the
326
+ * component could not deliver. React 19 passes `ref` as an ordinary prop, so the
327
+ * `...props` spread below already forwards it — the type was the only thing
328
+ * still saying otherwise. It WORKED at runtime and failed at `tsc` with
329
+ * «Property 'ref' does not exist», which is the worst half of the two: the
330
+ * escape route is a cast or a wrapper element, and both are detours around a
331
+ * type rather than around a behaviour.
332
+ *
333
+ * `blog-content-manager` took the second one — its Giphy dialog focuses the
334
+ * search field 50 ms after opening, because Radix claims focus first, and it had
335
+ * to take the `ref` on the wrapping `div` and reach the input with a
336
+ * `querySelector`.
337
+ *
338
+ * The same applies to every primitive that wraps a native control you can focus:
339
+ * `Textarea`, `Label` and `DateField` change with it. See `docs/decisions/`
340
+ * § 41.
341
+ */
342
+ type InputProps = ComponentProps<'input'> & {
320
343
  /** Marks the control as invalid and tints the border. */
321
344
  invalid?: boolean;
322
345
  };
@@ -447,7 +470,50 @@ type SwitchProps = ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>;
447
470
  */
448
471
  declare function Switch({ className, ...props }: SwitchProps): react.JSX.Element;
449
472
 
450
- /** The container scrolls horizontally: the page never does. */
473
+ /**
474
+ * The table, and the surface it sits on. The two are one piece.
475
+ *
476
+ * The container has always scrolled horizontally so the PAGE never does. What it
477
+ * did not carry was a shape, and that turned out to be the same omission twice:
478
+ * `TableRow` tints a `<tr>` on hover, a `<tr>` is a rectangle, and nothing
479
+ * clipped it — so every project wrapped the table in its own `rounded-xl border`
480
+ * and the hover of the header row and of the last row spilled out through the
481
+ * rounded corner. The fix from outside is `overflow-hidden` on that wrapper, and
482
+ * it worked exactly as far as somebody remembering it: five tables in `cursos`
483
+ * had it and the nine in `blog-content-manager` did not.
484
+ *
485
+ * So the surface comes with the table. `rounded-card` and `border-hairline` are
486
+ * the same two the system already gives a card — a table IS a panel of content,
487
+ * not a bare grid — and the clip comes free with the scroll: an element with
488
+ * `overflow-x: auto` clips its content to the border box, corners included. The
489
+ * hover cannot spill because there is nowhere left to spill to, and fourteen
490
+ * copies of the same `div` stop existing.
491
+ *
492
+ * There is NO background token on it, and that is not an oversight: `TableRow`'s
493
+ * hover is `bg-surface`, so painting the container `surface` too would make the
494
+ * hover invisible. The table sits on the page and the row lifts off it, which is
495
+ * the direction the tint was written for.
496
+ *
497
+ * `className` reaches the `<table>` and not the container, which is the trap
498
+ * `Nav`'s `size` documents: a `rounded-none` passed from the call site does
499
+ * nothing, silently. There is one shape on purpose — fourteen call sites wanted
500
+ * the same one — and a second gets a prop when a second consumer exists, not
501
+ * before. See `docs/decisions/0.8.md` § 39.
502
+ *
503
+ * THE `tabIndex` IS NOT DECORATION and it is not new behaviour dressed up as
504
+ * markup. A region you can pan with a mouse has to be reachable with a keyboard
505
+ * — WCAG 2.1.1 — and a table of text contains nothing focusable to land on, so
506
+ * without it a keyboard user simply cannot read the columns that are off screen.
507
+ * It has been true since the container started scrolling; it went unseen because
508
+ * no story had more columns than width, and the first one that did failed axe on
509
+ * `scrollable-region-focusable` at once.
510
+ *
511
+ * It is unconditional because the alternative is worse. Whether the table
512
+ * overflows depends on the viewport, so the only way to set this correctly at
513
+ * render is to measure in an effect and re-measure on resize — a ResizeObserver
514
+ * on every table in the system to avoid a tab stop. A stop that scrolls nothing
515
+ * is a small cost; a region a keyboard cannot reach is content that is not there.
516
+ */
451
517
  declare function Table({ className, ...props }: ComponentPropsWithoutRef<'table'>): react.JSX.Element;
452
518
  declare function TableHeader({ className, ...props }: ComponentPropsWithoutRef<'thead'>): react.JSX.Element;
453
519
  declare function TableBody({ className, ...props }: ComponentPropsWithoutRef<'tbody'>): react.JSX.Element;
@@ -455,6 +521,15 @@ declare function TableFooter({ className, ...props }: ComponentPropsWithoutRef<'
455
521
  declare function TableRow({ className, ...props }: ComponentPropsWithoutRef<'tr'>): react.JSX.Element;
456
522
  declare function TableHead({ className, ...props }: ComponentPropsWithoutRef<'th'>): react.JSX.Element;
457
523
  declare function TableCell({ className, ...props }: ComponentPropsWithoutRef<'td'>): react.JSX.Element;
524
+ /**
525
+ * The caption, at the bottom and INSIDE the surface.
526
+ *
527
+ * It carries its own horizontal padding, which the cells get from `px-step-sm`
528
+ * and it used to get from nobody: with no border drawn around the table it read
529
+ * as a line under a grid, and with one it would sit flush against the left edge.
530
+ * The bottom padding is the same reasoning — a caption touching the border below
531
+ * it reads as an overflow, not as a caption.
532
+ */
458
533
  declare function TableCaption({ className, ...props }: ComponentPropsWithoutRef<'caption'>): react.JSX.Element;
459
534
 
460
535
  type TabsProps = ComponentPropsWithoutRef<typeof TabsPrimitive.Root>;
@@ -463,7 +538,8 @@ declare function TabsList({ className, ...props }: ComponentPropsWithoutRef<type
463
538
  declare function TabsTrigger({ className, ...props }: ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>): react.JSX.Element;
464
539
  declare function TabsContent({ className, ...props }: ComponentPropsWithoutRef<typeof TabsPrimitive.Content>): react.JSX.Element;
465
540
 
466
- type TextareaProps = ComponentPropsWithoutRef<'textarea'> & {
541
+ /** `ComponentProps` carries `ref`, which React 19 passes as a prop. See `InputProps`. */
542
+ type TextareaProps = ComponentProps<'textarea'> & {
467
543
  invalid?: boolean;
468
544
  };
469
545
  declare function Textarea({ className, invalid, ...props }: TextareaProps): react.JSX.Element;
@@ -572,7 +648,7 @@ type CardShellProps = ComponentPropsWithoutRef<'a'> & {
572
648
  children: ReactNode;
573
649
  };
574
650
 
575
- type ArticleCardProps = Omit<CardShellProps, 'children' | 'title'> & {
651
+ type ArticleCardProps = Omit<CardShellProps, "children" | "title"> & {
576
652
  title: ReactNode;
577
653
  /** Standfirst. Clamped to two lines so the grid does not fall out of line. */
578
654
  excerpt?: ReactNode;
@@ -617,8 +693,8 @@ type ArticleCardProps = Omit<CardShellProps, 'children' | 'title'> & {
617
693
  }) => ReactNode) | undefined;
618
694
  };
619
695
  /**
620
- * The metadata line uses `meta` and not `eyebrow`: `18 ago 2026 · 8 min de
621
- * lectura` is a datum, not an overline, and in small caps it was neither.
696
+ * The metadata line uses `meta` and not `eyebrow`: `18 ago 2026 · 8 min de lectura`
697
+ * is a datum, not an overline, and in small caps it was neither.
622
698
  *
623
699
  * The tags are the CATEGORY family — a lowercase sand pill — not the status one.
624
700
  * A slug is something you read as `engineering-culture`.
@@ -788,7 +864,7 @@ declare function CourseCard({ title, summary, meta, status, progress, className,
788
864
  * smaller one: the hole inside a table page or a dashboard widget, competing with
789
865
  * a dozen elements around it. An admin panel has twenty of those on one screen,
790
866
  * and twenty faces is not the humour contract, it is a zoo. The variant carries
791
- * no face, and the type does not let one through. See `docs/decisions.md` § 27.
867
+ * no face, and the type does not let one through. See `docs/decisions/0.7.md` § 27.
792
868
  */
793
869
  type EmptyStateBase = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
794
870
  title: ReactNode;
@@ -874,18 +950,32 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
874
950
  /**
875
951
  * The footer, and the site's CLI signature: `$ cd ~/eduardoalvarez.dev/2026`.
876
952
  *
877
- * The domain comes from `naming.domain` and not from a hand-written string, for
953
+ * The domain defaults to `naming.domain` and not to a hand-written string, for
878
954
  * the same reason as the wordmark: if it changes, it changes in all five
879
- * projects at once.
955
+ * projects at once. A project that lives on its OWN domain passes `domain` —
956
+ * see `docs/decisions/0.9.md` § 49.
880
957
  *
881
958
  * The social links are icons with NO visible text, so `aria-label` is not an
882
959
  * improvement: it is the only thing that makes them legible. Which is why it is
883
960
  * mandatory in the type and not an optional prop that gets forgotten.
884
961
  *
885
- * The signature sits top right, level with the FIRST row that exists, not at the
886
- * end of the block. That is a composition decision and not a styling one: the
887
- * footer can carry brand, links and social icons, and hanging the signature off
888
- * one specific row sinks it the moment that row stops being the first.
962
+ * IT HAS TWO SHAPES, and the one that already existed is the one you get by
963
+ * passing nothing. That is not a courtesy: of the three projects that draw a
964
+ * footer, two want what was already there — `eduardoalvarez.dev` in 56 lines and
965
+ * `links` in a 64-line Astro replica — and only `cursos` wanted more. Changing
966
+ * the default would have broken the two that work to serve the one that did not.
967
+ *
968
+ * It is the third time the system answers «one component, two shapes» and the
969
+ * answer has not moved: `EmptyState` is a discriminated union where `page` is
970
+ * the default and `inline` cannot be handed a face; `Nav` takes a `size` where
971
+ * `default` is the bar it always was. Both left what was written before exactly
972
+ * where it was. See `docs/decisions/0.8.md` § 44.
973
+ *
974
+ * The union is what holds the rule up. `columns`, `description` and `action`
975
+ * exist only on `full`, and the default form cannot be handed one. As loose
976
+ * optional props they would compose into a third shape that nobody designed and
977
+ * nothing describes — a footer with columns and no description, or with a
978
+ * description and no columns, laid out by whichever branch happened to run.
889
979
  */
890
980
  type SocialLink = {
891
981
  /** What replaces the visible text. Mandatory. */
@@ -897,12 +987,40 @@ type SocialLink = {
897
987
  */
898
988
  icon: ReactNode;
899
989
  };
900
- type FooterProps = ComponentPropsWithoutRef<'footer'> & {
990
+ /** One link in a column of the full footer. */
991
+ type FooterColumnLink = {
992
+ label: ReactNode;
993
+ href: string;
994
+ /** Opens in a new tab, with the `rel` that has to go with it. */
995
+ external?: boolean | undefined;
996
+ };
997
+ /**
998
+ * A column of the full footer: a mono heading in small caps and its links.
999
+ *
1000
+ * The columns are not decoration and they are not a sitemap. Two of the three in
1001
+ * `cursos` change with who is looking — «Administración» with panel and metrics
1002
+ * for an admin, «Cuenta» with my courses and my diplomas for everybody else —
1003
+ * and a flat row of nine links cannot express that. Which is why this is data
1004
+ * the project builds and not a `children` the library walks.
1005
+ */
1006
+ type FooterColumn = {
1007
+ title: string;
1008
+ links: readonly FooterColumnLink[];
1009
+ };
1010
+ /**
1011
+ * `children` is OMITTED, and it is the point of the type rather than an
1012
+ * oversight.
1013
+ *
1014
+ * The footer used to take a row of loose text links this way — `./rss`,
1015
+ * `./aviso-legal` — and that row is what `variant="full"`'s columns replace. A
1016
+ * flat row cannot say which block a link belongs to, cannot carry a heading a
1017
+ * screen reader can jump to, and made whoever wrote the label type the `./`
1018
+ * themselves, which the columns put there. See docs/decisions/0.8.md § 47.
1019
+ */
1020
+ type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
901
1021
  social?: readonly SocialLink[];
902
1022
  /** The signature's year. */
903
1023
  year?: number;
904
- /** Text links: legal notice, RSS, sitemap. */
905
- children?: ReactNode;
906
1024
  /**
907
1025
  * The brand row: the fin and the wordmark, at the very top.
908
1026
  *
@@ -912,12 +1030,66 @@ type FooterProps = ComponentPropsWithoutRef<'footer'> & {
912
1030
  * type.
913
1031
  */
914
1032
  brand?: ReactNode;
1033
+ /**
1034
+ * Makes the domain inside the signature a link, keeping the `$`, the path and
1035
+ * the prompt's mark as text.
1036
+ *
1037
+ * Only the domain: linking the whole line would turn a prompt into a button
1038
+ * and put `cd ~/` inside the accessible name of the link. Without it the
1039
+ * signature is text, which is what it has always been.
1040
+ */
1041
+ signatureHref?: string | undefined;
1042
+ /**
1043
+ * The domain the signature prints, defaulting to the identity's own.
1044
+ *
1045
+ * It exists because the default is right for the sites that ARE
1046
+ * `eduardoalvarez.dev` and wrong for the ones that are not: `cursos` lives on
1047
+ * `cursos.eduardoalvarez.dev` and had been printing it since before this
1048
+ * component existed. Adopting the footer would have made a site sign with its
1049
+ * parent's domain — a fact, not a style, and one nothing in the type could
1050
+ * have warned about.
1051
+ *
1052
+ * It is a domain and not a whole signature: the `$`, the `cd ~/` and the year
1053
+ * are the identity's and stay the component's. See `docs/decisions/0.9.md`
1054
+ * § 49.
1055
+ */
1056
+ domain?: string | undefined;
915
1057
  };
916
- declare function Footer({ social, year, children, brand, className, ...props }: FooterProps): react.JSX.Element;
917
- type FooterLinkProps = ComponentPropsWithoutRef<'a'> & {
918
- asChild?: boolean | undefined;
919
- };
920
- declare function FooterLink({ asChild, className, ...props }: FooterLinkProps): react.JSX.Element;
1058
+ type FooterProps = FooterBase & ({
1059
+ /** The shape the library has always had: stacked rows and the signature at the top right. */
1060
+ variant?: 'default' | undefined;
1061
+ columns?: never;
1062
+ description?: never;
1063
+ action?: never;
1064
+ linkAsChild?: never;
1065
+ } | {
1066
+ /** `full`: brand and description on the left, link columns on the right, signature closing it. */
1067
+ variant: 'full';
1068
+ /** The link columns. Mandatory: without them `full` is the default form with extra steps. */
1069
+ columns: readonly FooterColumn[];
1070
+ /** One line under the brand, saying what the site is. */
1071
+ description?: ReactNode;
1072
+ /** An action under the row of icons — «Reportar un problema». Usually a tertiary button. */
1073
+ action?: ReactNode;
1074
+ /**
1075
+ * Renders the column links through the child, to plug in the framework's
1076
+ * `Link`. It receives each `href` in the Slot's `props`.
1077
+ *
1078
+ * It is § 24's rule applied where it now bites: a column turns data into
1079
+ * markup, so without a slot the only way to reach one of those links
1080
+ * from a project is to select it by structure or by a style class, and
1081
+ * neither is a contract. `Breadcrumb` and `ArticleCard` have the same
1082
+ * signature on purpose.
1083
+ *
1084
+ * It is also what a client-side transition needs: `cursos` reached for
1085
+ * it the moment its columns stopped being `<a>` tags.
1086
+ */
1087
+ linkAsChild?: ((props: {
1088
+ href: string;
1089
+ children: ReactNode;
1090
+ }) => ReactNode) | undefined;
1091
+ });
1092
+ declare function Footer({ variant, columns, description, action, linkAsChild, social, brand, year, signatureHref, domain, className, ...rest }: FooterProps): react.JSX.Element;
921
1093
 
922
1094
  /**
923
1095
  * ONE per site. It is the only piece in the system that is spent like the
@@ -1000,7 +1172,7 @@ declare function LinkRow({ name, description, icon, external, className, ...prop
1000
1172
  * everything an app shell asks for: a `~/cursos` wordmark goes in `brand`, and a
1001
1173
  * user menu or a «Entrar» button goes in `actions`. Session state does not get a
1002
1174
  * prop of its own — it is project infrastructure, which is the third clause of
1003
- * the criterion that decides what enters this library. See `docs/decisions.md`
1175
+ * the criterion that decides what enters this library. See `docs/decisions/`
1004
1176
  * § 30.
1005
1177
  */
1006
1178
  type NavProps = ComponentPropsWithoutRef<'header'> & {
@@ -1043,6 +1215,15 @@ type NavItemProps = ComponentPropsWithoutRef<'a'> & {
1043
1215
  * than it looks in a mockup. Brackets are how a terminal marks the active path,
1044
1216
  * so they say «you are here» without relying on the color being told apart. They
1045
1217
  * are `aria-hidden`, because whoever is listening already has `aria-current`.
1218
+ *
1219
+ * `children` goes through `Slottable`, and that is what makes `asChild` work at
1220
+ * all. The prompt and the brackets are the component's own nodes, so a plain
1221
+ * `Slot` saw four children where it needs one and threw «Slot failed to slot
1222
+ * onto its children» on EVERY render — the prop was declared, typed and
1223
+ * impossible to call. It passed `tsc` and it passed the build, because the shape
1224
+ * of the children is not something either one looks at. `Slottable` is Radix's
1225
+ * answer to exactly this: it marks which child the router's `Link` replaces and
1226
+ * leaves the decoration where it is. See `docs/decisions/0.8.md` § 40.
1046
1227
  */
1047
1228
  declare function NavItem({ active, asChild, className, children, ...props }: NavItemProps): react.JSX.Element;
1048
1229
 
@@ -1237,101 +1418,6 @@ type ScrollingProgressBarProps = Omit<ComponentPropsWithoutRef<'div'>, 'children
1237
1418
  };
1238
1419
  declare function ScrollingProgressBar({ target, tone, sticky, className, ...props }: ScrollingProgressBarProps): react.JSX.Element;
1239
1420
 
1240
- /**
1241
- * The blog admin's sidebar.
1242
- *
1243
- * The `▸` is put there by the component, same as `NavItem`'s `./` and the
1244
- * breadcrumb's `~`: it is the same CLI aesthetic and the same decision — the
1245
- * format is part of the piece, not a convention to be remembered. It is
1246
- * `aria-hidden`.
1247
- *
1248
- * An `icon` REPLACES it rather than joining it. Two marks before a label is one
1249
- * more than the eye needs, and the `▸` exists to say «this is a place you can
1250
- * go» — which is exactly what a section icon already says, and says better. A
1251
- * sidebar with no icons keeps the prompt, which is the reading sites' case.
1252
- *
1253
- * The footer carries the version and the branch (`v5.0.1 · main`) in the `meta`
1254
- * scale. It is not decoration: in an admin it is the first thing anyone asks
1255
- * when something looks off.
1256
- */
1257
- type SidebarItemProps = ComponentPropsWithoutRef<'a'> & {
1258
- active?: boolean | undefined;
1259
- asChild?: boolean | undefined;
1260
- /** Counter on the right: pending drafts, unused media. */
1261
- badge?: ReactNode;
1262
- /**
1263
- * The section's glyph, on the left. It REPLACES the `▸` rather than joining
1264
- * it, and it inherits `currentColor`, so it follows the item's state without
1265
- * being tinted separately.
1266
- */
1267
- icon?: ReactNode;
1268
- };
1269
- declare function SidebarItem({ active, asChild, badge, icon, className, children, ...props }: SidebarItemProps): react.JSX.Element;
1270
- /**
1271
- * A labelled block of items — «Contenido», «Alumnos», «Ventas».
1272
- *
1273
- * A panel's sidebar stops being readable somewhere around eight items, and the
1274
- * fix is not a scrollbar: it is saying what the blocks are. The label is a `<p>`
1275
- * and not a heading, because a heading here would land in the document outline
1276
- * between the page's own — a sidebar is navigation, not content.
1277
- *
1278
- * The items go in a nested `<ul>` named by that label, which is what gives a
1279
- * screen reader «lista Ventas, 3 elementos» instead of one list of eleven.
1280
- */
1281
- type SidebarGroupProps = Omit<ComponentPropsWithoutRef<'li'>, 'title'> & {
1282
- /** The block's name. Sentence case, not a section title. */
1283
- label: ReactNode;
1284
- };
1285
- declare function SidebarGroup({ label, children, className, ...props }: SidebarGroupProps): react.JSX.Element;
1286
- type SidebarNavProps = ComponentPropsWithoutRef<'nav'> & {
1287
- /**
1288
- * The panel's heading, as an eyebrow. It also names the `<nav>` when it is a
1289
- * string, which is why a `brand` row does not replace it: a logo is not an
1290
- * accessible name. Pass `aria-label` when neither fits.
1291
- */
1292
- title?: ReactNode;
1293
- /**
1294
- * The row at the top: isotype and wordmark, `cursos · admin`. It is a slot and
1295
- * not a `logo`/`name` pair because every panel spells its own name
1296
- * differently, and the part that IS the system — the rhythm, the hairline
1297
- * under it — is here.
1298
- *
1299
- * Collapsed, it is hidden: a wordmark does not fit in a rail and the component
1300
- * cannot trim somebody else's markup. Pass the isotype on its own through
1301
- * `mark` for the rail to keep something at the top.
1302
- */
1303
- brand?: ReactNode;
1304
- /** What `brand` becomes in the rail. Usually the isotype with no wordmark. */
1305
- mark?: ReactNode;
1306
- /**
1307
- * Who is signed in, at the bottom above the version. A slot, because an avatar
1308
- * needs a session and a sign-out route and the library takes no project
1309
- * infrastructure — the same reason `Nav`'s user menu goes in `actions`.
1310
- */
1311
- user?: ReactNode;
1312
- /**
1313
- * Turns the sidebar into a rail: icons only, and the widths become the
1314
- * library's — `w-sidebar` and `w-sidebar-rail`. It is CONTROLLED and there is
1315
- * no uncontrolled mode, because this state is almost always persisted in a
1316
- * cookie or in `localStorage`, and an internal state would fight the one the
1317
- * project already keeps.
1318
- */
1319
- collapsed?: boolean | undefined;
1320
- /**
1321
- * Called with what the state should become. With it, the toggle appears; with
1322
- * `collapsed` alone the sidebar is a rail with no way out of it, which is a
1323
- * legitimate layout and not an accident.
1324
- */
1325
- onCollapsedChange?: ((collapsed: boolean) => void) | undefined;
1326
- /** The toggle's accessible name, in the two directions. */
1327
- collapseLabel?: string;
1328
- expandLabel?: string;
1329
- /** Version and branch, at the bottom. */
1330
- version?: ReactNode;
1331
- branch?: ReactNode;
1332
- };
1333
- declare function SidebarNav({ title, brand, mark, user, collapsed, onCollapsedChange, collapseLabel, expandLabel, version, branch, children, className, ...props }: SidebarNavProps): react.JSX.Element;
1334
-
1335
1421
  /**
1336
1422
  * A large metric: the number in the `stat` scale and its name underneath.
1337
1423
  *
@@ -1356,7 +1442,7 @@ declare function SidebarNav({ title, brand, mark, user, collapsed, onCollapsedCh
1356
1442
  * eyebrow is the same length in none of them, so an inline icon puts the only
1357
1443
  * coloured mark on a different x in every card; pinned to the corner it lands on
1358
1444
  * a grid. The circle is the tint pattern the system already has — `bg-accent/10`
1359
- * as a surface and the colour on the GLYPH, per `docs/decisions.md` § 4b — and a
1445
+ * as a surface and the colour on the GLYPH, per `docs/decisions/0.6.md` § 4b — and a
1360
1446
  * glyph clears the 3:1 graphical threshold where text would not clear 4.5.
1361
1447
  *
1362
1448
  * WHICH IS WHY A NEUTRAL NUMBER IS PRIMARY INK AND NOT BIOLUME. With a biolume
@@ -1364,7 +1450,7 @@ declare function SidebarNav({ title, brand, mark, user, collapsed, onCollapsedCh
1364
1450
  * the size of a postcard, and the thing you came to read stops being the loudest
1365
1451
  * thing in it. `alert` and `achievement` DO still paint the number sand, so the
1366
1452
  * document's rule survives exactly where it matters: sand when the number is not
1367
- * just a number. See `docs/decisions.md` § 31.
1453
+ * just a number. See `docs/decisions/0.7.md` § 31.
1368
1454
  */
1369
1455
  type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1370
1456
  /** The number, already formatted. The library imposes no locale. */
@@ -1376,7 +1462,7 @@ type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1376
1462
  * the opposite — the diplomas issued, the modules finished. The two paint the
1377
1463
  * same sand today and they are still two names: a system that names by meaning
1378
1464
  * cannot make «this is bad» the only way to say «this stands out». See
1379
- * `docs/decisions.md` § 28.
1465
+ * `docs/decisions/0.7.md` § 28.
1380
1466
  */
1381
1467
  tone?: 'neutral' | 'alert' | 'achievement';
1382
1468
  /** With `progress`, the metric reads as progress and adds the bar. */
@@ -1562,4 +1648,4 @@ declare function TableOfContents({ items, title, activeHref, linkAsChild, classN
1562
1648
 
1563
1649
  declare function cn(...inputs: ClassValue[]): string;
1564
1650
 
1565
- export { Accordion, AccordionContent, AccordionItem, type AccordionProps, AccordionTrigger, type AccordionTriggerProps, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, type AlertProps, ArticleCard, type ArticleCardProps, AudioPlayer, type AudioPlayerMode, type AudioPlayerProps, AuthorCard, type AuthorCardProps, Avatar, AvatarFallback, AvatarImage, type AvatarProps, AvatarUpload, type AvatarUploadProps, Badge, type BadgeProps, Blockquote, type BlockquoteProps, Breadcrumb, type BreadcrumbProps, Button, type ButtonProps, Calendar, type CalendarEvent, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBadge, type CategoryBadgeProps, Checkbox, type CheckboxProps, Code, CodeBlock, type CodeBlockProps, type CodeProps, CourseCard, type CourseCardProps, type Crumb, DateField, type DateFieldProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, EventCalendar, type EventCalendarProps, Face, Footer, FooterLink, type FooterLinkProps, type FooterProps, Hero, type HeroProps, Input, type InputProps, LinkRow, type LinkRowProps, MetricBadge, type MetricBadgeProps, Nav, NavItem, type NavItemProps, type NavProps, NewsletterForm, type NewsletterFormProps, type NewsletterState, PageHeader, type PageHeaderProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, type PaginationLinkProps, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, type PopoverContentProps, PopoverTrigger, Pose, Progress, type ProgressProps, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, ScrollingProgressBar, type ScrollingProgressBarProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps, Sheet, SheetBody, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SidebarGroup, type SidebarGroupProps, SidebarItem, type SidebarItemProps, SidebarNav, type SidebarNavProps, Skeleton, type SkeletonProps, type SocialLink, Stat, type StatDelta, type StatProps, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, type TableOfContentsProps, TableRow, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, TalkCard, type TalkCardProps, Text, type TextProps, Textarea, type TextareaProps, Theme, ThemeToggle, type ThemeToggleProps, ToastAction, type ToastOptions, type ToastVariant, Toaster, type ToasterProps, type TocEntry, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alert as alertVariants, avatar as avatarVariants, badge as badgeVariants, button as buttonVariants, cn, text as textVariants, toast, useTheme };
1651
+ export { Accordion, AccordionContent, AccordionItem, type AccordionProps, AccordionTrigger, type AccordionTriggerProps, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, type AlertProps, ArticleCard, type ArticleCardProps, AudioPlayer, type AudioPlayerMode, type AudioPlayerProps, AuthorCard, type AuthorCardProps, Avatar, AvatarFallback, AvatarImage, type AvatarProps, AvatarUpload, type AvatarUploadProps, Badge, type BadgeProps, Blockquote, type BlockquoteProps, Breadcrumb, type BreadcrumbProps, Button, type ButtonProps, Calendar, type CalendarEvent, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBadge, type CategoryBadgeProps, Checkbox, type CheckboxProps, Code, CodeBlock, type CodeBlockProps, type CodeProps, CourseCard, type CourseCardProps, type Crumb, DateField, type DateFieldProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, EventCalendar, type EventCalendarProps, Face, Footer, type FooterColumn, type FooterColumnLink, type FooterProps, Hero, type HeroProps, Input, type InputProps, LinkRow, type LinkRowProps, MetricBadge, type MetricBadgeProps, Nav, NavItem, type NavItemProps, type NavProps, NewsletterForm, type NewsletterFormProps, type NewsletterState, PageHeader, type PageHeaderProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, type PaginationLinkProps, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, type PopoverContentProps, PopoverTrigger, Pose, Progress, type ProgressProps, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, ScrollingProgressBar, type ScrollingProgressBarProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps, Sheet, SheetBody, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Skeleton, type SkeletonProps, type SocialLink, Stat, type StatDelta, type StatProps, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, type TableOfContentsProps, TableRow, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, TalkCard, type TalkCardProps, Text, type TextProps, Textarea, type TextareaProps, Theme, ThemeToggle, type ThemeToggleProps, ToastAction, type ToastOptions, type ToastVariant, Toaster, type ToasterProps, type TocEntry, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alert as alertVariants, avatar as avatarVariants, badge as badgeVariants, button as buttonVariants, cn, text as textVariants, toast, useTheme };