@eduardoalvarez/arrecife 0.11.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 +21 -0
  2. package/README.md +34 -14
  3. package/dist/brand/index.cjs +2 -2
  4. package/dist/brand/index.d.cts +1 -1
  5. package/dist/brand/index.d.ts +1 -1
  6. package/dist/brand/index.js +3 -3
  7. package/dist/chart/index.cjs +2 -2
  8. package/dist/chart/index.d.cts +3 -3
  9. package/dist/chart/index.d.ts +3 -3
  10. package/dist/chart/index.js +3 -3
  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-RKGKO2TW.js → chunk-BRDTB44R.js} +2 -2
  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 +81 -11
  26. package/dist/index.d.cts +31 -16
  27. package/dist/index.d.ts +31 -16
  28. package/dist/index.js +78 -21
  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 +39 -13
  42. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -209,7 +209,7 @@ var typeScale = {
209
209
  * (plankton 5.57:1 over abyss), which is the part that is not negotiable.
210
210
  *
211
211
  * At 13 the three badge families grew past the size of a small button and
212
- * outweighed the title they accompany. See `docs/decisions/`.
212
+ * outweighed the title they accompany. See `docs/decisions/` § 10.
213
213
  */
214
214
  chip: { family: "mono", size: 11.5, lineHeight: 1.4, weight: 400 },
215
215
  /**
@@ -263,7 +263,7 @@ var control = {
263
263
  * baseline; 28 would have been a fifth height that matches nothing.
264
264
  *
265
265
  * It does not replace `icon`. A page's primary action stays at 42; this is for
266
- * a row of a table. See `docs/decisions/0.6.md` § 22.
266
+ * a row of a table. See `docs/decisions/` § 22.
267
267
  */
268
268
  iconSm: 32
269
269
  };
@@ -286,7 +286,7 @@ var size = {
286
286
  * together eat the top of the content area. 56 is what `cursos` had arrived at
287
287
  * on its own, and it is the same reasoning as `control.iconSm`: the one admin
288
288
  * app of the five is denser than the four reading sites. See
289
- * `docs/decisions/0.7.md` § 30.
289
+ * `docs/decisions/` § 30.
290
290
  */
291
291
  navCompact: 56,
292
292
  /**
@@ -359,7 +359,20 @@ var naming = {
359
359
  wordmark: "Eduardo \xC1lvarez",
360
360
  mascot: "Tiburonc\xEDn",
361
361
  /** The domain, for the footer CLI signature: `$ cd ~/eduardoalvarez.dev/2026`. */
362
- domain: "eduardoalvarez.dev"
362
+ domain: "eduardoalvarez.dev",
363
+ /** The library's own name, for a footer that credits it. */
364
+ library: "Arrecife",
365
+ /**
366
+ * Where the library is published, for `Footer builtWith`.
367
+ *
368
+ * It is here and not written into the component for the reason the domain is:
369
+ * one string, five projects. It is the same URL as `homepage` in
370
+ * `package.json` and it cannot be derived from it — this file imports nothing
371
+ * — so `check:exports` compares the two on every build. Without that, moving
372
+ * the Storybook would update what npm prints and leave five production
373
+ * footers linking at the old address.
374
+ */
375
+ libraryUrl: "https://arrecife.eduardoalvarez.dev"
363
376
  };
364
377
 
365
378
  // src/tokens/index.ts
@@ -484,7 +497,7 @@ var button = classVarianceAuthority.cva(
484
497
  ],
485
498
  // The one control whose focus ring is not biolume. It is the system's
486
499
  // only sand fill, and a biolume ring three pixels off a sand button puts
487
- // both of the brand's accents in the same glance. See `docs/decisions/0.7.md` § 37.
500
+ // both of the brand's accents in the same glance. See `docs/decisions/` § 37.
488
501
  conversion: "bg-warm text-warm-on hover:bg-warm-hover focus-ring-warm",
