@eduardoalvarez/arrecife 0.10.0 → 0.12.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 (42) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +44 -13
  3. package/dist/brand/index.cjs +11 -5
  4. package/dist/brand/index.d.cts +45 -6
  5. package/dist/brand/index.d.ts +45 -6
  6. package/dist/brand/index.js +3 -3
  7. package/dist/chart/index.cjs +28 -6
  8. package/dist/chart/index.d.cts +21 -5
  9. package/dist/chart/index.d.ts +21 -5
  10. package/dist/chart/index.js +29 -7
  11. package/dist/{chunk-FGFNK72B.js → chunk-5YWGOFDX.js} +17 -4
  12. package/dist/{chunk-5A5GH2PF.js → chunk-6QJQ6K7J.js} +1 -1
  13. package/dist/{chunk-TRPBID2W.js → chunk-BFYNBIVJ.js} +1 -1
  14. package/dist/{chunk-IIT3YLYN.js → chunk-BRDTB44R.js} +12 -6
  15. package/dist/{chunk-XXDATT3A.js → chunk-FF33ARRA.js} +1 -1
  16. package/dist/{chunk-FAAGZG7A.js → chunk-TMUGT3Y3.js} +1 -1
  17. package/dist/{chunk-6IGD5REB.js → chunk-W75O3Z77.js} +1 -1
  18. package/dist/{chunk-ZSCSKCTY.js → chunk-WU66TPJT.js} +1 -1
  19. package/dist/form/index.cjs +2 -2
  20. package/dist/form/index.js +4 -4
  21. package/dist/icons/index.cjs +2 -2
  22. package/dist/icons/index.d.cts +2 -2
  23. package/dist/icons/index.d.ts +2 -2
  24. package/dist/icons/index.js +3 -3
  25. package/dist/index.cjs +153 -31
  26. package/dist/index.d.cts +95 -18
  27. package/dist/index.d.ts +95 -18
  28. package/dist/index.js +141 -38
  29. package/dist/og/index.cjs +1 -2
  30. package/dist/og/index.js +1 -1
  31. package/dist/shiki/index.js +1 -1
  32. package/dist/tokens/index.cjs +17 -4
  33. package/dist/tokens/index.d.cts +20 -5
  34. package/dist/tokens/index.d.ts +20 -5
  35. package/dist/tokens/index.js +2 -2
  36. package/dist/tokens/theme.css +20 -3
  37. package/dist/variants/index.cjs +1 -1
  38. package/dist/variants/index.d.cts +2 -2
  39. package/dist/variants/index.d.ts +2 -2
  40. package/dist/variants/index.js +1 -1
  41. package/llms.txt +71 -13
  42. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -26,7 +26,7 @@ import * as ToastPrimitive from '@radix-ui/react-toast';
26
26
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
27
27
  import { F as Face, P as Pose } from './catalog-D13txprv.cjs';
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.cjs';
29
- export { Isotype, IsotypeProps, Logo, LogoProps, Mascot, MascotFace, MascotFaceProps, MascotProps } from './brand/index.cjs';
29
+ export { Isotype, IsotypeBackground, IsotypeProps, Logo, LogoProps, Mascot, MascotFace, MascotFaceProps, MascotProps } from './brand/index.cjs';
30
30
  import { ClassValue } from 'clsx';
31
31
  import '@radix-ui/react-label';
32
32
 
@@ -48,7 +48,7 @@ import '@radix-ui/react-label';
48
48
  * `--ease-standard`, so it introduces neither a new timing nor a new curve.
49
49
  * Whoever asked for less motion still sees the panel appear where it will stay.
50
50
  *
51
- * See `docs/decisions/0.6.md` § 20.
51
+ * See `docs/decisions/` § 20.
52
52
  *
53
53
  * The chevron, by contrast, rotates with no transition: `transition-standard`
54
54
  * only covers color and border, so `rotate` snaps even with the class in place.