489
502
  secondary: [
490
503
  "border-hairline-hover border bg-transparent text-text-primary",
@@ -3240,8 +3253,7 @@ function SocialRow({ social }) {
3240
3253
  function Signature({
3241
3254
  year,
3242
3255
  href,
3243
- domain: domainName = naming.domain,
3244
- className
3256
+ domain: domainName = naming.domain
3245
3257
  }) {
3246
3258
  const domain = href ? /* @__PURE__ */ jsxRuntime.jsx(
3247
3259
  "a",
@@ -3251,7 +3263,7 @@ function Signature({
3251
3263
  children: domainName
3252
3264
  }
3253
3265
  ) : domainName;
3254
- return /* @__PURE__ */ jsxRuntime.jsxs(Text, { variant: "meta", tone: "muted", as: "p", className: cn("shrink-0", className), children: [
3266
+ return /* @__PURE__ */ jsxRuntime.jsxs(Text, { variant: "meta", tone: "muted", as: "p", children: [
3255
3267
  /* @__PURE__ */ jsxRuntime.jsxs("span", { "aria-hidden": "true", className: "text-accent", children: [
3256
3268
  "$",
3257
3269
  " "
@@ -3269,6 +3281,46 @@ function Signature({
3269
3281
  )
3270
3282
  ] });
3271
3283
  }
3284
+ function BuiltWith() {
3285
+ return /* @__PURE__ */ jsxRuntime.jsxs(Text, { variant: "meta", tone: "muted", as: "p", children: [
3286
+ "Creado con",
3287
+ " ",
3288
+ /* @__PURE__ */ jsxRuntime.jsx(
3289
+ "a",
3290
+ {
3291
+ href: naming.libraryUrl,
3292
+ target: "_blank",
3293
+ rel: "noopener noreferrer",
3294
+ className: cn(
3295
+ "text-accent hover:text-text-primary transition-standard cursor-pointer",
3296
+ "underline decoration-1 underline-offset-4",
3297
+ "rounded-chip focus-ring"
3298
+ ),
3299
+ children: naming.library
3300
+ }
3301
+ ),
3302
+ " ",
3303
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { as: react.Heart, tone: "current", className: "text-accent inline align-middle" })
3304
+ ] });
3305
+ }
3306
+ function SignatureBlock({
3307
+ year,
3308
+ href,
3309
+ domain,
3310
+ builtWith,
3311
+ className
3312
+ }) {
3313
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3314
+ "div",
3315
+ {
3316
+ className: cn("gap-step-xs flex shrink-0 flex-col items-center sm:items-end", className),
3317
+ children: [
3318
+ /* @__PURE__ */ jsxRuntime.jsx(Signature, { year, href, domain }),
3319
+ builtWith ? /* @__PURE__ */ jsxRuntime.jsx(BuiltWith, {}) : null
3320
+ ]
3321
+ }
3322
+ );
3323
+ }
3272
3324
  function Shell({
3273
3325
  className,
3274
3326
  contentClassName,
@@ -3291,6 +3343,7 @@ function Footer({
3291
3343
  linkAsChild,
3292
3344
  social,
3293
3345
  brand: brand2,
3346
+ builtWith,
3294
3347
  year = (/* @__PURE__ */ new Date()).getFullYear(),
3295
3348
  signatureHref,
3296
3349
  domain,
@@ -3340,7 +3393,15 @@ function Footer({
3340
3393
  column.title
3341
3394
  )) })
3342
3395
  ] }),
3343
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-hairline mt-step-xl pt-step-lg border-t", children: /* @__PURE__ */ jsxRuntime.jsx(Signature, { year, href: signatureHref, domain, className: "text-center sm:text-right" }) })
3396
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-hairline mt-step-xl pt-step-lg border-t", children: /* @__PURE__ */ jsxRuntime.jsx(
3397
+ SignatureBlock,
3398
+ {
3399
+ year,
3400
+ href: signatureHref,
3401
+ domain,
3402
+ builtWith
3403
+ }
3404
+ ) })
3344
3405
  ] });
3345
3406
  }
3346
3407
  const rows = [
@@ -3351,7 +3412,16 @@ function Footer({
3351
3412
  return /* @__PURE__ */ jsxRuntime.jsxs(Shell, { className, contentClassName: "gap-step-lg", ...rest, children: [
3352
3413
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gap-step-md flex flex-col items-center sm:flex-row sm:flex-wrap", children: [
3353
3414
  first ?? null,
3354
- /* @__PURE__ */ jsxRuntime.jsx(Signature, { year, href: signatureHref, domain, className: "sm:ml-auto" })
3415
+ /* @__PURE__ */ jsxRuntime.jsx(
3416
+ SignatureBlock,
3417
+ {
3418
+ year,
3419
+ href: signatureHref,
3420
+ domain,
3421
+ builtWith,
3422
+ className: "sm:ml-auto"
3423
+ }
3424
+ )
3355
3425
  ] }),
3356
3426
  others
3357
3427
  ] });
@@ -3502,7 +3572,7 @@ function Nav({ brand: brand2, children, actions, size: size2 = "default", classN
3502
3572
  puts it in `actions`. A `Nav` that hid its own items would leave every
3503
3573
  consumer without a drawer with no navigation at all, silently.
3504
3574
 
3505
- See `docs/decisions/0.10.md` § 54.
3575
+ See `docs/decisions/` § 54.
3506
3576
  */
3507
3577
  /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Principal", className: "ml-auto min-w-0 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "gap-step-md flex w-max items-center", children: [
3508
3578
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "text-text-muted font-mono text-meta select-none", children: "~/" }),
package/dist/index.d.cts CHANGED
@@ -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
  *
@@ -912,7 +912,7 @@ type CourseCardProps = Omit<CardShellProps, 'children' | 'title' | 'media'> & {
912
912
  * formatted in a currency the library does not know, the rating is drawn by a
913
913
  * component the project already has, and the cover is an image pipeline. What
914
914
  * IS the identity's stays here: the title's scale and its hover, the sand bar,
915
- * the status badge. See `docs/decisions/0.11.md` § 59.
915
+ * the status badge. See `docs/decisions/` § 59.
916
916
  *
917
917
  * The title does NOT go over the cover. It stays in the body at `h3`, with the
918
918
  * hover every other card has. Text on a photograph needs a scrim, and a scrim's
@@ -941,7 +941,7 @@ declare function CourseCard({ title, summary, meta, status, progress, media, foo
941
941
  * smaller one: the hole inside a table page or a dashboard widget, competing with
942
942
  * a dozen elements around it. An admin panel has twenty of those on one screen,
943
943
  * and twenty faces is not the humour contract, it is a zoo. The variant carries
944
- * 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.
945
945
  */
946
946
  type EmptyStateBase = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
947
947
  title: ReactNode;
@@ -1030,7 +1030,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
1030
1030
  * The domain defaults to `naming.domain` and not to a hand-written string, for
1031
1031
  * the same reason as the wordmark: if it changes, it changes in all five
1032
1032
  * projects at once. A project that lives on its OWN domain passes `domain` —
1033
- * see `docs/decisions/0.9.md` § 49.
1033
+ * see `docs/decisions/` § 49.
1034
1034
  *
1035
1035
  * The social links are icons with NO visible text, so `aria-label` is not an
1036
1036
  * improvement: it is the only thing that makes them legible. Which is why it is
@@ -1046,7 +1046,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
1046
1046
  * answer has not moved: `EmptyState` is a discriminated union where `page` is
1047
1047
  * the default and `inline` cannot be handed a face; `Nav` takes a `size` where
1048
1048
  * `default` is the bar it always was. Both left what was written before exactly
1049
- * where it was. See `docs/decisions/0.8.md` § 44.
1049
+ * where it was. See `docs/decisions/` § 44.
1050
1050
  *
1051
1051
  * The union is what holds the rule up. `columns`, `description` and `action`
1052
1052
  * exist only on `full`, and the default form cannot be handed one. As loose
@@ -1094,7 +1094,7 @@ type FooterColumn = {
1094
1094
  * `./aviso-legal` — and that row is what `variant="full"`'s columns replace. A
1095
1095
  * flat row cannot say which block a link belongs to, cannot carry a heading a
1096
1096
  * screen reader can jump to, and made whoever wrote the label type the `./`
1097
- * themselves, which the columns put there. See docs/decisions/0.8.md § 47.
1097
+ * themselves, which the columns put there. See docs/decisions/ § 47.
1098
1098
  */
1099
1099
  type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1100
1100
  social?: readonly SocialLink[];
@@ -1129,10 +1129,25 @@ type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1129
1129
  * have warned about.
1130
1130
  *
1131
1131
  * It is a domain and not a whole signature: the `$`, the `cd ~/` and the year
1132
- * 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/`
1133
1133
  * § 49.
1134
1134
  */
1135
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;
1136
1151
  };
1137
1152
  type FooterProps = FooterBase & ({
1138
1153
  /** The shape the library has always had: stacked rows and the signature at the top right. */
@@ -1168,7 +1183,7 @@ type FooterProps = FooterBase & ({
1168
1183
  children: ReactNode;
1169
1184
  }) => ReactNode) | undefined;
1170
1185
  });
1171
- 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;
1172
1187
 
1173
1188
  /**
1174
1189
  * ONE per site. It is the only piece in the system that is spent like the
@@ -1302,7 +1317,7 @@ type NavItemProps = ComponentPropsWithoutRef<'a'> & {
1302
1317
  * impossible to call. It passed `tsc` and it passed the build, because the shape
1303
1318
  * of the children is not something either one looks at. `Slottable` is Radix's
1304
1319
  * answer to exactly this: it marks which child the router's `Link` replaces and
1305
- * leaves the decoration where it is. See `docs/decisions/0.8.md` § 40.
1320
+ * leaves the decoration where it is. See `docs/decisions/` § 40.
1306
1321
  */
1307
1322
  declare function NavItem({ active, asChild, className, children, ...props }: NavItemProps): react.JSX.Element;
1308
1323
 
@@ -1439,7 +1454,7 @@ declare function NewsletterForm({ title, description, state, onSubmitEmail, succ
1439
1454
  * at 24px, and `cursos` titles 29 of its 32 at `h3` — every one in the panel —
1440
1455
  * and the other three, the public catalog pages, at `h2`. Both are rungs the
1441
1456
  * scale already has, and a third `size` could only have named one of them. See
1442
- * `docs/decisions/0.11.md` § 57.
1457
+ * `docs/decisions/` § 57.
1443
1458
  *
1444
1459
  * It takes no mascot face, at either scale: faces go in empty states,
1445
1460
  * confirmations, errors, course progress and celebration.
@@ -1543,7 +1558,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1543
1558
  * eyebrow is the same length in none of them, so an inline icon puts the only
1544
1559
  * coloured mark on a different x in every card; pinned to the corner it lands on
1545
1560
  * a grid. The circle is the tint pattern the system already has — `bg-accent/10`
1546
- * 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
1547
1562
  * glyph clears the 3:1 graphical threshold where text would not clear 4.5.
1548
1563
  *
1549
1564
  * WHICH IS WHY A NEUTRAL NUMBER IS PRIMARY INK AND NOT BIOLUME. With a biolume
@@ -1551,7 +1566,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1551
1566
  * the size of a postcard, and the thing you came to read stops being the loudest
1552
1567
  * thing in it. `alert` and `achievement` DO still paint the number sand, so the
1553
1568
  * document's rule survives exactly where it matters: sand when the number is not
1554
- * just a number. See `docs/decisions/0.7.md` § 31.
1569
+ * just a number. See `docs/decisions/` § 31.
1555
1570
  */
1556
1571
  type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1557
1572
  /** The number, already formatted. The library imposes no locale. */
@@ -1563,7 +1578,7 @@ type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1563
1578
  * the opposite — the diplomas issued, the modules finished. The two paint the
1564
1579
  * same sand today and they are still two names: a system that names by meaning
1565
1580
  * cannot make «this is bad» the only way to say «this stands out». See
1566
- * `docs/decisions/0.7.md` § 28.
1581
+ * `docs/decisions/` § 28.
1567
1582
  */
1568
1583
  tone?: 'neutral' | 'alert' | 'achievement';
1569
1584
  /** With `progress`, the metric reads as progress and adds the bar. */
package/dist/index.d.ts CHANGED
@@ -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
  *
@@ -912,7 +912,7 @@ type CourseCardProps = Omit<CardShellProps, 'children' | 'title' | 'media'> & {
912
912
  * formatted in a currency the library does not know, the rating is drawn by a
913
913
  * component the project already has, and the cover is an image pipeline. What
914
914
  * IS the identity's stays here: the title's scale and its hover, the sand bar,
915
- * the status badge. See `docs/decisions/0.11.md` § 59.
915
+ * the status badge. See `docs/decisions/` § 59.
916
916
  *
917
917
  * The title does NOT go over the cover. It stays in the body at `h3`, with the
918
918
  * hover every other card has. Text on a photograph needs a scrim, and a scrim's
@@ -941,7 +941,7 @@ declare function CourseCard({ title, summary, meta, status, progress, media, foo
941
941
  * smaller one: the hole inside a table page or a dashboard widget, competing with
942
942
  * a dozen elements around it. An admin panel has twenty of those on one screen,
943
943
  * and twenty faces is not the humour contract, it is a zoo. The variant carries
944
- * 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.
945
945
  */
946
946
  type EmptyStateBase = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
947
947
  title: ReactNode;
@@ -1030,7 +1030,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
1030
1030
  * The domain defaults to `naming.domain` and not to a hand-written string, for
1031
1031
  * the same reason as the wordmark: if it changes, it changes in all five
1032
1032
  * projects at once. A project that lives on its OWN domain passes `domain` —
1033
- * see `docs/decisions/0.9.md` § 49.
1033
+ * see `docs/decisions/` § 49.
1034
1034
  *
1035
1035
  * The social links are icons with NO visible text, so `aria-label` is not an
1036
1036
  * improvement: it is the only thing that makes them legible. Which is why it is
@@ -1046,7 +1046,7 @@ declare function EventCalendar({ events, onCreateEvent, onUpdateEvent, onDeleteE
1046
1046
  * answer has not moved: `EmptyState` is a discriminated union where `page` is
1047
1047
  * the default and `inline` cannot be handed a face; `Nav` takes a `size` where
1048
1048
  * `default` is the bar it always was. Both left what was written before exactly
1049
- * where it was. See `docs/decisions/0.8.md` § 44.
1049
+ * where it was. See `docs/decisions/` § 44.
1050
1050
  *
1051
1051
  * The union is what holds the rule up. `columns`, `description` and `action`
1052
1052
  * exist only on `full`, and the default form cannot be handed one. As loose
@@ -1094,7 +1094,7 @@ type FooterColumn = {
1094
1094
  * `./aviso-legal` — and that row is what `variant="full"`'s columns replace. A
1095
1095
  * flat row cannot say which block a link belongs to, cannot carry a heading a
1096
1096
  * screen reader can jump to, and made whoever wrote the label type the `./`
1097
- * themselves, which the columns put there. See docs/decisions/0.8.md § 47.
1097
+ * themselves, which the columns put there. See docs/decisions/ § 47.
1098
1098
  */
1099
1099
  type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1100
1100
  social?: readonly SocialLink[];
@@ -1129,10 +1129,25 @@ type FooterBase = Omit<ComponentPropsWithoutRef<'footer'>, 'children'> & {
1129
1129
  * have warned about.
1130
1130
  *
1131
1131
  * It is a domain and not a whole signature: the `$`, the `cd ~/` and the year
1132
- * 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/`
1133
1133
  * § 49.
1134
1134
  */
1135
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;
1136
1151
  };
1137
1152
  type FooterProps = FooterBase & ({
1138
1153
  /** The shape the library has always had: stacked rows and the signature at the top right. */
@@ -1168,7 +1183,7 @@ type FooterProps = FooterBase & ({
1168
1183
  children: ReactNode;
1169
1184
  }) => ReactNode) | undefined;
1170
1185
  });
1171
- 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;
1172
1187
 
1173
1188
  /**
1174
1189
  * ONE per site. It is the only piece in the system that is spent like the
@@ -1302,7 +1317,7 @@ type NavItemProps = ComponentPropsWithoutRef<'a'> & {
1302
1317
  * impossible to call. It passed `tsc` and it passed the build, because the shape
1303
1318
  * of the children is not something either one looks at. `Slottable` is Radix's
1304
1319
  * answer to exactly this: it marks which child the router's `Link` replaces and
1305
- * leaves the decoration where it is. See `docs/decisions/0.8.md` § 40.
1320
+ * leaves the decoration where it is. See `docs/decisions/` § 40.
1306
1321
  */
1307
1322
  declare function NavItem({ active, asChild, className, children, ...props }: NavItemProps): react.JSX.Element;
1308
1323
 
@@ -1439,7 +1454,7 @@ declare function NewsletterForm({ title, description, state, onSubmitEmail, succ
1439
1454
  * at 24px, and `cursos` titles 29 of its 32 at `h3` — every one in the panel —
1440
1455
  * and the other three, the public catalog pages, at `h2`. Both are rungs the
1441
1456
  * scale already has, and a third `size` could only have named one of them. See
1442
- * `docs/decisions/0.11.md` § 57.
1457
+ * `docs/decisions/` § 57.
1443
1458
  *
1444
1459
  * It takes no mascot face, at either scale: faces go in empty states,
1445
1460
  * confirmations, errors, course progress and celebration.
@@ -1543,7 +1558,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1543
1558
  * eyebrow is the same length in none of them, so an inline icon puts the only
1544
1559
  * coloured mark on a different x in every card; pinned to the corner it lands on
1545
1560
  * a grid. The circle is the tint pattern the system already has — `bg-accent/10`
1546
- * 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
1547
1562
  * glyph clears the 3:1 graphical threshold where text would not clear 4.5.
1548
1563
  *
1549
1564
  * WHICH IS WHY A NEUTRAL NUMBER IS PRIMARY INK AND NOT BIOLUME. With a biolume
@@ -1551,7 +1566,7 @@ declare function ScrollingProgressBar({ target, tone, sticky, className, ...prop
1551
1566
  * the size of a postcard, and the thing you came to read stops being the loudest
1552
1567
  * thing in it. `alert` and `achievement` DO still paint the number sand, so the
1553
1568
  * document's rule survives exactly where it matters: sand when the number is not
1554
- * just a number. See `docs/decisions/0.7.md` § 31.
1569
+ * just a number. See `docs/decisions/` § 31.
1555
1570
  */
1556
1571
  type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1557
1572
  /** The number, already formatted. The library imposes no locale. */
@@ -1563,7 +1578,7 @@ type StatProps = Omit<ComponentPropsWithoutRef<'div'>, 'title'> & {
1563
1578
  * the opposite — the diplomas issued, the modules finished. The two paint the
1564
1579
  * same sand today and they are still two names: a system that names by meaning
1565
1580
  * cannot make «this is bad» the only way to say «this stands out». See
1566
- * `docs/decisions/0.7.md` § 28.
1581
+ * `docs/decisions/` § 28.
1567
1582
  */
1568
1583
  tone?: 'neutral' | 'alert' | 'achievement';
1569
1584
  /** With `progress`, the metric reads as progress and adds the bar. */
package/dist/index.js CHANGED
@@ -1,23 +1,23 @@
1
1
  'use client';
2
- import { Label } from './chunk-6IGD5REB.js';
3
- export { Label } from './chunk-6IGD5REB.js';
4
- import { Text } from './chunk-TRPBID2W.js';
5
- export { Text } from './chunk-TRPBID2W.js';
6
- export { tokens } from './chunk-5A5GH2PF.js';
2
+ import { Label } from './chunk-W75O3Z77.js';
3
+ export { Label } from './chunk-W75O3Z77.js';
4
+ import { Text } from './chunk-BFYNBIVJ.js';
5
+ export { Text } from './chunk-BFYNBIVJ.js';
6
+ export { tokens } from './chunk-6QJQ6K7J.js';
7
7
  import { toggleTheme, currentTheme, watchTheme } from './chunk-GCRII2KQ.js';
8
8
  export { THEME_ATTRIBUTE, THEME_EVENT, THEME_KEY, applyTheme, currentTheme, preferredTheme, storedTheme, themeScript, toggleTheme, watchTheme } from './chunk-GCRII2KQ.js';
9
- import { alert, button, avatar, badge, category, metric, CARD_SURFACE, CARD } from './chunk-XXDATT3A.js';
10
- export { CARD, CARD_HOVER, CARD_SURFACE, alert as alertVariants, avatar as avatarVariants, badge as badgeVariants, button as buttonVariants, category as categoryBadgeVariants, metric as metricBadgeVariants } from './chunk-XXDATT3A.js';
9
+ import { alert, button, avatar, badge, category, metric, CARD_SURFACE, CARD } from './chunk-FF33ARRA.js';
10
+ export { CARD, CARD_HOVER, CARD_SURFACE, alert as alertVariants, avatar as avatarVariants, badge as badgeVariants, button as buttonVariants, category as categoryBadgeVariants, metric as metricBadgeVariants } from './chunk-FF33ARRA.js';
11
11
  export { text as textVariants } from './chunk-ODBFN44D.js';
12
- import { MascotFace, Mascot } from './chunk-RKGKO2TW.js';
13
- export { Isotype, Logo, Mascot, MascotFace } from './chunk-RKGKO2TW.js';
14
- import { Icon } from './chunk-ZSCSKCTY.js';
15
- import { cn } from './chunk-FAAGZG7A.js';
16
- export { cn } from './chunk-FAAGZG7A.js';
12
+ import { MascotFace, Mascot } from './chunk-BRDTB44R.js';
13
+ export { Isotype, Logo, Mascot, MascotFace } from './chunk-BRDTB44R.js';
14
+ import { Icon } from './chunk-WU66TPJT.js';
15
+ import { cn } from './chunk-TMUGT3Y3.js';
16
+ export { cn } from './chunk-TMUGT3Y3.js';
17
17
  export { ASSETS_PATH, faceList, faceUsage, faces, fins, poseList, poses } from './chunk-CKRSQPTX.js';
18
- import { naming } from './chunk-FGFNK72B.js';
19
- export { brand, colors, control, dark, fonts, gradient, light, limits, motion, naming, radius, series, shadow, size, spacing, syntax, tagline, typeScale } from './chunk-FGFNK72B.js';
20
- import { CaretDown, XCircle, Warning, CheckCircle, Info, Camera, CircleNotch, CaretLeft, CaretRight, Minus, Check, X, DotsThree, CaretUp, Copy, ArrowUpRight, TrendDown, TrendUp, Sun, Moon, WarningCircle, Waveform, ArrowCounterClockwise, ArrowClockwise, SpeakerSlash, SpeakerHigh, ArrowsClockwise, Pause, Play } from '@phosphor-icons/react';
18
+ import { naming } from './chunk-5YWGOFDX.js';
19
+ export { brand, colors, control, dark, fonts, gradient, light, limits, motion, naming, radius, series, shadow, size, spacing, syntax, tagline, typeScale } from './chunk-5YWGOFDX.js';
20
+ import { CaretDown, XCircle, Warning, CheckCircle, Info, Camera, CircleNotch, CaretLeft, CaretRight, Minus, Check, X, DotsThree, CaretUp, Copy, ArrowUpRight, TrendDown, TrendUp, Sun, Moon, WarningCircle, Waveform, ArrowCounterClockwise, ArrowClockwise, SpeakerSlash, SpeakerHigh, ArrowsClockwise, Pause, Play, Heart } from '@phosphor-icons/react';
21
21
  import * as AccordionPrimitive from '@radix-ui/react-accordion';
22
22
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
23
23
  import { cva } from 'class-variance-authority';
@@ -2478,8 +2478,7 @@ function SocialRow({ social }) {
2478
2478
  function Signature({
2479
2479
  year,
2480
2480
  href,
2481
- domain: domainName = naming.domain,
2482
- className
2481
+ domain: domainName = naming.domain
2483
2482
  }) {
2484
2483
  const domain = href ? /* @__PURE__ */ jsx(
2485
2484
  "a",
@@ -2489,7 +2488,7 @@ function Signature({
2489
2488
  children: domainName
2490
2489
  }
2491
2490
  ) : domainName;
2492
- return /* @__PURE__ */ jsxs(Text, { variant: "meta", tone: "muted", as: "p", className: cn("shrink-0", className), children: [
2491
+ return /* @__PURE__ */ jsxs(Text, { variant: "meta", tone: "muted", as: "p", children: [
2493
2492
  /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "text-accent", children: [
2494
2493
  "$",
2495
2494
  " "
@@ -2507,6 +2506,46 @@ function Signature({
2507
2506
  )
2508
2507
  ] });
2509
2508
  }
2509
+ function BuiltWith() {
2510
+ return /* @__PURE__ */ jsxs(Text, { variant: "meta", tone: "muted", as: "p", children: [
2511
+ "Creado con",
2512
+ " ",
2513
+ /* @__PURE__ */ jsx(
2514
+ "a",
2515
+ {
2516
+ href: naming.libraryUrl,
2517
+ target: "_blank",
2518
+ rel: "noopener noreferrer",
2519
+ className: cn(
2520
+ "text-accent hover:text-text-primary transition-standard cursor-pointer",
2521
+ "underline decoration-1 underline-offset-4",
2522
+ "rounded-chip focus-ring"
2523
+ ),
2524
+ children: naming.library
2525
+ }
2526
+ ),
2527
+ " ",
2528
+ /* @__PURE__ */ jsx(Icon, { as: Heart, tone: "current", className: "text-accent inline align-middle" })
2529
+ ] });
2530
+ }
2531
+ function SignatureBlock({
2532
+ year,
2533
+ href,
2534
+ domain,
2535
+ builtWith,
2536
+ className
2537
+ }) {
2538
+ return /* @__PURE__ */ jsxs(
2539
+ "div",
2540
+ {
2541
+ className: cn("gap-step-xs flex shrink-0 flex-col items-center sm:items-end", className),
2542
+ children: [
2543
+ /* @__PURE__ */ jsx(Signature, { year, href, domain }),
2544
+ builtWith ? /* @__PURE__ */ jsx(BuiltWith, {}) : null
2545
+ ]
2546
+ }
2547
+ );
2548
+ }
2510
2549
  function Shell({
2511
2550
  className,
2512
2551
  contentClassName,
@@ -2529,6 +2568,7 @@ function Footer({
2529
2568
  linkAsChild,
2530
2569
  social,
2531
2570
  brand: brand2,
2571
+ builtWith,
2532
2572
  year = (/* @__PURE__ */ new Date()).getFullYear(),
2533
2573
  signatureHref,
2534
2574
  domain,
@@ -2578,7 +2618,15 @@ function Footer({
2578
2618
  column.title
2579
2619
  )) })
2580
2620
  ] }),
2581
- /* @__PURE__ */ jsx("div", { className: "border-hairline mt-step-xl pt-step-lg border-t", children: /* @__PURE__ */ jsx(Signature, { year, href: signatureHref, domain, className: "text-center sm:text-right" }) })
2621
+ /* @__PURE__ */ jsx("div", { className: "border-hairline mt-step-xl pt-step-lg border-t", children: /* @__PURE__ */ jsx(
2622
+ SignatureBlock,
2623
+ {
2624
+ year,
2625
+ href: signatureHref,
2626
+ domain,
2627
+ builtWith
2628
+ }
2629
+ ) })
2582
2630
  ] });
2583
2631
  }
2584
2632
  const rows = [
@@ -2589,7 +2637,16 @@ function Footer({
2589
2637
  return /* @__PURE__ */ jsxs(Shell, { className, contentClassName: "gap-step-lg", ...rest, children: [
2590
2638
  /* @__PURE__ */ jsxs("div", { className: "gap-step-md flex flex-col items-center sm:flex-row sm:flex-wrap", children: [
2591
2639
  first ?? null,
2592
- /* @__PURE__ */ jsx(Signature, { year, href: signatureHref, domain, className: "sm:ml-auto" })
2640
+ /* @__PURE__ */ jsx(
2641
+ SignatureBlock,
2642
+ {
2643
+ year,
2644
+ href: signatureHref,
2645
+ domain,
2646
+ builtWith,
2647
+ className: "sm:ml-auto"
2648
+ }
2649
+ )
2593
2650
  ] }),
2594
2651
  others
2595
2652
  ] });
@@ -2740,7 +2797,7 @@ function Nav({ brand: brand2, children, actions, size: size2 = "default", classN
2740
2797
  puts it in `actions`. A `Nav` that hid its own items would leave every
2741
2798
  consumer without a drawer with no navigation at all, silently.
2742
2799
 
2743
- See `docs/decisions/0.10.md` § 54.
2800
+ See `docs/decisions/` § 54.
2744
2801
  */
2745
2802
  /* @__PURE__ */ jsx("nav", { "aria-label": "Principal", className: "ml-auto min-w-0 overflow-x-auto", children: /* @__PURE__ */ jsxs("ul", { className: "gap-step-md flex w-max items-center", children: [
2746
2803
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-text-muted font-mono text-meta select-none", children: "~/" }),
package/dist/og/index.cjs CHANGED
@@ -74,8 +74,7 @@ var tagline = {
74
74
  var naming = {
75
75
  wordmark: "Eduardo \xC1lvarez",
76
76
  /** The domain, for the footer CLI signature: `$ cd ~/eduardoalvarez.dev/2026`. */
77
- domain: "eduardoalvarez.dev"
78
- };
77
+ domain: "eduardoalvarez.dev"};
79
78
 
80
79
  // src/og/templates.ts
81
80
  var OG = {