@@ -111,7 +111,7 @@ declare function Alert({ className, variant, emphasis, title, icon, children, ..
111
111
  * «Borrar el artículo», not «Aceptar».
112
112
  *
113
113
  * `destructive` is for the destructive button that has none of that around it:
114
- * a table row, a toolbar. See `docs/decisions/0.6.md` § 21.
114
+ * a table row, a toolbar. See `docs/decisions/` § 21.
115
115
  */
116
116
  declare const AlertDialog: react.FC<AlertDialogPrimitive.AlertDialogProps>;
117
117
  declare const AlertDialogTrigger: react.ForwardRefExoticComponent<AlertDialogPrimitive.AlertDialogTriggerProps & react.RefAttributes<HTMLButtonElement>>;
@@ -497,7 +497,7 @@ declare function Switch({ className, ...props }: SwitchProps): react.JSX.Element
497
497
  * `Nav`'s `size` documents: a `rounded-none` passed from the call site does
498
498
  * nothing, silently. There is one shape on purpose — fourteen call sites wanted
499
499
  * the same one — and a second gets a prop when a second consumer exists, not
500
- * before. See `docs/decisions/0.8.md` § 39.
500
+ * before. See `docs/decisions/` § 39.
501
501
  *
502
502
  * THE `tabIndex` IS NOT DECORATION and it is not new behaviour dressed up as
503
503
  * markup. A region you can pan with a mouse has to be reachable with a keyboard
@@ -771,7 +771,7 @@ declare function AuthorCard({ name, role, src, bio, action, className, ...props
771
771
  * paths this file used to carry verbatim from the portfolio are gone with
772
772
  * `lib/glyphs.tsx`; `Play`, `Pause`, `SpeakerHigh` and `SpeakerSlash` are the
773
773
  * same symbols in Phosphor's hand, and the ±15s skips are `ArrowCounterClockwise`
774
- * and `ArrowClockwise`. See `docs/decisions/0.10.md` § 51.
774
+ * and `ArrowClockwise`. See `docs/decisions/` § 51.
775
775
  * - analytics' `trackEvent` → the `onFirstPlay` prop, which the consumer wires
776
776
  * to whatever they use. It still fires exactly once per load.
777
777
  *
@@ -869,7 +869,13 @@ type CodeBlockProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> & {
869
869
  };
870
870
  declare function CodeBlock({ children, language, copyText, className, ...props }: CodeBlockProps): react.JSX.Element;
871
871
 
872
- type CourseCardProps = Omit<CardShellProps, 'children' | 'title'> & {
872
+ /**
873
+ * `media` is left out of the shell's props because `<a>` already has an
874
+ * attribute by that name — a media query for the linked resource, a string —
875
+ * and intersected with the slot it would make the slot accept only strings.
876
+ * No browser acts on it and no project was passing it.
877
+ */
878
+ type CourseCardProps = Omit<CardShellProps, 'children' | 'title' | 'media'> & {
873
879
  title: ReactNode;
874
880
  summary?: ReactNode;
875
881
  /** Level, duration, number of lessons: whatever the project wants to list. */
@@ -881,8 +887,42 @@ type CourseCardProps = Omit<CardShellProps, 'children' | 'title'> & {
881
887
  * when passed, the bar goes in sand, which is the color of course progress.
882
888
  */
883
889
  progress?: number | undefined;
890
+ /**
891
+ * The cover, at the top and bleeding to the card's edges, with `alt=""`: the
892
+ * whole card is one link and `title` already names it.
893
+ *
894
+ * The project owns the element — an `<img>`, a framework's `Image`, a
895
+ * generated cover — and its ratio; the card clips it to its own corners. An
896
+ * `alt` that repeats the title makes a screen reader say the course twice
897
+ * before anything else.
898
+ */
899
+ media?: ReactNode;
900
+ /**
901
+ * The closing row, under `meta`: the rating, the price, whatever the project
902
+ * sells the course with. It sits at the bottom of the card, so the rows of a
903
+ * grid line up whatever the length of each summary.
904
+ */
905
+ footer?: ReactNode;
884
906
  };
885
- declare function CourseCard({ title, summary, meta, status, progress, className, ...props }: CourseCardProps): react.JSX.Element;
907
+ /**
908
+ * The course, as a card that links to it.
909
+ *
910
+ * `media` and `footer` are slots rather than props for a cover URL, a rating
911
+ * and a price, because none of those three is the identity's. The price comes
912
+ * formatted in a currency the library does not know, the rating is drawn by a
913
+ * component the project already has, and the cover is an image pipeline. What
914
+ * IS the identity's stays here: the title's scale and its hover, the sand bar,
915
+ * the status badge. See `docs/decisions/` § 59.
916
+ *
917
+ * The title does NOT go over the cover. It stays in the body at `h3`, with the
918
+ * hover every other card has. Text on a photograph needs a scrim, and a scrim's
919
+ * contrast depends on the photograph: it cannot be measured once and recorded,
920
+ * which is the only way contrast is decided in this system.
921
+ *
922
+ * And the cover does not move on hover. Rule 6 is the border and nothing else:
923
+ * no zoom, no scale, no displacement.
924
+ */
925
+ declare function CourseCard({ title, summary, meta, status, progress, media, footer, className, ...props }: CourseCardProps): react.JSX.Element;
886
926
 
887
927
  /**
888
928
  * The mascot's most important rule, finally as code.
@@ -901,7 +941,7 @@ declare function CourseCard({ title, summary, meta, status, progress, className,
901
941
  * smaller one: the hole inside a table page or a dashboard widget, competing with
902
942
  * a dozen elements around it. An admin panel has twenty of those on one screen,
903
943
  * and twenty faces is not the humour contract, it is a zoo. The variant carries
904
- * no face, and the type does not let one through. See `docs/decisions/0.7.md` § 27.
944
+ * no face, and the type does not let one through. See `docs/decisions/` § 27.
905
945
  */
906
946
  type EmptyStateBase = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
907
947
  title: ReactNode;
@@ -990,7 +1030,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
990
1030
  * The domain defaults to `naming.domain` and not to a hand-written string, for
991
1031
  * the same reason as the wordmark: if it changes, it changes in all five
992
1032
  * projects at once. A project that lives on its OWN domain passes `domain` —
993
- * see `docs/decisions/0.9.md` § 49.
1033
+ * see `docs/decisions/` § 49.
994
1034
  *
995
1035
  * The social links are icons with NO visible text, so `aria-label` is not an
996
1036
  * improvement: it is the only thing that makes them legible. Which is why it is
@@ -1006,7 +1046,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
1006
1046
  * answer has not moved: `EmptyState` is a discriminated union where `page` is
1007
1047
  * the default and `inline` cannot be handed a face; `Nav` takes a `size` where
1008
1048
  * `default` is the bar it always was. Both left what was written before exactly
1009
- * where it was. See `docs/decisions/0.8.md` § 44.
1049
+ * where it was. See `docs/decisions/` § 44.
1010
1050
  *
1011
1051
  * The union is what holds the rule up. `columns`, `description` and `action`
1012
1052
  * exist only on `full`, and the default form cannot be handed one. As loose
@@ -1054,7 +1094,7 @@ type FooterColumn = {
1054
1094
  * `./aviso-legal` — and that row is what `variant="full"`'s columns replace. A
1055
1095
  * flat row cannot say which block a link belongs to, cannot carry a heading a
1056
1096
  * screen reader can jump to, and made whoever wrote the label type the `./`
1057
- * themselves, which the columns put there. See docs/decisions/0.8.md § 47.
1097
+ * themselves, which the columns put there. See docs/decisions/ § 47.
1058
1098
  */
1059
1099
  type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1060
1100
  social?: readonly SocialLink[];
@@ -1089,10 +1129,25 @@ type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1089
1129
  * have warned about.
1090
1130
  *
1091
1131
  * It is a domain and not a whole signature: the `$`, the `cd ~/` and the year
1092
- * are the identity's and stay the component's. See `docs/decisions/0.9.md`
1132
+ * are the identity's and stay the component's. See `docs/decisions/`
1093
1133
  * § 49.
1094
1134
  */
1095
1135
  domain?: string | undefined;
1136
+ /**
1137
+ * Adds «Creado con Arrecife ♥», linking to the library's Storybook.
1138
+ *
1139
+ * OFF BY DEFAULT, and that is the decision rather than the default. No
1140
+ * consuming project credits the library today — the four were read before
1141
+ * this was written — so turning it on for everybody would be the library
1142
+ * putting a line into five production footers that none of them asked for.
1143
+ * That is the move § 45 is about, and it does not get made twice.
1144
+ *
1145
+ * A site that wants it passes `builtWith`. It is a boolean and not a slot: the
1146
+ * string and the destination are the library's, and a slot would be an
1147
+ * invitation to write «Hecho con Arrecife» on one site and «Creado con» on the
1148
+ * next, which is the drift this package exists to remove.
1149
+ */
1150
+ builtWith?: boolean | undefined;
1096
1151
  };
1097
1152
  type FooterProps = FooterBase & ({
1098
1153
  /** The shape the library has always had: stacked rows and the signature at the top right. */
@@ -1128,7 +1183,7 @@ type FooterProps = FooterBase & ({
1128
1183
  children: ReactNode;
1129
1184
  }) => ReactNode) | undefined;
1130
1185
  });
1131
- declare function Footer({ variant, columns, description, action, linkAsChild, social, brand, year, signatureHref, domain, className, ...rest }: FooterProps): react.JSX.Element;
1186
+ declare function Footer({ variant, columns, description, action, linkAsChild, social, brand, builtWith, year, signatureHref, domain, className, ...rest }: FooterProps): react.JSX.Element;
1132
1187
 
1133
1188
  /**
1134
1189
  * ONE per site. It is the only piece in the system that is spent like the
@@ -1262,7 +1317,7 @@ type NavItemProps = ComponentPropsWithoutRef<'a'> & {
1262
1317
  * impossible to call. It passed `tsc` and it passed the build, because the shape
1263
1318
  * of the children is not something either one looks at. `Slottable` is Radix's
1264
1319
  * answer to exactly this: it marks which child the router's `Link` replaces and
1265
- * leaves the decoration where it is. See `docs/decisions/0.8.md` § 40.
1320
+ * leaves the decoration where it is. See `docs/decisions/` § 40.
1266
1321
  */
1267
1322
  declare function NavItem({ active, asChild, className, children, ...props }: NavItemProps): react.JSX.Element;
1268
1323
 
@@ -1392,6 +1447,15 @@ declare function NewsletterForm({ title, description, state, onSubmitEmail, succ
1392
1447
  *
1393
1448
  * `display` for covers, `page` for section headers.
1394
1449
  *
1450
+ * The size picks the title's scale by default, and `titleVariant` lets the
1451
+ * screen pick another one. The default is the document's — «h1 44/700» on the
1452
+ * six interior pages of the reading site — and it is right there. It is not
1453
+ * right in the two admin apps: `blog-content-manager` titles its twelve screens
1454
+ * at 24px, and `cursos` titles 29 of its 32 at `h3` — every one in the panel —
1455
+ * and the other three, the public catalog pages, at `h2`. Both are rungs the
1456
+ * scale already has, and a third `size` could only have named one of them. See
1457
+ * `docs/decisions/` § 57.
1458
+ *
1395
1459
  * It takes no mascot face, at either scale: faces go in empty states,
1396
1460
  * confirmations, errors, course progress and celebration.
1397
1461
  *
@@ -1416,8 +1480,21 @@ type PageHeaderProps = Omit<ComponentPropsWithoutRef<'header'>, 'title'> & Varia
1416
1480
  action?: ReactNode | undefined;
1417
1481
  /** The headline's level. `h1` unless the page already has one. */
1418
1482
  as?: 'h1' | 'h2' | undefined;
1483
+ /**
1484
+ * The headline's scale, when the screen needs a different one from what
1485
+ * `size` gives — `display` for `display`, `h1` for `page`.
1486
+ *
1487
+ * It is the same split `Text` makes: `as` is the level, this is how big it
1488
+ * looks. A panel's `<h1>` at `h3` is still the page's only `h1`. The padding
1489
+ * stays with `size`, so a header inside a layout that already spaces its
1490
+ * content passes `className="py-0"`.
1491
+ *
1492
+ * Only the four headline scales, all in the display family. `stat` is for
1493
+ * numbers and `body` is not a headline.
1494
+ */
1495
+ titleVariant?: 'display' | 'h1' | 'h2' | 'h3' | undefined;
1419
1496
  };
1420
- declare function PageHeader({ title, eyebrow, description, action, size, as, className, ...props }: PageHeaderProps): react.JSX.Element;
1497
+ declare function PageHeader({ title, eyebrow, description, action, size, as, titleVariant, className, ...props }: PageHeaderProps): react.JSX.Element;
1421
1498
 
1422
1499
  /**
1423
1500
  * How much you have read. It is NOT `Progress` under another name.
@@ -1481,7 +1558,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1481
1558
  * eyebrow is the same length in none of them, so an inline icon puts the only
1482
1559
  * coloured mark on a different x in every card; pinned to the corner it lands on
1483
1560
  * a grid. The circle is the tint pattern the system already has — `bg-accent/10`
1484
- * as a surface and the colour on the GLYPH, per `docs/decisions/0.6.md` § 4b — and a
1561
+ * as a surface and the colour on the GLYPH, per `docs/decisions/` § 4b — and a
1485
1562
  * glyph clears the 3:1 graphical threshold where text would not clear 4.5.
1486
1563
  *
1487
1564
  * WHICH IS WHY A NEUTRAL NUMBER IS PRIMARY INK AND NOT BIOLUME. With a biolume
@@ -1489,7 +1566,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1489
1566
  * the size of a postcard, and the thing you came to read stops being the loudest
1490
1567
  * thing in it. `alert` and `achievement` DO still paint the number sand, so the
1491
1568
  * document's rule survives exactly where it matters: sand when the number is not
1492
- * just a number. See `docs/decisions/0.7.md` § 31.
1569
+ * just a number. See `docs/decisions/` § 31.
1493
1570
  */
1494
1571
  type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1495
1572
  /** The number, already formatted. The library imposes no locale. */
@@ -1501,7 +1578,7 @@ type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1501
1578
  * the opposite — the diplomas issued, the modules finished. The two paint the
1502
1579
  * same sand today and they are still two names: a system that names by meaning
1503
1580
  * cannot make «this is bad» the only way to say «this stands out». See
1504
- * `docs/decisions/0.7.md` § 28.
1581
+ * `docs/decisions/` § 28.
1505
1582
  */
1506
1583
  tone?: 'neutral' | 'alert' | 'achievement';
1507
1584
  /** With `progress`, the metric reads as progress and adds the bar. */
package/dist/index.d.ts CHANGED
@@ -26,7 +26,7 @@ import * as ToastPrimitive from '@radix-ui/react-toast';
26
26
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
27
27
  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
- export { Isotype, IsotypeProps, Logo, LogoProps, Mascot, MascotFace, MascotFaceProps, MascotProps } from './brand/index.js';
29
+ export { Isotype, IsotypeBackground, IsotypeProps, Logo, LogoProps, Mascot, MascotFace, MascotFaceProps, MascotProps } from './brand/index.js';
30
30
  import { ClassValue } from 'clsx';
31
31
  import '@radix-ui/react-label';
32
32
 
@@ -48,7 +48,7 @@ import '@radix-ui/react-label';
48
48
  * `--ease-standard`, so it introduces neither a new timing nor a new curve.
49
49
  * Whoever asked for less motion still sees the panel appear where it will stay.
50
50
  *
51
- * See `docs/decisions/0.6.md` § 20.
51
+ * See `docs/decisions/` § 20.
52
52
  *
53
53
  * The chevron, by contrast, rotates with no transition: `transition-standard`
54
54
  * only covers color and border, so `rotate` snaps even with the class in place.
@@ -111,7 +111,7 @@ declare function Alert({ className, variant, emphasis, title, icon, children, ..
111
111
  * «Borrar el artículo», not «Aceptar».
112
112
  *
113
113
  * `destructive` is for the destructive button that has none of that around it:
114
- * a table row, a toolbar. See `docs/decisions/0.6.md` § 21.
114
+ * a table row, a toolbar. See `docs/decisions/` § 21.
115
115
  */
116
116
  declare const AlertDialog: react.FC<AlertDialogPrimitive.AlertDialogProps>;
117
117
  declare const AlertDialogTrigger: react.ForwardRefExoticComponent<AlertDialogPrimitive.AlertDialogTriggerProps & react.RefAttributes<HTMLButtonElement>>;
@@ -497,7 +497,7 @@ declare function Switch({ className, ...props }: SwitchProps): react.JSX.Element
497
497
  * `Nav`'s `size` documents: a `rounded-none` passed from the call site does
498
498
  * nothing, silently. There is one shape on purpose — fourteen call sites wanted
499
499
  * the same one — and a second gets a prop when a second consumer exists, not
500
- * before. See `docs/decisions/0.8.md` § 39.
500
+ * before. See `docs/decisions/` § 39.
501
501
  *
502
502
  * THE `tabIndex` IS NOT DECORATION and it is not new behaviour dressed up as
503
503
  * markup. A region you can pan with a mouse has to be reachable with a keyboard
@@ -771,7 +771,7 @@ declare function AuthorCard({ name, role, src, bio, action, className, ...props
771
771
  * paths this file used to carry verbatim from the portfolio are gone with
772
772
  * `lib/glyphs.tsx`; `Play`, `Pause`, `SpeakerHigh` and `SpeakerSlash` are the
773
773
  * same symbols in Phosphor's hand, and the ±15s skips are `ArrowCounterClockwise`
774
- * and `ArrowClockwise`. See `docs/decisions/0.10.md` § 51.
774
+ * and `ArrowClockwise`. See `docs/decisions/` § 51.
775
775
  * - analytics' `trackEvent` → the `onFirstPlay` prop, which the consumer wires
776
776
  * to whatever they use. It still fires exactly once per load.
777
777
  *
@@ -869,7 +869,13 @@ type CodeBlockProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> & {
869
869
  };
870
870
  declare function CodeBlock({ children, language, copyText, className, ...props }: CodeBlockProps): react.JSX.Element;
871
871
 
872
- type CourseCardProps = Omit<CardShellProps, 'children' | 'title'> & {
872
+ /**
873
+ * `media` is left out of the shell's props because `<a>` already has an
874
+ * attribute by that name — a media query for the linked resource, a string —
875
+ * and intersected with the slot it would make the slot accept only strings.
876
+ * No browser acts on it and no project was passing it.
877
+ */
878
+ type CourseCardProps = Omit<CardShellProps, 'children' | 'title' | 'media'> & {
873
879
  title: ReactNode;
874
880
  summary?: ReactNode;
875
881
  /** Level, duration, number of lessons: whatever the project wants to list. */
@@ -881,8 +887,42 @@ type CourseCardProps = Omit<CardShellProps, 'children' | 'title'> & {
881
887
  * when passed, the bar goes in sand, which is the color of course progress.
882
888
  */
883
889
  progress?: number | undefined;
890
+ /**
891
+ * The cover, at the top and bleeding to the card's edges, with `alt=""`: the
892
+ * whole card is one link and `title` already names it.
893
+ *
894
+ * The project owns the element — an `<img>`, a framework's `Image`, a
895
+ * generated cover — and its ratio; the card clips it to its own corners. An
896
+ * `alt` that repeats the title makes a screen reader say the course twice
897
+ * before anything else.
898
+ */
899
+ media?: ReactNode;
900
+ /**
901
+ * The closing row, under `meta`: the rating, the price, whatever the project
902
+ * sells the course with. It sits at the bottom of the card, so the rows of a
903
+ * grid line up whatever the length of each summary.
904
+ */
905
+ footer?: ReactNode;
884
906
  };
885
- declare function CourseCard({ title, summary, meta, status, progress, className, ...props }: CourseCardProps): react.JSX.Element;
907
+ /**
908
+ * The course, as a card that links to it.
909
+ *
910
+ * `media` and `footer` are slots rather than props for a cover URL, a rating
911
+ * and a price, because none of those three is the identity's. The price comes
912
+ * formatted in a currency the library does not know, the rating is drawn by a
913
+ * component the project already has, and the cover is an image pipeline. What
914
+ * IS the identity's stays here: the title's scale and its hover, the sand bar,
915
+ * the status badge. See `docs/decisions/` § 59.
916
+ *
917
+ * The title does NOT go over the cover. It stays in the body at `h3`, with the
918
+ * hover every other card has. Text on a photograph needs a scrim, and a scrim's
919
+ * contrast depends on the photograph: it cannot be measured once and recorded,
920
+ * which is the only way contrast is decided in this system.
921
+ *
922
+ * And the cover does not move on hover. Rule 6 is the border and nothing else:
923
+ * no zoom, no scale, no displacement.
924
+ */
925
+ declare function CourseCard({ title, summary, meta, status, progress, media, footer, className, ...props }: CourseCardProps): react.JSX.Element;
886
926
 
887
927
  /**
888
928
  * The mascot's most important rule, finally as code.
@@ -901,7 +941,7 @@ declare function CourseCard({ title, summary, meta, status, progress, className,
901
941
  * smaller one: the hole inside a table page or a dashboard widget, competing with
902
942
  * a dozen elements around it. An admin panel has twenty of those on one screen,
903
943
  * and twenty faces is not the humour contract, it is a zoo. The variant carries
904
- * no face, and the type does not let one through. See `docs/decisions/0.7.md` § 27.
944
+ * no face, and the type does not let one through. See `docs/decisions/` § 27.
905
945
  */
906
946
  type EmptyStateBase = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
907
947
  title: ReactNode;
@@ -990,7 +1030,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
990
1030
  * The domain defaults to `naming.domain` and not to a hand-written string, for
991
1031
  * the same reason as the wordmark: if it changes, it changes in all five
992
1032
  * projects at once. A project that lives on its OWN domain passes `domain` —
993
- * see `docs/decisions/0.9.md` § 49.
1033
+ * see `docs/decisions/` § 49.
994
1034
  *
995
1035
  * The social links are icons with NO visible text, so `aria-label` is not an
996
1036
  * improvement: it is the only thing that makes them legible. Which is why it is
@@ -1006,7 +1046,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
1006
1046
  * answer has not moved: `EmptyState` is a discriminated union where `page` is
1007
1047
  * the default and `inline` cannot be handed a face; `Nav` takes a `size` where
1008
1048
  * `default` is the bar it always was. Both left what was written before exactly
1009
- * where it was. See `docs/decisions/0.8.md` § 44.
1049
+ * where it was. See `docs/decisions/` § 44.
1010
1050
  *
1011
1051
  * The union is what holds the rule up. `columns`, `description` and `action`
1012
1052
  * exist only on `full`, and the default form cannot be handed one. As loose
@@ -1054,7 +1094,7 @@ type FooterColumn = {
1054
1094
  * `./aviso-legal` — and that row is what `variant="full"`'s columns replace. A
1055
1095
  * flat row cannot say which block a link belongs to, cannot carry a heading a
1056
1096
  * screen reader can jump to, and made whoever wrote the label type the `./`
1057
- * themselves, which the columns put there. See docs/decisions/0.8.md § 47.
1097
+ * themselves, which the columns put there. See docs/decisions/ § 47.
1058
1098
  */
1059
1099
  type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1060
1100
  social?: readonly SocialLink[];
@@ -1089,10 +1129,25 @@ type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1089
1129
  * have warned about.
1090
1130
  *
1091
1131
  * It is a domain and not a whole signature: the `$`, the `cd ~/` and the year
1092
- * are the identity's and stay the component's. See `docs/decisions/0.9.md`
1132
+ * are the identity's and stay the component's. See `docs/decisions/`
1093
1133
  * § 49.
1094
1134
  */
1095
1135
  domain?: string | undefined;
1136
+ /**
1137
+ * Adds «Creado con Arrecife ♥», linking to the library's Storybook.
1138
+ *
1139
+ * OFF BY DEFAULT, and that is the decision rather than the default. No
1140
+ * consuming project credits the library today — the four were read before
1141
+ * this was written — so turning it on for everybody would be the library
1142
+ * putting a line into five production footers that none of them asked for.
1143
+ * That is the move § 45 is about, and it does not get made twice.
1144
+ *
1145
+ * A site that wants it passes `builtWith`. It is a boolean and not a slot: the
1146
+ * string and the destination are the library's, and a slot would be an
1147
+ * invitation to write «Hecho con Arrecife» on one site and «Creado con» on the
1148
+ * next, which is the drift this package exists to remove.
1149
+ */
1150
+ builtWith?: boolean | undefined;
1096
1151
  };
1097
1152
  type FooterProps = FooterBase & ({
1098
1153
  /** The shape the library has always had: stacked rows and the signature at the top right. */
@@ -1128,7 +1183,7 @@ type FooterProps = FooterBase & ({
1128
1183
  children: ReactNode;
1129
1184
  }) => ReactNode) | undefined;
1130
1185
  });
1131
- declare function Footer({ variant, columns, description, action, linkAsChild, social, brand, year, signatureHref, domain, className, ...rest }: FooterProps): react.JSX.Element;
1186
+ declare function Footer({ variant, columns, description, action, linkAsChild, social, brand, builtWith, year, signatureHref, domain, className, ...rest }: FooterProps): react.JSX.Element;
1132
1187
 
1133
1188
  /**
1134
1189
  * ONE per site. It is the only piece in the system that is spent like the
@@ -1262,7 +1317,7 @@ type NavItemProps = ComponentPropsWithoutRef<'a'> & {
1262
1317
  * impossible to call. It passed `tsc` and it passed the build, because the shape
1263
1318
  * of the children is not something either one looks at. `Slottable` is Radix's
1264
1319
  * answer to exactly this: it marks which child the router's `Link` replaces and
1265
- * leaves the decoration where it is. See `docs/decisions/0.8.md` § 40.
1320
+ * leaves the decoration where it is. See `docs/decisions/` § 40.
1266
1321
  */
1267
1322
  declare function NavItem({ active, asChild, className, children, ...props }: NavItemProps): react.JSX.Element;
1268
1323
 
@@ -1392,6 +1447,15 @@ declare function NewsletterForm({ title, description, state, onSubmitEmail, succ
1392
1447
  *
1393
1448
  * `display` for covers, `page` for section headers.
1394
1449
  *
1450
+ * The size picks the title's scale by default, and `titleVariant` lets the
1451
+ * screen pick another one. The default is the document's — «h1 44/700» on the
1452
+ * six interior pages of the reading site — and it is right there. It is not
1453
+ * right in the two admin apps: `blog-content-manager` titles its twelve screens
1454
+ * at 24px, and `cursos` titles 29 of its 32 at `h3` — every one in the panel —
1455
+ * and the other three, the public catalog pages, at `h2`. Both are rungs the
1456
+ * scale already has, and a third `size` could only have named one of them. See
1457
+ * `docs/decisions/` § 57.
1458
+ *
1395
1459
  * It takes no mascot face, at either scale: faces go in empty states,
1396
1460
  * confirmations, errors, course progress and celebration.
1397
1461
  *
@@ -1416,8 +1480,21 @@ type PageHeaderProps = Omit<ComponentPropsWithoutRef<'header'>, 'title'> & Varia
1416
1480
  action?: ReactNode | undefined;
1417
1481
  /** The headline's level. `h1` unless the page already has one. */
1418
1482
  as?: 'h1' | 'h2' | undefined;
1483
+ /**
1484
+ * The headline's scale, when the screen needs a different one from what
1485
+ * `size` gives — `display` for `display`, `h1` for `page`.
1486
+ *
1487
+ * It is the same split `Text` makes: `as` is the level, this is how big it
1488
+ * looks. A panel's `<h1>` at `h3` is still the page's only `h1`. The padding
1489
+ * stays with `size`, so a header inside a layout that already spaces its
1490
+ * content passes `className="py-0"`.
1491
+ *
1492
+ * Only the four headline scales, all in the display family. `stat` is for
1493
+ * numbers and `body` is not a headline.
1494
+ */
1495
+ titleVariant?: 'display' | 'h1' | 'h2' | 'h3' | undefined;
1419
1496
  };
1420
- declare function PageHeader({ title, eyebrow, description, action, size, as, className, ...props }: PageHeaderProps): react.JSX.Element;
1497
+ declare function PageHeader({ title, eyebrow, description, action, size, as, titleVariant, className, ...props }: PageHeaderProps): react.JSX.Element;
1421
1498
 
1422
1499
  /**
1423
1500
  * How much you have read. It is NOT `Progress` under another name.
@@ -1481,7 +1558,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1481
1558
  * eyebrow is the same length in none of them, so an inline icon puts the only
1482
1559
  * coloured mark on a different x in every card; pinned to the corner it lands on
1483
1560
  * a grid. The circle is the tint pattern the system already has — `bg-accent/10`
1484
- * as a surface and the colour on the GLYPH, per `docs/decisions/0.6.md` § 4b — and a
1561
+ * as a surface and the colour on the GLYPH, per `docs/decisions/` § 4b — and a
1485
1562
  * glyph clears the 3:1 graphical threshold where text would not clear 4.5.
1486
1563
  *
1487
1564
  * WHICH IS WHY A NEUTRAL NUMBER IS PRIMARY INK AND NOT BIOLUME. With a biolume
@@ -1489,7 +1566,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1489
1566
  * the size of a postcard, and the thing you came to read stops being the loudest
1490
1567
  * thing in it. `alert` and `achievement` DO still paint the number sand, so the
1491
1568
  * document's rule survives exactly where it matters: sand when the number is not
1492
- * just a number. See `docs/decisions/0.7.md` § 31.
1569
+ * just a number. See `docs/decisions/` § 31.
1493
1570
  */
1494
1571
  type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1495
1572
  /** The number, already formatted. The library imposes no locale. */
@@ -1501,7 +1578,7 @@ type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1501
1578
  * the opposite — the diplomas issued, the modules finished. The two paint the
1502
1579
  * same sand today and they are still two names: a system that names by meaning
1503
1580
  * cannot make «this is bad» the only way to say «this stands out». See
1504
- * `docs/decisions/0.7.md` § 28.
1581
+ * `docs/decisions/` § 28.
1505
1582
  */
1506
1583
  tone?: 'neutral' | 'alert' | 'achievement';
1507
1584
  /** With `progress`, the metric reads as progress and adds the bar. */