@krizaka/ui 3.52.0 → 3.53.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.
- package/dist/action-bar.js +1 -1
- package/dist/argument-card.js +2 -2
- package/dist/blocks.css +108 -0
- package/dist/chapter.d.ts +89 -0
- package/dist/chapter.js +123 -0
- package/dist/chapter.js.map +1 -0
- package/dist/choice-grid.js +1 -1
- package/dist/choice-grid.js.map +1 -1
- package/dist/{chunk-IBDTAMPF.js → chunk-7JG3VR4C.js} +2 -2
- package/dist/{chunk-C7LTF5CC.js → chunk-ENOS6ETI.js} +2 -2
- package/dist/{chunk-C7LTF5CC.js.map → chunk-ENOS6ETI.js.map} +1 -1
- package/dist/{chunk-2AGSO3WH.js → chunk-FVGFPB73.js} +2 -2
- package/dist/{chunk-2AGSO3WH.js.map → chunk-FVGFPB73.js.map} +1 -1
- package/dist/cover-hero.js +1 -1
- package/dist/link-card.js +2 -2
- package/dist/media-grid.js +1 -1
- package/dist/media-grid.js.map +1 -1
- package/dist/page-hero.js +1 -1
- package/dist/page-index.js +1 -1
- package/dist/service-card.js +1 -1
- package/dist/slot-picker.js +1 -1
- package/package.json +20 -6
- package/registry/account-menu.json +1 -1
- package/registry/account-settings.json +1 -1
- package/registry/achievement.json +1 -1
- package/registry/action-bar.json +2 -2
- package/registry/activity-feed.json +1 -1
- package/registry/agenda.json +1 -1
- package/registry/alert.json +1 -1
- package/registry/anatomy-plate.json +1 -1
- package/registry/app-header.json +1 -1
- package/registry/app-shell.json +1 -1
- package/registry/argument-card.json +2 -2
- package/registry/audio-player.json +1 -1
- package/registry/auth-layout.json +1 -1
- package/registry/avatar.json +1 -1
- package/registry/badge.json +1 -1
- package/registry/bird-plate.json +1 -1
- package/registry/button.json +1 -1
- package/registry/captcha.json +1 -1
- package/registry/card-grid.json +1 -1
- package/registry/card.json +1 -1
- package/registry/catalogue-page.json +1 -1
- package/registry/changelog-page.json +1 -1
- package/registry/chapter.json +478 -0
- package/registry/chat.json +1 -1
- package/registry/checkbox.json +1 -1
- package/registry/chip-link.json +1 -1
- package/registry/chip-row.json +1 -1
- package/registry/chip.json +1 -1
- package/registry/choice-grid.json +2 -2
- package/registry/code-block.json +1 -1
- package/registry/combobox.json +1 -1
- package/registry/command.json +1 -1
- package/registry/comparison-table.json +1 -1
- package/registry/component-page.json +1 -1
- package/registry/confirm-button.json +1 -1
- package/registry/contact-page.json +1 -1
- package/registry/continue-prompt.json +1 -1
- package/registry/countdown.json +1 -1
- package/registry/cover-hero.json +2 -2
- package/registry/cta-panel.json +1 -1
- package/registry/dashboard-layout.json +1 -1
- package/registry/data-table.json +1 -1
- package/registry/date-picker.json +1 -1
- package/registry/decision-list.json +1 -1
- package/registry/description-list.json +1 -1
- package/registry/detail-layout.json +1 -1
- package/registry/dialog.json +1 -1
- package/registry/docs-article-page.json +1 -1
- package/registry/docs-hub-page.json +1 -1
- package/registry/docs-layout.json +1 -1
- package/registry/docs-nav.json +1 -1
- package/registry/document-viewer.json +1 -1
- package/registry/drop-overlay.json +1 -1
- package/registry/dropdown-menu.json +1 -1
- package/registry/elephant.json +2 -2
- package/registry/empty-state.json +1 -1
- package/registry/engine-flow.json +1 -1
- package/registry/error-page.json +1 -1
- package/registry/examples/chapter/detail.d.ts +4 -0
- package/registry/examples/chapter/detail.js +21 -0
- package/registry/examples/chapter/detail.tsx +16 -0
- package/registry/examples/chapter/foot.d.ts +4 -0
- package/registry/examples/chapter/foot.js +20 -0
- package/registry/examples/chapter/foot.tsx +15 -0
- package/registry/examples/chapter/head.d.ts +4 -0
- package/registry/examples/chapter/head.js +22 -0
- package/registry/examples/chapter/head.tsx +17 -0
- package/registry/examples/chapter/index.d.ts +4 -0
- package/registry/examples/chapter/index.js +34 -0
- package/registry/examples/chapter/index.tsx +30 -0
- package/registry/examples/chapter/reading-page.d.ts +4 -0
- package/registry/examples/chapter/reading-page.js +34 -0
- package/registry/examples/chapter/reading-page.tsx +25 -0
- package/registry/field.json +1 -1
- package/registry/file-upload.json +1 -1
- package/registry/filter-bar.json +1 -1
- package/registry/flock.json +1 -1
- package/registry/footnote.json +1 -1
- package/registry/force-update-screen.json +1 -1
- package/registry/form.json +1 -1
- package/registry/gallery-page.json +1 -1
- package/registry/genui.json +1 -1
- package/registry/glossary-term.json +1 -1
- package/registry/glossary.json +1 -1
- package/registry/glow-card.json +1 -1
- package/registry/goal-gauge.json +1 -1
- package/registry/how-it-works-page.json +1 -1
- package/registry/image-cropper.json +1 -1
- package/registry/index.json +37 -6
- package/registry/iso.json +1 -1
- package/registry/kanban.json +1 -1
- package/registry/kbd.json +1 -1
- package/registry/kpi-explained.json +1 -1
- package/registry/landing-page.json +1 -1
- package/registry/landscape.json +1 -1
- package/registry/language-switch.json +1 -1
- package/registry/legal-page.json +1 -1
- package/registry/link-card.json +2 -2
- package/registry/list.json +1 -1
- package/registry/loader.json +1 -1
- package/registry/longform-page.json +1 -1
- package/registry/maintenance-screen.json +1 -1
- package/registry/map.json +2 -2
- package/registry/markdown.json +1 -1
- package/registry/marketing-layout.json +1 -1
- package/registry/marquee.json +1 -1
- package/registry/mascot-quote.json +1 -1
- package/registry/mascot-state.json +1 -1
- package/registry/mascots.json +1 -1
- package/registry/match-dialog.json +1 -1
- package/registry/media-capture.json +1 -1
- package/registry/media-gallery.json +1 -1
- package/registry/media-grid.json +2 -2
- package/registry/meta-row.json +1 -1
- package/registry/meter.json +1 -1
- package/registry/nav-bar.json +2 -2
- package/registry/next-actions.json +1 -1
- package/registry/number-ticker.json +1 -1
- package/registry/opening-hours.json +1 -1
- package/registry/page-header.json +1 -1
- package/registry/page-hero.json +2 -2
- package/registry/page-index.json +2 -2
- package/registry/page.json +1 -1
- package/registry/pagination.json +1 -1
- package/registry/photo-grid.json +1 -1
- package/registry/pointer-light.json +1 -1
- package/registry/popover.json +1 -1
- package/registry/pricing-page.json +1 -1
- package/registry/product-page.json +1 -1
- package/registry/profile-card.json +1 -1
- package/registry/progress.json +1 -1
- package/registry/promise-card.json +1 -1
- package/registry/radio-group.json +1 -1
- package/registry/rail-nav.json +2 -2
- package/registry/recipes.json +1 -1
- package/registry/router.json +1 -1
- package/registry/scroll-stage.json +1 -1
- package/registry/search-field.json +1 -1
- package/registry/section-backdrop.json +1 -1
- package/registry/separator.json +1 -1
- package/registry/service-card.json +2 -2
- package/registry/settings-layout.json +1 -1
- package/registry/showcase.json +1 -1
- package/registry/site-footer.json +2 -2
- package/registry/sites.json +1 -1
- package/registry/skeleton.json +1 -1
- package/registry/skip-link.json +1 -1
- package/registry/slider.json +1 -1
- package/registry/slot-picker.json +2 -2
- package/registry/slot.json +1 -1
- package/registry/specimen-tag.json +1 -1
- package/registry/spinner.json +1 -1
- package/registry/split-view.json +1 -1
- package/registry/stage-banner.json +1 -1
- package/registry/stat.json +1 -1
- package/registry/status-page.json +1 -1
- package/registry/step-progress.json +1 -1
- package/registry/step-showcase.json +1 -1
- package/registry/stepper.json +1 -1
- package/registry/sticky-action.json +1 -1
- package/registry/swipe-deck.json +1 -1
- package/registry/switch.json +1 -1
- package/registry/tabs.json +1 -1
- package/registry/tag-input.json +1 -1
- package/registry/tag-selector.json +1 -1
- package/registry/taped-photo.json +1 -1
- package/registry/terminal-replay.json +1 -1
- package/registry/text-style.json +1 -1
- package/registry/theme.json +1 -1
- package/registry/toast.json +1 -1
- package/registry/toc.json +1 -1
- package/registry/tooltip.json +1 -1
- package/registry/tree-view.json +1 -1
- package/registry/update-prompt.json +1 -1
- package/registry/upload-queue.json +1 -1
- package/registry/verified-badge.json +1 -1
- package/registry/vertical-video.json +1 -1
- package/registry/video-player.json +1 -1
- package/registry/video-trimmer.json +1 -1
- package/registry/virtual.json +1 -1
- package/registry/waveform.json +1 -1
- /package/dist/{chunk-IBDTAMPF.js.map → chunk-7JG3VR4C.js.map} +0 -0
package/dist/action-bar.js
CHANGED
package/dist/argument-card.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cardHoverClass
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7JG3VR4C.js";
|
|
4
4
|
import {
|
|
5
5
|
Facts
|
|
6
6
|
} from "./chunk-YKEIOYJ5.js";
|
|
7
7
|
import {
|
|
8
8
|
BlockLink
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-FVGFPB73.js";
|
|
10
10
|
import {
|
|
11
11
|
ArrowGlyph,
|
|
12
12
|
ChevronGlyph
|
package/dist/blocks.css
CHANGED
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
}
|
|
55
55
|
.kz-frame[data-margin] { --kz-margin-x: max(8px, calc(var(--kz-gutter) - 12px)); }
|
|
56
56
|
.kz-heading-number,
|
|
57
|
+
.kz-chapter-no,
|
|
57
58
|
.kz-margin-note {
|
|
58
59
|
font-family: var(--kz-font-mono);
|
|
59
60
|
font-size: 13px;
|
|
@@ -1260,6 +1261,113 @@ a.kz-fact:focus-visible { outline: 2px solid var(--kz-ring, var(--kz-accent)); o
|
|
|
1260
1261
|
.kz-footnotes li::marker { font-family: var(--kz-font-mono); color: var(--kz-paper-rule-margin); }
|
|
1261
1262
|
.kz-fn-back { color: var(--kz-accent-text); text-decoration: none; }
|
|
1262
1263
|
|
|
1264
|
+
/* ChapterIndex, ChapterHead, ChapterFoot (#617) — the chapters of a story on the notebook's lines, never boxes. Every row is
|
|
1265
|
+
one ruled line (--kz-chapter-line = the paper's module, 32 px): the number hangs in the margin left of the red rule
|
|
1266
|
+
(`[data-margin]`, moved to --kz-margin-x), the serif title is the link and its hit area is the whole row, the period is
|
|
1267
|
+
quiet on the right (under the title in a narrow column). The ruling is `[data-paper="lines"]`, shifted so a major line
|
|
1268
|
+
runs under the titles' baseline (--kz-chapter-baseline, in em of the title). No border per row, nothing moves. */
|
|
1269
|
+
.kz-chapters {
|
|
1270
|
+
--kz-chapter-line: var(--kz-paper-module, 32px);
|
|
1271
|
+
--kz-chapter-pad: var(--kz-paper-line, 8px);
|
|
1272
|
+
--kz-chapter-baseline: calc(var(--kz-chapter-line) / 2 + 0.36em);
|
|
1273
|
+
--kz-chapter-gap: 16px;
|
|
1274
|
+
container-type: inline-size;
|
|
1275
|
+
box-sizing: border-box;
|
|
1276
|
+
max-width: var(--kz-chapters-max, 46rem); /* the period stays within reach of its title */
|
|
1277
|
+
margin: 0;
|
|
1278
|
+
padding: var(--kz-chapter-pad) 0;
|
|
1279
|
+
list-style: none;
|
|
1280
|
+
font-size: 1.1875rem;
|
|
1281
|
+
}
|
|
1282
|
+
.kz-chapters[data-margin], .kz-chapter-head[data-margin] { --kz-margin-x: 3rem; }
|
|
1283
|
+
.kz-chapters[data-paper] { background-position: 0 calc(var(--kz-chapter-pad) + var(--kz-chapter-baseline)); }
|
|
1284
|
+
.kz-chapters ul { margin: 0; padding: 0; list-style: none; }
|
|
1285
|
+
.kz-chapter-row {
|
|
1286
|
+
position: relative;
|
|
1287
|
+
display: grid;
|
|
1288
|
+
grid-template-columns: var(--kz-margin-x) minmax(0, 1fr) auto;
|
|
1289
|
+
align-items: baseline;
|
|
1290
|
+
min-height: var(--kz-chapter-line);
|
|
1291
|
+
line-height: var(--kz-chapter-line);
|
|
1292
|
+
}
|
|
1293
|
+
.kz-chapter-row .kz-chapter-no { grid-column: 1; padding-right: 12px; text-align: right; white-space: nowrap; }
|
|
1294
|
+
.kz-chapter-link {
|
|
1295
|
+
grid-column: 2;
|
|
1296
|
+
min-width: 0;
|
|
1297
|
+
padding-left: var(--kz-chapter-gap);
|
|
1298
|
+
font-family: var(--kz-font-display);
|
|
1299
|
+
font-weight: 400;
|
|
1300
|
+
line-height: var(--kz-chapter-line);
|
|
1301
|
+
color: var(--kz-text-primary);
|
|
1302
|
+
text-decoration: none;
|
|
1303
|
+
overflow-wrap: anywhere;
|
|
1304
|
+
}
|
|
1305
|
+
.kz-chapter-link::after { content: ""; position: absolute; inset: 0; }
|
|
1306
|
+
.kz-chapter-link:focus-visible { outline: none; }
|
|
1307
|
+
.kz-chapter-link:focus-visible::after { outline: var(--kz-ring-width, 2px) solid var(--kz-ring); outline-offset: 0; }
|
|
1308
|
+
.kz-chapter-title { text-decoration-line: none; text-decoration-thickness: 1.5px; text-underline-offset: 0.2em; }
|
|
1309
|
+
.kz-chapter-link:is(:hover, :focus-visible) .kz-chapter-title { text-decoration-line: underline; text-decoration-color: var(--kz-hue, var(--kz-accent)); }
|
|
1310
|
+
.kz-chapter-link[aria-current="page"] .kz-chapter-title { text-decoration-line: underline; text-decoration-color: var(--kz-paper-rule-margin); }
|
|
1311
|
+
.kz-chapter-new,
|
|
1312
|
+
.kz-chapter-period,
|
|
1313
|
+
.kz-chapter-meta {
|
|
1314
|
+
font-family: var(--kz-font-mono);
|
|
1315
|
+
font-size: 12.5px;
|
|
1316
|
+
line-height: 16px;
|
|
1317
|
+
font-variant-numeric: var(--kz-figures, lining-nums tabular-nums);
|
|
1318
|
+
}
|
|
1319
|
+
.kz-chapter-new { margin-left: 4px; white-space: nowrap; color: var(--kz-hue-text, var(--kz-accent-text)); }
|
|
1320
|
+
.kz-chapter-period { grid-column: 3; padding-left: var(--kz-chapter-gap); white-space: nowrap; color: var(--kz-text-secondary); }
|
|
1321
|
+
.kz-chapter-detail { grid-column: 2 / -1; padding-left: var(--kz-chapter-gap); font-size: 14.5px; color: var(--kz-text-secondary); }
|
|
1322
|
+
/* A narrow column: the row flows as text with a hanging indent — the number still in the margin (inline, so it shares the
|
|
1323
|
+
title's baseline), the title wraps from line to line, the period runs on after its last word: two ruled lines at most. */
|
|
1324
|
+
@container (max-width: 34rem) {
|
|
1325
|
+
.kz-chapter-row { display: block; padding-left: calc(var(--kz-margin-x) + var(--kz-chapter-gap)); }
|
|
1326
|
+
.kz-chapter-row .kz-chapter-no {
|
|
1327
|
+
display: inline-block;
|
|
1328
|
+
box-sizing: border-box;
|
|
1329
|
+
width: var(--kz-margin-x);
|
|
1330
|
+
margin-left: calc(-1 * (var(--kz-margin-x) + var(--kz-chapter-gap)));
|
|
1331
|
+
margin-right: var(--kz-chapter-gap);
|
|
1332
|
+
}
|
|
1333
|
+
.kz-chapter-link { display: inline; padding-left: 0; }
|
|
1334
|
+
.kz-chapter-period { display: inline-block; padding-left: 0; }
|
|
1335
|
+
.kz-chapter-detail { display: block; padding-left: 0; }
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
/* The foot: the previous and the next as two rows of the index, then one quiet line back to the story. */
|
|
1339
|
+
.kz-chapter-row[data-dir] .kz-chapter-period { color: var(--kz-text-secondary); }
|
|
1340
|
+
.kz-chapter-back { margin: 0; padding-left: calc(var(--kz-margin-x) + var(--kz-chapter-gap)); font-size: 14.5px; line-height: var(--kz-chapter-line); }
|
|
1341
|
+
.kz-chapter-back-link { color: var(--kz-text-secondary); text-decoration: none; text-decoration-thickness: 1.5px; text-underline-offset: 0.2em; }
|
|
1342
|
+
.kz-chapter-back-link:is(:hover, :focus-visible) { color: var(--kz-text-primary); text-decoration-line: underline; text-decoration-color: var(--kz-hue, var(--kz-accent)); }
|
|
1343
|
+
.kz-chapter-back-link:focus-visible { outline: var(--kz-ring-width, 2px) solid var(--kz-ring); outline-offset: 2px; }
|
|
1344
|
+
|
|
1345
|
+
/* The head: the number in the margin beside the title's first line, one quiet meta line, the standfirst once. */
|
|
1346
|
+
.kz-chapter-head {
|
|
1347
|
+
display: grid;
|
|
1348
|
+
grid-template-columns: var(--kz-margin-x) minmax(0, 1fr);
|
|
1349
|
+
align-items: baseline;
|
|
1350
|
+
row-gap: 12px;
|
|
1351
|
+
padding-block: 8px;
|
|
1352
|
+
}
|
|
1353
|
+
.kz-chapter-head > * { grid-column: 2; margin: 0; padding-left: var(--kz-chapter-gap, 16px); min-width: 0; }
|
|
1354
|
+
.kz-chapter-head > .kz-chapter-no { grid-column: 1; grid-row: 1; padding: 0 12px 0 0; text-align: right; white-space: nowrap; }
|
|
1355
|
+
.kz-chapter-head-title {
|
|
1356
|
+
grid-row: 1;
|
|
1357
|
+
max-width: 22ch;
|
|
1358
|
+
font-family: var(--kz-font-display);
|
|
1359
|
+
font-size: clamp(1.85rem, 5.2vw, 2.75rem);
|
|
1360
|
+
font-weight: 400;
|
|
1361
|
+
line-height: 1.15;
|
|
1362
|
+
letter-spacing: -0.01em;
|
|
1363
|
+
color: var(--kz-text-primary);
|
|
1364
|
+
text-wrap: balance;
|
|
1365
|
+
overflow-wrap: anywhere;
|
|
1366
|
+
}
|
|
1367
|
+
.kz-chapter-meta { color: var(--kz-text-secondary); }
|
|
1368
|
+
.kz-chapter-standfirst { max-width: 60ch; font-size: 1.125rem; line-height: 1.6; color: var(--kz-text-secondary); text-wrap: pretty; }
|
|
1369
|
+
.kz-chapter-arrow { color: var(--kz-hue-text, var(--kz-paper-rule-margin)); }
|
|
1370
|
+
|
|
1263
1371
|
/* Mascot life — the Flock's birds at ease, in character (Mascot `life`). */
|
|
1264
1372
|
/* mascot-life:begin — generated by scripts/gen-mascot-life.mjs from src/mascots/life.ts; do not edit */
|
|
1265
1373
|
@keyframes kzb-breathe{0%,100%{transform:scale(1,1)}50%{transform:scale(.996,1.018)}}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { L as LinkComponent } from './block-link-BAg4eoZk.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/** The notebook under the rows: `lines` (the ruling of `Page`, aligned on the rows) or `false` (the page's own paper). */
|
|
5
|
+
type ChapterPaper = "lines" | false;
|
|
6
|
+
interface ChapterEntry {
|
|
7
|
+
/** Its number, hung in the margin: `01`, `§ 1`. */
|
|
8
|
+
number: React.ReactNode;
|
|
9
|
+
/** The title, in the serif: the link. */
|
|
10
|
+
title: React.ReactNode;
|
|
11
|
+
/** Where it leads. */
|
|
12
|
+
href: string;
|
|
13
|
+
/** When it happened, quiet on the right (under the title on a phone): `janv. – mars 2026`, or a `<time>`. */
|
|
14
|
+
period?: React.ReactNode;
|
|
15
|
+
/** One more line under the title (what was faced → what was built). Off unless given: the chapter's page says it. */
|
|
16
|
+
detail?: React.ReactNode;
|
|
17
|
+
/** The latest chapter: a small mark after the title, in the hue (`newLabel`). */
|
|
18
|
+
isNew?: boolean;
|
|
19
|
+
/** The page the reader is on. */
|
|
20
|
+
current?: boolean;
|
|
21
|
+
}
|
|
22
|
+
type ChapterIndexProps = Omit<React.OlHTMLAttributes<HTMLOListElement>, "children"> & {
|
|
23
|
+
/** The chapters, in reading order. */
|
|
24
|
+
chapters: readonly ChapterEntry[];
|
|
25
|
+
/** The word of the latest chapter's mark. @default "New" */
|
|
26
|
+
newLabel?: React.ReactNode;
|
|
27
|
+
/** The accessible name of the list, when no heading names it (`aria-labelledby`). */
|
|
28
|
+
label?: string;
|
|
29
|
+
/** The ruling under the rows. `false` when the page is ruled already and the list starts on its module. @default "lines" */
|
|
30
|
+
paper?: ChapterPaper;
|
|
31
|
+
/** The app's router link (Next's `Link`), so internal chapters prefetch. */
|
|
32
|
+
linkAs?: LinkComponent;
|
|
33
|
+
};
|
|
34
|
+
/** The chapters of a story as a sober timeline: one ruled line each, the number in the margin, the title the link. */
|
|
35
|
+
declare function ChapterIndex({ chapters, newLabel, label, paper, linkAs, className, ...props }: ChapterIndexProps): React.JSX.Element;
|
|
36
|
+
type ChapterHeadProps = Omit<React.HTMLAttributes<HTMLElement>, "title"> & {
|
|
37
|
+
/** The chapter's number, hung in the margin: `01`, `Chapitre 1`. */
|
|
38
|
+
number: React.ReactNode;
|
|
39
|
+
/** The title: the page's `h1`. */
|
|
40
|
+
title: React.ReactNode;
|
|
41
|
+
/** When it happened: `janv. – mars 2026`. */
|
|
42
|
+
period?: React.ReactNode;
|
|
43
|
+
/** How long it reads: `8 min`. */
|
|
44
|
+
readingTime?: React.ReactNode;
|
|
45
|
+
/** What was faced: the first half of the standfirst. */
|
|
46
|
+
faced?: React.ReactNode;
|
|
47
|
+
/** What was built: its second half, after the arrow. */
|
|
48
|
+
built?: React.ReactNode;
|
|
49
|
+
/** The words a screen reader says before each half (the arrow is drawn, not read): `["What I faced", "What we built"]`. */
|
|
50
|
+
versusLabels?: readonly [string, string];
|
|
51
|
+
/** The level of the title. @default 1 */
|
|
52
|
+
level?: 1 | 2;
|
|
53
|
+
};
|
|
54
|
+
/** The head of a chapter: the number in the margin, the title, the period and the reading time, the standfirst once. */
|
|
55
|
+
declare function ChapterHead({ number, title, period, readingTime, faced, built, versusLabels, level, className, children, ...props }: ChapterHeadProps): React.JSX.Element;
|
|
56
|
+
interface ChapterLink {
|
|
57
|
+
/** Its number, in the margin: `02`. */
|
|
58
|
+
number?: React.ReactNode;
|
|
59
|
+
/** Its title, the link. */
|
|
60
|
+
title: React.ReactNode;
|
|
61
|
+
/** Where it leads. */
|
|
62
|
+
href: string;
|
|
63
|
+
}
|
|
64
|
+
type ChapterFootProps = Omit<React.HTMLAttributes<HTMLElement>, "children"> & {
|
|
65
|
+
/** The chapter before this one (none on the first). */
|
|
66
|
+
previous?: ChapterLink;
|
|
67
|
+
/** The chapter after this one (none on the latest). */
|
|
68
|
+
next?: ChapterLink;
|
|
69
|
+
/** The line back to the story: `{ href: "/", label: "Back to the story" }`. */
|
|
70
|
+
back?: {
|
|
71
|
+
href: string;
|
|
72
|
+
label: React.ReactNode;
|
|
73
|
+
};
|
|
74
|
+
/** The quiet words beside each link. @default { previous: "Previous", next: "Next" } */
|
|
75
|
+
labels?: {
|
|
76
|
+
previous: React.ReactNode;
|
|
77
|
+
next: React.ReactNode;
|
|
78
|
+
};
|
|
79
|
+
/** The accessible name of the navigation. @default "Chapters" */
|
|
80
|
+
label?: string;
|
|
81
|
+
/** The ruling under the links. @default "lines" */
|
|
82
|
+
paper?: ChapterPaper;
|
|
83
|
+
/** The app's router link (Next's `Link`). */
|
|
84
|
+
linkAs?: LinkComponent;
|
|
85
|
+
};
|
|
86
|
+
/** The foot of a chapter: the previous and the next on the ruled lines, then one line back to the story. */
|
|
87
|
+
declare function ChapterFoot({ previous, next, back, labels, label, paper, linkAs, className, ...props }: ChapterFootProps): React.JSX.Element;
|
|
88
|
+
|
|
89
|
+
export { type ChapterEntry, ChapterFoot, type ChapterFootProps, ChapterHead, type ChapterHeadProps, ChapterIndex, type ChapterIndexProps, type ChapterLink, LinkComponent };
|
package/dist/chapter.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BlockLink
|
|
3
|
+
} from "./chunk-FVGFPB73.js";
|
|
4
|
+
import {
|
|
5
|
+
cn
|
|
6
|
+
} from "./chunk-W675RFOA.js";
|
|
7
|
+
|
|
8
|
+
// src/chapter/chapter.tsx
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
function ChapterRow({
|
|
11
|
+
number,
|
|
12
|
+
title,
|
|
13
|
+
href,
|
|
14
|
+
aside,
|
|
15
|
+
mark,
|
|
16
|
+
detail,
|
|
17
|
+
current,
|
|
18
|
+
rel,
|
|
19
|
+
linkAs
|
|
20
|
+
}) {
|
|
21
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22
|
+
/* @__PURE__ */ jsx("span", { className: "kz-chapter-no", children: number }),
|
|
23
|
+
/* @__PURE__ */ jsxs(BlockLink, { href, linkAs, rel, className: "kz-chapter-link", "aria-current": current ? "page" : void 0, children: [
|
|
24
|
+
/* @__PURE__ */ jsx("span", { className: "kz-chapter-title", children: title }),
|
|
25
|
+
mark && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
26
|
+
" ",
|
|
27
|
+
/* @__PURE__ */ jsx("span", { className: "kz-chapter-new", children: mark })
|
|
28
|
+
] })
|
|
29
|
+
] }),
|
|
30
|
+
aside && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
31
|
+
" ",
|
|
32
|
+
/* @__PURE__ */ jsx("span", { className: "kz-chapter-period", children: aside })
|
|
33
|
+
] }),
|
|
34
|
+
detail && /* @__PURE__ */ jsx("span", { className: "kz-chapter-detail", children: detail })
|
|
35
|
+
] });
|
|
36
|
+
}
|
|
37
|
+
function ChapterIndex({ chapters, newLabel = "New", label, paper = "lines", linkAs, className, ...props }) {
|
|
38
|
+
return (
|
|
39
|
+
// `role="list"`: a list without bullets is still a list to VoiceOver.
|
|
40
|
+
/* @__PURE__ */ jsx("ol", { role: "list", "aria-label": label, "data-paper": paper || void 0, "data-margin": "", className: cn("kz-chapters", className), ...props, children: chapters.map((c, i) => /* @__PURE__ */ jsx("li", { className: "kz-chapter-row", "data-new": c.isNew ? "" : void 0, "data-detail": c.detail ? "" : void 0, children: /* @__PURE__ */ jsx(ChapterRow, { number: c.number, title: c.title, href: c.href, aside: c.period, mark: c.isNew ? newLabel : void 0, detail: c.detail, current: c.current, linkAs }) }, i)) })
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
function ChapterHead({ number, title, period, readingTime, faced, built, versusLabels, level = 1, className, children, ...props }) {
|
|
44
|
+
const H = level === 1 ? "h1" : "h2";
|
|
45
|
+
const meta = [period, readingTime].filter((m) => m !== void 0 && m !== null && m !== "");
|
|
46
|
+
return /* @__PURE__ */ jsxs("header", { "data-margin": "", className: cn("kz-chapter-head", className), ...props, children: [
|
|
47
|
+
/* @__PURE__ */ jsx("p", { className: "kz-chapter-no", children: number }),
|
|
48
|
+
/* @__PURE__ */ jsx(H, { className: "kz-chapter-head-title", children: title }),
|
|
49
|
+
meta.length > 0 && /* @__PURE__ */ jsx("p", { className: "kz-chapter-meta", children: meta.map((m, i) => /* @__PURE__ */ jsxs("span", { children: [
|
|
50
|
+
i > 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: " \xB7 " }),
|
|
51
|
+
m
|
|
52
|
+
] }, i)) }),
|
|
53
|
+
faced && built && /* @__PURE__ */ jsxs("p", { className: "kz-chapter-standfirst", children: [
|
|
54
|
+
versusLabels && /* @__PURE__ */ jsxs("span", { className: "kz-sr-only", children: [
|
|
55
|
+
versusLabels[0],
|
|
56
|
+
", "
|
|
57
|
+
] }),
|
|
58
|
+
faced,
|
|
59
|
+
/* @__PURE__ */ jsx("span", { className: "kz-chapter-arrow", "aria-hidden": true, children: " \u2192 " }),
|
|
60
|
+
versusLabels && /* @__PURE__ */ jsxs("span", { className: "kz-sr-only", children: [
|
|
61
|
+
"; ",
|
|
62
|
+
versusLabels[1],
|
|
63
|
+
", "
|
|
64
|
+
] }),
|
|
65
|
+
built
|
|
66
|
+
] }),
|
|
67
|
+
children
|
|
68
|
+
] });
|
|
69
|
+
}
|
|
70
|
+
function ChapterFoot({
|
|
71
|
+
previous,
|
|
72
|
+
next,
|
|
73
|
+
back,
|
|
74
|
+
labels = { previous: "Previous", next: "Next" },
|
|
75
|
+
label = "Chapters",
|
|
76
|
+
paper = "lines",
|
|
77
|
+
linkAs,
|
|
78
|
+
className,
|
|
79
|
+
...props
|
|
80
|
+
}) {
|
|
81
|
+
return /* @__PURE__ */ jsxs("nav", { "aria-label": label, "data-paper": paper || void 0, "data-margin": "", className: cn("kz-chapters kz-chapter-foot", className), ...props, children: [
|
|
82
|
+
/* @__PURE__ */ jsxs("ul", { role: "list", children: [
|
|
83
|
+
previous && /* @__PURE__ */ jsx("li", { className: "kz-chapter-row", "data-dir": "previous", children: /* @__PURE__ */ jsx(
|
|
84
|
+
ChapterRow,
|
|
85
|
+
{
|
|
86
|
+
number: previous.number,
|
|
87
|
+
title: previous.title,
|
|
88
|
+
href: previous.href,
|
|
89
|
+
rel: "prev",
|
|
90
|
+
linkAs,
|
|
91
|
+
aside: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
92
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u2190 " }),
|
|
93
|
+
labels.previous
|
|
94
|
+
] })
|
|
95
|
+
}
|
|
96
|
+
) }),
|
|
97
|
+
next && /* @__PURE__ */ jsx("li", { className: "kz-chapter-row", "data-dir": "next", children: /* @__PURE__ */ jsx(
|
|
98
|
+
ChapterRow,
|
|
99
|
+
{
|
|
100
|
+
number: next.number,
|
|
101
|
+
title: next.title,
|
|
102
|
+
href: next.href,
|
|
103
|
+
rel: "next",
|
|
104
|
+
linkAs,
|
|
105
|
+
aside: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
106
|
+
labels.next,
|
|
107
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: " \u2192" })
|
|
108
|
+
] })
|
|
109
|
+
}
|
|
110
|
+
) })
|
|
111
|
+
] }),
|
|
112
|
+
back && /* @__PURE__ */ jsx("p", { className: "kz-chapter-back", children: /* @__PURE__ */ jsxs(BlockLink, { href: back.href, linkAs, className: "kz-chapter-back-link", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u21A9 " }),
|
|
114
|
+
back.label
|
|
115
|
+
] }) })
|
|
116
|
+
] });
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
ChapterFoot,
|
|
120
|
+
ChapterHead,
|
|
121
|
+
ChapterIndex
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=chapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chapter/chapter.tsx"],"sourcesContent":["// Server-safe. The chapters of a story on the Cahier (ADR-004, blocks.css, krizaka-ui#617): a sober timeline, never a\n// stack of boxes. The rows sit on the notebook's ruled lines (`data-paper=\"lines\"`, the ruling of `Page`), the number\n// hangs in the margin beside its red rule (`data-margin`), the serif title is the link, the period is quiet.\n// - `ChapterIndex` — the chapters in reading order, one ruled line each (two at most), the latest marked « New »;\n// - `ChapterHead` — the head of a chapter's page: number in the margin, title, one quiet meta line, the standfirst;\n// - `ChapterFoot` — its foot: the previous and next chapters on the lines, then one line back to the story.\n// No border per row, no card, no button: the paper carries the rhythm. Every word arrives as a prop.\nimport type * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\n\n/** The notebook under the rows: `lines` (the ruling of `Page`, aligned on the rows) or `false` (the page's own paper). */\ntype ChapterPaper = \"lines\" | false;\n\nexport interface ChapterEntry {\n /** Its number, hung in the margin: `01`, `§ 1`. */\n number: React.ReactNode;\n /** The title, in the serif: the link. */\n title: React.ReactNode;\n /** Where it leads. */\n href: string;\n /** When it happened, quiet on the right (under the title on a phone): `janv. – mars 2026`, or a `<time>`. */\n period?: React.ReactNode;\n /** One more line under the title (what was faced → what was built). Off unless given: the chapter's page says it. */\n detail?: React.ReactNode;\n /** The latest chapter: a small mark after the title, in the hue (`newLabel`). */\n isNew?: boolean;\n /** The page the reader is on. */\n current?: boolean;\n}\n\n/** One ruled row: number in the margin, the title as the link (its hit area the whole row), an aside on the right. */\nfunction ChapterRow({\n number,\n title,\n href,\n aside,\n mark,\n detail,\n current,\n rel,\n linkAs,\n}: {\n number?: React.ReactNode;\n title: React.ReactNode;\n href: string;\n aside?: React.ReactNode;\n mark?: React.ReactNode;\n detail?: React.ReactNode;\n current?: boolean;\n rel?: string;\n linkAs?: LinkComponent;\n}) {\n return (\n <>\n <span className=\"kz-chapter-no\">{number}</span>\n <BlockLink href={href} linkAs={linkAs} rel={rel} className=\"kz-chapter-link\" aria-current={current ? \"page\" : undefined}>\n <span className=\"kz-chapter-title\">{title}</span>\n {mark && (\n <>\n {\" \"}\n <span className=\"kz-chapter-new\">{mark}</span>\n </>\n )}\n </BlockLink>\n {aside && (\n <>\n {/* A space, not a margin: in a narrow column the period runs on after the title, and starts flush when it wraps. */}{\" \"}\n <span className=\"kz-chapter-period\">{aside}</span>\n </>\n )}\n {detail && <span className=\"kz-chapter-detail\">{detail}</span>}\n </>\n );\n}\n\nexport type ChapterIndexProps = Omit<React.OlHTMLAttributes<HTMLOListElement>, \"children\"> & {\n /** The chapters, in reading order. */\n chapters: readonly ChapterEntry[];\n /** The word of the latest chapter's mark. @default \"New\" */\n newLabel?: React.ReactNode;\n /** The accessible name of the list, when no heading names it (`aria-labelledby`). */\n label?: string;\n /** The ruling under the rows. `false` when the page is ruled already and the list starts on its module. @default \"lines\" */\n paper?: ChapterPaper;\n /** The app's router link (Next's `Link`), so internal chapters prefetch. */\n linkAs?: LinkComponent;\n};\n\n/** The chapters of a story as a sober timeline: one ruled line each, the number in the margin, the title the link. */\nexport function ChapterIndex({ chapters, newLabel = \"New\", label, paper = \"lines\", linkAs, className, ...props }: ChapterIndexProps) {\n return (\n // `role=\"list\"`: a list without bullets is still a list to VoiceOver.\n <ol role=\"list\" aria-label={label} data-paper={paper || undefined} data-margin=\"\" className={cn(\"kz-chapters\", className)} {...props}>\n {chapters.map((c, i) => (\n <li key={i} className=\"kz-chapter-row\" data-new={c.isNew ? \"\" : undefined} data-detail={c.detail ? \"\" : undefined}>\n <ChapterRow number={c.number} title={c.title} href={c.href} aside={c.period} mark={c.isNew ? newLabel : undefined} detail={c.detail} current={c.current} linkAs={linkAs} />\n </li>\n ))}\n </ol>\n );\n}\n\nexport type ChapterHeadProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The chapter's number, hung in the margin: `01`, `Chapitre 1`. */\n number: React.ReactNode;\n /** The title: the page's `h1`. */\n title: React.ReactNode;\n /** When it happened: `janv. – mars 2026`. */\n period?: React.ReactNode;\n /** How long it reads: `8 min`. */\n readingTime?: React.ReactNode;\n /** What was faced: the first half of the standfirst. */\n faced?: React.ReactNode;\n /** What was built: its second half, after the arrow. */\n built?: React.ReactNode;\n /** The words a screen reader says before each half (the arrow is drawn, not read): `[\"What I faced\", \"What we built\"]`. */\n versusLabels?: readonly [string, string];\n /** The level of the title. @default 1 */\n level?: 1 | 2;\n};\n\n/** The head of a chapter: the number in the margin, the title, the period and the reading time, the standfirst once. */\nexport function ChapterHead({ number, title, period, readingTime, faced, built, versusLabels, level = 1, className, children, ...props }: ChapterHeadProps) {\n const H = level === 1 ? \"h1\" : \"h2\";\n const meta = [period, readingTime].filter((m) => m !== undefined && m !== null && m !== \"\");\n return (\n <header data-margin=\"\" className={cn(\"kz-chapter-head\", className)} {...props}>\n <p className=\"kz-chapter-no\">{number}</p>\n <H className=\"kz-chapter-head-title\">{title}</H>\n {meta.length > 0 && (\n <p className=\"kz-chapter-meta\">\n {meta.map((m, i) => (\n <span key={i}>\n {i > 0 && <span aria-hidden> · </span>}\n {m}\n </span>\n ))}\n </p>\n )}\n {faced && built && (\n <p className=\"kz-chapter-standfirst\">\n {versusLabels && <span className=\"kz-sr-only\">{versusLabels[0]}, </span>}\n {faced}\n <span className=\"kz-chapter-arrow\" aria-hidden>\n {\" → \"}\n </span>\n {versusLabels && <span className=\"kz-sr-only\">; {versusLabels[1]}, </span>}\n {built}\n </p>\n )}\n {children}\n </header>\n );\n}\n\nexport interface ChapterLink {\n /** Its number, in the margin: `02`. */\n number?: React.ReactNode;\n /** Its title, the link. */\n title: React.ReactNode;\n /** Where it leads. */\n href: string;\n}\n\nexport type ChapterFootProps = Omit<React.HTMLAttributes<HTMLElement>, \"children\"> & {\n /** The chapter before this one (none on the first). */\n previous?: ChapterLink;\n /** The chapter after this one (none on the latest). */\n next?: ChapterLink;\n /** The line back to the story: `{ href: \"/\", label: \"Back to the story\" }`. */\n back?: { href: string; label: React.ReactNode };\n /** The quiet words beside each link. @default { previous: \"Previous\", next: \"Next\" } */\n labels?: { previous: React.ReactNode; next: React.ReactNode };\n /** The accessible name of the navigation. @default \"Chapters\" */\n label?: string;\n /** The ruling under the links. @default \"lines\" */\n paper?: ChapterPaper;\n /** The app's router link (Next's `Link`). */\n linkAs?: LinkComponent;\n};\n\n/** The foot of a chapter: the previous and the next on the ruled lines, then one line back to the story. */\nexport function ChapterFoot({\n previous,\n next,\n back,\n labels = { previous: \"Previous\", next: \"Next\" },\n label = \"Chapters\",\n paper = \"lines\",\n linkAs,\n className,\n ...props\n}: ChapterFootProps) {\n return (\n <nav aria-label={label} data-paper={paper || undefined} data-margin=\"\" className={cn(\"kz-chapters kz-chapter-foot\", className)} {...props}>\n <ul role=\"list\">\n {previous && (\n <li className=\"kz-chapter-row\" data-dir=\"previous\">\n <ChapterRow\n number={previous.number}\n title={previous.title}\n href={previous.href}\n rel=\"prev\"\n linkAs={linkAs}\n aside={\n <>\n <span aria-hidden>← </span>\n {labels.previous}\n </>\n }\n />\n </li>\n )}\n {next && (\n <li className=\"kz-chapter-row\" data-dir=\"next\">\n <ChapterRow\n number={next.number}\n title={next.title}\n href={next.href}\n rel=\"next\"\n linkAs={linkAs}\n aside={\n <>\n {labels.next}\n <span aria-hidden> →</span>\n </>\n }\n />\n </li>\n )}\n </ul>\n {back && (\n <p className=\"kz-chapter-back\">\n <BlockLink href={back.href} linkAs={linkAs} className=\"kz-chapter-back-link\">\n <span aria-hidden>↩ </span>\n {back.label}\n </BlockLink>\n </p>\n )}\n </nav>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/choice-grid.js
CHANGED
|
@@ -22,7 +22,7 @@ function BlockLink({
|
|
|
22
22
|
}) {
|
|
23
23
|
if (external) return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
24
24
|
const Comp = Link;
|
|
25
|
-
return /* @__PURE__ */ jsx(Comp, { href, ...props });
|
|
25
|
+
return /* @__PURE__ */ jsx(Comp, { href, rel, ...props });
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// src/router/route-state.tsx
|
package/dist/choice-grid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/choice-grid/choice-grid.tsx","../src/block-link.tsx","../src/router/route-state.tsx"],"sourcesContent":["// Client. A row of choices shown as tiles — a visual, a name, a line (story.css): pick a plan, a persona, a team, a side.\n// Selectable (`onValueChange`), it is a radio group with roving focus; with `href` on its items, a set of links (a\n// line-up that leads somewhere); otherwise a showcase of the line-up.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { useRouteBinding } from \"../router\";\nimport { brandClass, type StoryVariant, storyVariantClass } from \"../story-variant\";\n\nexport interface ChoiceItem {\n /** The value of the choice (and its React key). */\n id: string;\n /** What represents it: a mark, an avatar, an illustration. Decorative — the name carries the meaning. */\n visual: React.ReactNode;\n /** Its name, short. */\n name: React.ReactNode;\n /** One line under the name: what it is, its role. */\n title?: React.ReactNode;\n /** A small line above the visual (a family, a tier), after its `icon`. */\n eyebrow?: React.ReactNode;\n /** A small glyph before the eyebrow (decorative). */\n icon?: React.ReactNode;\n /** A short tag in the top corner (“P1”, “New”, “Popular”). */\n badge?: React.ReactNode;\n /** Under the line: a gauge (`StatGauge`), facts, a price. */\n extra?: React.ReactNode;\n /** At the bottom: where the tile leads (“Chapter 2 ↓”, “See the plan”). */\n meta?: React.ReactNode;\n /** Makes the tile a link (ignored when the grid is selectable). */\n href?: string;\n /** A brand scope for this tile (`orazaka` → `.brand-orazaka`): its accent becomes that brand's. */\n brand?: string;\n /** Not selectable. */\n disabled?: boolean;\n}\n\nexport type ChoiceGridProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"defaultValue\" | \"onChange\"> & {\n /** The accessible name of the group (“Choose your plan”) — passed translated. */\n label: string;\n /** The choices, in reading order. */\n items: readonly ChoiceItem[];\n /** A short mono line above the grid (a step, a tag). */\n tag?: React.ReactNode;\n /** A line beside the tag: what the choice means. */\n caption?: React.ReactNode;\n /** A call above the tiles, larger (“Choose your plan”). */\n prompt?: React.ReactNode;\n /** The chosen id (controlled). */\n value?: string;\n /** The chosen id at first (uncontrolled). */\n defaultValue?: string;\n /** Makes the grid a radio group: called with the id chosen by click, Enter, Space or the arrow keys. */\n onValueChange?: (id: string) => void;\n /** Binds the choice to this search parameter of the URL (`?type=…`): the URL is the state. Without it the state is local — only for an ephemeral choice. */\n routeKey?: string;\n /** The ids the parameter may hold; the first is the default unless `defaultValue` says otherwise. */\n routeValues?: readonly string[];\n /** The app's link component for the tiles' internal `href`s (Next's `Link`); an `<a>` otherwise. */\n linkAs?: LinkComponent;\n /**\n * The number of columns (one on a phone).\n * @default min(items, 4)\n */\n columns?: number;\n /**\n * `default`: sober tiles. `arcade`: the select screen — the brand's light on each card, corners that lock, a flash.\n * @default \"default\"\n */\n variant?: StoryVariant;\n /** A brand scope for the whole grid (`orochia` → `.brand-orochia`). */\n brand?: string;\n /**\n * The tiles' arrival on mount (arcade: the corners locking one by one, the gauges filling). Always off under\n * `prefers-reduced-motion`.\n * @default true\n */\n animated?: boolean;\n};\n\nconst CORNERS = [\"tl\", \"tr\", \"bl\", \"br\"] as const;\n\n/**\n * A line-up of choices as tiles. With `onValueChange` (or `value`), a radio group: one tab stop, the arrow keys move\n * and choose, Home/End jump, the chosen tile is marked. With `href` on the items, a list of links. Otherwise a list\n * named by `label` that presents the line-up.\n */\nexport function ChoiceGrid({\n label,\n items,\n tag,\n caption,\n prompt,\n value: valueProp,\n defaultValue: defaultValueProp,\n onValueChange: onValueChangeProp,\n routeKey,\n routeValues,\n linkAs,\n columns,\n variant,\n brand,\n animated = true,\n className,\n style,\n ...props\n}: ChoiceGridProps) {\n const { value, defaultValue, onValueChange } = useRouteBinding(routeKey, routeValues, { value: valueProp, defaultValue: defaultValueProp, onValueChange: onValueChangeProp });\n const selectable = onValueChange !== undefined || value !== undefined;\n const [inner, setInner] = React.useState(defaultValue);\n const current = value ?? inner;\n const refs = React.useRef<(HTMLButtonElement | null)[]>([]);\n const enabled = items.map((item, i) => (item.disabled ? -1 : i)).filter((i) => i >= 0);\n const chosenIndex = items.findIndex((item) => item.id === current && !item.disabled);\n const focusIndex = chosenIndex >= 0 ? chosenIndex : (enabled[0] ?? 0);\n\n const choose = (i: number) => {\n const item = items[i];\n if (!item || item.disabled) return;\n if (value === undefined) setInner(item.id);\n onValueChange?.(item.id);\n };\n const onKeyDown = (e: React.KeyboardEvent, i: number) => {\n const at = enabled.indexOf(i);\n let next: number | undefined;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") next = enabled[(at + 1) % enabled.length];\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") next = enabled[(at - 1 + enabled.length) % enabled.length];\n else if (e.key === \"Home\") next = enabled[0];\n else if (e.key === \"End\") next = enabled[enabled.length - 1];\n if (next === undefined) return;\n e.preventDefault();\n refs.current[next]?.focus();\n choose(next);\n };\n\n // A radio group holds radios, not list items; a showcase or a set of links is a list named by `label`.\n const Grid = selectable ? \"div\" : \"ul\";\n const Item = selectable ? \"div\" : \"li\";\n const vars = { \"--kzs-cols\": columns ?? Math.min(items.length, 4), ...style } as React.CSSProperties;\n return (\n <div data-kzs-scene=\"\" data-animated={animated ? \"\" : undefined} className={cn(\"kzs-choice\", storyVariantClass(variant), brandClass(brand), className)} style={vars} {...props}>\n <span className=\"kzs-texture\" aria-hidden />\n <span className=\"kzs-scan kzs-loop\" aria-hidden />\n {(tag || caption) && (\n <p className=\"kzs-choice-head\">\n {tag && <span className=\"kzs-choice-tag\">{tag}</span>}\n {tag && caption && <span className=\"kzs-choice-sep\" aria-hidden />}\n {caption && <span className=\"kzs-choice-caption\">{caption}</span>}\n </p>\n )}\n {prompt && <p className=\"kzs-choice-prompt\">{prompt}</p>}\n <Grid className=\"kzs-choice-grid\" role={selectable ? \"radiogroup\" : undefined} aria-label={label}>\n {items.map((item, i) => {\n const body = (\n <>\n <span className=\"kzs-choice-aura\" aria-hidden />\n <span className=\"kzs-choice-flash\" aria-hidden />\n {CORNERS.map((at) => (\n <span key={at} className=\"kzs-corner\" data-at={at} aria-hidden />\n ))}\n {(item.badge || item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-top\">\n {item.badge ? <span className=\"kzs-choice-badge\">{item.badge}</span> : <span />}\n {(item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-eyebrow\">\n {item.icon && <span aria-hidden>{item.icon}</span>}\n {item.eyebrow}\n </span>\n )}\n </span>\n )}\n <span className=\"kzs-choice-frame\" aria-hidden>\n <span className=\"kzs-choice-floor\" />\n <span className=\"kzs-choice-visual\">{item.visual}</span>\n </span>\n <span className=\"kzs-choice-name\">{item.name}</span>\n {item.title && <span className=\"kzs-choice-title\">{item.title}</span>}\n {item.extra && <span className=\"kzs-choice-extra\">{item.extra}</span>}\n {item.meta && <span className=\"kzs-choice-meta\">{item.meta}</span>}\n <span className=\"kzs-choice-check\" aria-hidden>\n <svg viewBox=\"0 0 24 24\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 5 5 9-10\" />\n </svg>\n </span>\n </>\n );\n const itemStyle = { \"--i\": i } as React.CSSProperties;\n let tile: React.ReactNode;\n if (selectable)\n tile = (\n <button\n ref={(el) => {\n refs.current[i] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={current === item.id}\n tabIndex={i === focusIndex ? 0 : -1}\n disabled={item.disabled}\n data-selectable=\"\"\n className=\"kzs-choice-item\"\n style={itemStyle}\n onClick={() => choose(i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n >\n {body}\n </button>\n );\n else if (item.href)\n tile = (\n <BlockLink href={item.href} linkAs={linkAs} className=\"kzs-choice-item\" data-link=\"\" style={itemStyle}>\n {body}\n </BlockLink>\n );\n else\n tile = (\n <div className=\"kzs-choice-item\" style={itemStyle}>\n {body}\n </div>\n );\n return (\n <Item key={item.id} className={cn(\"kzs-choice-slot\", brandClass(item.brand))} style={itemStyle}>\n {tile}\n </Item>\n );\n })}\n </Grid>\n </div>\n );\n}\n","// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} {...props} />;\n}\n","// Client. The URL is the state: a selection the user would want to share, reload or come back to (a tab, a type, a\n// filter) lives in a search parameter, never in `useState` (Oussama, 2026-10-22: « changer les tabs doit changer les routes »).\n// One primitive reads and writes it: `useRouteState`. The selection components take `routeKey` and bind to it.\nimport * as React from \"react\";\n\n/** How a router moves and reads the address: the browser's by default, your framework's through `RouteStateProvider`. */\nexport interface RouteAdapter {\n /** The current query string, with or without `?` (`\"\"` on the server). */\n search: () => string;\n /** Go to `search` (`?type=bail`, or `\"\"`), keeping the path and the hash; `replace` keeps the history as it is. */\n navigate: (search: string, options: { replace: boolean }) => void;\n /** Calls `onChange` when the address changes under you (back, forward, another navigation); returns the unsubscribe. */\n subscribe: (onChange: () => void) => () => void;\n}\n\nconst CHANGE = \"kz-route-state\";\n\n/** The History API: any web app (Vite, a static site). Next.js apps pass their router's adapter once, in the layout. */\nexport const browserAdapter: RouteAdapter = {\n search: () => (typeof window === \"undefined\" ? \"\" : window.location.search),\n navigate: (search, { replace }) => {\n const url = `${window.location.pathname}${search}${window.location.hash}`;\n window.history[replace ? \"replaceState\" : \"pushState\"](window.history.state, \"\", url);\n window.dispatchEvent(new Event(CHANGE));\n },\n subscribe: (onChange) => {\n window.addEventListener(\"popstate\", onChange);\n window.addEventListener(CHANGE, onChange);\n return () => {\n window.removeEventListener(\"popstate\", onChange);\n window.removeEventListener(CHANGE, onChange);\n };\n },\n};\n\nconst AdapterContext = React.createContext<RouteAdapter>(browserAdapter);\n\nexport interface RouteStateProviderProps {\n /** How your router reads the query string, navigates and tells about changes. */\n adapter: RouteAdapter;\n children: React.ReactNode;\n}\n\n/** Gives `useRouteState` your router: `<RouteStateProvider adapter={nextAdapter}>` once, in the root layout. */\nexport function RouteStateProvider({ adapter, children }: RouteStateProviderProps) {\n return <AdapterContext.Provider value={adapter}>{children}</AdapterContext.Provider>;\n}\n\nexport interface RouteStateOptions<V extends string> {\n /** The values the parameter may hold, as a const list: anything else in the address reads as the default. Omit for free text. */\n values?: readonly V[];\n /** The value when the parameter is absent. It is never written to the address (a clean URL). */\n default: V;\n /** `push` (the default) keeps each change in the history, `replace` overwrites it: use `replace` for a filter typed or toggled in passing. */\n history?: \"push\" | \"replace\";\n}\n\n/** The value a query string holds for `key`, checked against `values`. Pure: the hook and the tests share it. */\nexport function readRouteValue<V extends string>(search: string, key: string, { values, default: fallback }: Pick<RouteStateOptions<V>, \"values\" | \"default\">): V {\n const raw = new URLSearchParams(search).get(key);\n if (raw === null) return fallback;\n return !values || (values as readonly string[]).includes(raw) ? (raw as V) : fallback;\n}\n\n/** The query string with `key` set to `value` (removed when it is the default); every other parameter is kept. Pure. */\nexport function writeRouteValue(search: string, key: string, value: string, fallback: string): string {\n const params = new URLSearchParams(search);\n if (value === fallback) params.delete(key);\n else params.set(key, value);\n const text = params.toString();\n return text ? `?${text}` : \"\";\n}\n\n/**\n * A value kept in the URL's search parameter `key`: `const [type, setType] = useRouteState(\"type\", { values: TYPES, default: \"auto\" })`\n * with `const TYPES = [\"auto\", \"lease\", \"contract\", \"invoice\", \"other\"] as const`. The value is typed from the list, an\n * unknown one in the address reads as the default, the default is not written, other parameters are kept.\n * `key` undefined makes the hook inert (it returns the default) so a component can call it unconditionally.\n */\nexport function useRouteState<V extends string>(key: string | undefined, { values, default: fallback, history = \"push\" }: RouteStateOptions<V>): readonly [V, (next: V) => void] {\n const adapter = React.useContext(AdapterContext);\n const search = React.useSyncExternalStore(adapter.subscribe, adapter.search, () => \"\");\n const value = key === undefined ? fallback : readRouteValue(search, key, { values, default: fallback });\n const set = React.useCallback(\n (next: V) => {\n if (key === undefined) return;\n adapter.navigate(writeRouteValue(adapter.search(), key, next, fallback), { replace: history === \"replace\" });\n },\n [adapter, key, fallback, history],\n );\n return [value, set] as const;\n}\n\n/** What a selection component spreads on its root: `value` and `onValueChange` bound to the URL when `routeKey` is set. */\nexport interface RouteBindable {\n value?: string | null;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n}\n\n/** The props of a selection component bound to the URL (`routeKey`), or its own, unchanged, when there is no `routeKey`. */\nexport function useRouteBinding<P extends RouteBindable>(routeKey: string | undefined, routeValues: readonly string[] | undefined, props: P): P {\n const initial = props.defaultValue ?? props.value ?? routeValues?.[0] ?? \"\";\n const [value, set] = useRouteState<string>(routeKey, { values: routeValues, default: initial });\n if (routeKey === undefined) return props;\n return {\n ...props,\n value,\n defaultValue: undefined,\n onValueChange: (next: string) => {\n set(next);\n props.onValueChange?.(next);\n },\n };\n}\n"],"mappings":"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","names":["React","jsx","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/choice-grid/choice-grid.tsx","../src/block-link.tsx","../src/router/route-state.tsx"],"sourcesContent":["// Client. A row of choices shown as tiles — a visual, a name, a line (story.css): pick a plan, a persona, a team, a side.\n// Selectable (`onValueChange`), it is a radio group with roving focus; with `href` on its items, a set of links (a\n// line-up that leads somewhere); otherwise a showcase of the line-up.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { useRouteBinding } from \"../router\";\nimport { brandClass, type StoryVariant, storyVariantClass } from \"../story-variant\";\n\nexport interface ChoiceItem {\n /** The value of the choice (and its React key). */\n id: string;\n /** What represents it: a mark, an avatar, an illustration. Decorative — the name carries the meaning. */\n visual: React.ReactNode;\n /** Its name, short. */\n name: React.ReactNode;\n /** One line under the name: what it is, its role. */\n title?: React.ReactNode;\n /** A small line above the visual (a family, a tier), after its `icon`. */\n eyebrow?: React.ReactNode;\n /** A small glyph before the eyebrow (decorative). */\n icon?: React.ReactNode;\n /** A short tag in the top corner (“P1”, “New”, “Popular”). */\n badge?: React.ReactNode;\n /** Under the line: a gauge (`StatGauge`), facts, a price. */\n extra?: React.ReactNode;\n /** At the bottom: where the tile leads (“Chapter 2 ↓”, “See the plan”). */\n meta?: React.ReactNode;\n /** Makes the tile a link (ignored when the grid is selectable). */\n href?: string;\n /** A brand scope for this tile (`orazaka` → `.brand-orazaka`): its accent becomes that brand's. */\n brand?: string;\n /** Not selectable. */\n disabled?: boolean;\n}\n\nexport type ChoiceGridProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"defaultValue\" | \"onChange\"> & {\n /** The accessible name of the group (“Choose your plan”) — passed translated. */\n label: string;\n /** The choices, in reading order. */\n items: readonly ChoiceItem[];\n /** A short mono line above the grid (a step, a tag). */\n tag?: React.ReactNode;\n /** A line beside the tag: what the choice means. */\n caption?: React.ReactNode;\n /** A call above the tiles, larger (“Choose your plan”). */\n prompt?: React.ReactNode;\n /** The chosen id (controlled). */\n value?: string;\n /** The chosen id at first (uncontrolled). */\n defaultValue?: string;\n /** Makes the grid a radio group: called with the id chosen by click, Enter, Space or the arrow keys. */\n onValueChange?: (id: string) => void;\n /** Binds the choice to this search parameter of the URL (`?type=…`): the URL is the state. Without it the state is local — only for an ephemeral choice. */\n routeKey?: string;\n /** The ids the parameter may hold; the first is the default unless `defaultValue` says otherwise. */\n routeValues?: readonly string[];\n /** The app's link component for the tiles' internal `href`s (Next's `Link`); an `<a>` otherwise. */\n linkAs?: LinkComponent;\n /**\n * The number of columns (one on a phone).\n * @default min(items, 4)\n */\n columns?: number;\n /**\n * `default`: sober tiles. `arcade`: the select screen — the brand's light on each card, corners that lock, a flash.\n * @default \"default\"\n */\n variant?: StoryVariant;\n /** A brand scope for the whole grid (`orochia` → `.brand-orochia`). */\n brand?: string;\n /**\n * The tiles' arrival on mount (arcade: the corners locking one by one, the gauges filling). Always off under\n * `prefers-reduced-motion`.\n * @default true\n */\n animated?: boolean;\n};\n\nconst CORNERS = [\"tl\", \"tr\", \"bl\", \"br\"] as const;\n\n/**\n * A line-up of choices as tiles. With `onValueChange` (or `value`), a radio group: one tab stop, the arrow keys move\n * and choose, Home/End jump, the chosen tile is marked. With `href` on the items, a list of links. Otherwise a list\n * named by `label` that presents the line-up.\n */\nexport function ChoiceGrid({\n label,\n items,\n tag,\n caption,\n prompt,\n value: valueProp,\n defaultValue: defaultValueProp,\n onValueChange: onValueChangeProp,\n routeKey,\n routeValues,\n linkAs,\n columns,\n variant,\n brand,\n animated = true,\n className,\n style,\n ...props\n}: ChoiceGridProps) {\n const { value, defaultValue, onValueChange } = useRouteBinding(routeKey, routeValues, { value: valueProp, defaultValue: defaultValueProp, onValueChange: onValueChangeProp });\n const selectable = onValueChange !== undefined || value !== undefined;\n const [inner, setInner] = React.useState(defaultValue);\n const current = value ?? inner;\n const refs = React.useRef<(HTMLButtonElement | null)[]>([]);\n const enabled = items.map((item, i) => (item.disabled ? -1 : i)).filter((i) => i >= 0);\n const chosenIndex = items.findIndex((item) => item.id === current && !item.disabled);\n const focusIndex = chosenIndex >= 0 ? chosenIndex : (enabled[0] ?? 0);\n\n const choose = (i: number) => {\n const item = items[i];\n if (!item || item.disabled) return;\n if (value === undefined) setInner(item.id);\n onValueChange?.(item.id);\n };\n const onKeyDown = (e: React.KeyboardEvent, i: number) => {\n const at = enabled.indexOf(i);\n let next: number | undefined;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") next = enabled[(at + 1) % enabled.length];\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") next = enabled[(at - 1 + enabled.length) % enabled.length];\n else if (e.key === \"Home\") next = enabled[0];\n else if (e.key === \"End\") next = enabled[enabled.length - 1];\n if (next === undefined) return;\n e.preventDefault();\n refs.current[next]?.focus();\n choose(next);\n };\n\n // A radio group holds radios, not list items; a showcase or a set of links is a list named by `label`.\n const Grid = selectable ? \"div\" : \"ul\";\n const Item = selectable ? \"div\" : \"li\";\n const vars = { \"--kzs-cols\": columns ?? Math.min(items.length, 4), ...style } as React.CSSProperties;\n return (\n <div data-kzs-scene=\"\" data-animated={animated ? \"\" : undefined} className={cn(\"kzs-choice\", storyVariantClass(variant), brandClass(brand), className)} style={vars} {...props}>\n <span className=\"kzs-texture\" aria-hidden />\n <span className=\"kzs-scan kzs-loop\" aria-hidden />\n {(tag || caption) && (\n <p className=\"kzs-choice-head\">\n {tag && <span className=\"kzs-choice-tag\">{tag}</span>}\n {tag && caption && <span className=\"kzs-choice-sep\" aria-hidden />}\n {caption && <span className=\"kzs-choice-caption\">{caption}</span>}\n </p>\n )}\n {prompt && <p className=\"kzs-choice-prompt\">{prompt}</p>}\n <Grid className=\"kzs-choice-grid\" role={selectable ? \"radiogroup\" : undefined} aria-label={label}>\n {items.map((item, i) => {\n const body = (\n <>\n <span className=\"kzs-choice-aura\" aria-hidden />\n <span className=\"kzs-choice-flash\" aria-hidden />\n {CORNERS.map((at) => (\n <span key={at} className=\"kzs-corner\" data-at={at} aria-hidden />\n ))}\n {(item.badge || item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-top\">\n {item.badge ? <span className=\"kzs-choice-badge\">{item.badge}</span> : <span />}\n {(item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-eyebrow\">\n {item.icon && <span aria-hidden>{item.icon}</span>}\n {item.eyebrow}\n </span>\n )}\n </span>\n )}\n <span className=\"kzs-choice-frame\" aria-hidden>\n <span className=\"kzs-choice-floor\" />\n <span className=\"kzs-choice-visual\">{item.visual}</span>\n </span>\n <span className=\"kzs-choice-name\">{item.name}</span>\n {item.title && <span className=\"kzs-choice-title\">{item.title}</span>}\n {item.extra && <span className=\"kzs-choice-extra\">{item.extra}</span>}\n {item.meta && <span className=\"kzs-choice-meta\">{item.meta}</span>}\n <span className=\"kzs-choice-check\" aria-hidden>\n <svg viewBox=\"0 0 24 24\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 5 5 9-10\" />\n </svg>\n </span>\n </>\n );\n const itemStyle = { \"--i\": i } as React.CSSProperties;\n let tile: React.ReactNode;\n if (selectable)\n tile = (\n <button\n ref={(el) => {\n refs.current[i] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={current === item.id}\n tabIndex={i === focusIndex ? 0 : -1}\n disabled={item.disabled}\n data-selectable=\"\"\n className=\"kzs-choice-item\"\n style={itemStyle}\n onClick={() => choose(i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n >\n {body}\n </button>\n );\n else if (item.href)\n tile = (\n <BlockLink href={item.href} linkAs={linkAs} className=\"kzs-choice-item\" data-link=\"\" style={itemStyle}>\n {body}\n </BlockLink>\n );\n else\n tile = (\n <div className=\"kzs-choice-item\" style={itemStyle}>\n {body}\n </div>\n );\n return (\n <Item key={item.id} className={cn(\"kzs-choice-slot\", brandClass(item.brand))} style={itemStyle}>\n {tile}\n </Item>\n );\n })}\n </Grid>\n </div>\n );\n}\n","// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} rel={rel} {...props} />;\n}\n","// Client. The URL is the state: a selection the user would want to share, reload or come back to (a tab, a type, a\n// filter) lives in a search parameter, never in `useState` (Oussama, 2026-10-22: « changer les tabs doit changer les routes »).\n// One primitive reads and writes it: `useRouteState`. The selection components take `routeKey` and bind to it.\nimport * as React from \"react\";\n\n/** How a router moves and reads the address: the browser's by default, your framework's through `RouteStateProvider`. */\nexport interface RouteAdapter {\n /** The current query string, with or without `?` (`\"\"` on the server). */\n search: () => string;\n /** Go to `search` (`?type=bail`, or `\"\"`), keeping the path and the hash; `replace` keeps the history as it is. */\n navigate: (search: string, options: { replace: boolean }) => void;\n /** Calls `onChange` when the address changes under you (back, forward, another navigation); returns the unsubscribe. */\n subscribe: (onChange: () => void) => () => void;\n}\n\nconst CHANGE = \"kz-route-state\";\n\n/** The History API: any web app (Vite, a static site). Next.js apps pass their router's adapter once, in the layout. */\nexport const browserAdapter: RouteAdapter = {\n search: () => (typeof window === \"undefined\" ? \"\" : window.location.search),\n navigate: (search, { replace }) => {\n const url = `${window.location.pathname}${search}${window.location.hash}`;\n window.history[replace ? \"replaceState\" : \"pushState\"](window.history.state, \"\", url);\n window.dispatchEvent(new Event(CHANGE));\n },\n subscribe: (onChange) => {\n window.addEventListener(\"popstate\", onChange);\n window.addEventListener(CHANGE, onChange);\n return () => {\n window.removeEventListener(\"popstate\", onChange);\n window.removeEventListener(CHANGE, onChange);\n };\n },\n};\n\nconst AdapterContext = React.createContext<RouteAdapter>(browserAdapter);\n\nexport interface RouteStateProviderProps {\n /** How your router reads the query string, navigates and tells about changes. */\n adapter: RouteAdapter;\n children: React.ReactNode;\n}\n\n/** Gives `useRouteState` your router: `<RouteStateProvider adapter={nextAdapter}>` once, in the root layout. */\nexport function RouteStateProvider({ adapter, children }: RouteStateProviderProps) {\n return <AdapterContext.Provider value={adapter}>{children}</AdapterContext.Provider>;\n}\n\nexport interface RouteStateOptions<V extends string> {\n /** The values the parameter may hold, as a const list: anything else in the address reads as the default. Omit for free text. */\n values?: readonly V[];\n /** The value when the parameter is absent. It is never written to the address (a clean URL). */\n default: V;\n /** `push` (the default) keeps each change in the history, `replace` overwrites it: use `replace` for a filter typed or toggled in passing. */\n history?: \"push\" | \"replace\";\n}\n\n/** The value a query string holds for `key`, checked against `values`. Pure: the hook and the tests share it. */\nexport function readRouteValue<V extends string>(search: string, key: string, { values, default: fallback }: Pick<RouteStateOptions<V>, \"values\" | \"default\">): V {\n const raw = new URLSearchParams(search).get(key);\n if (raw === null) return fallback;\n return !values || (values as readonly string[]).includes(raw) ? (raw as V) : fallback;\n}\n\n/** The query string with `key` set to `value` (removed when it is the default); every other parameter is kept. Pure. */\nexport function writeRouteValue(search: string, key: string, value: string, fallback: string): string {\n const params = new URLSearchParams(search);\n if (value === fallback) params.delete(key);\n else params.set(key, value);\n const text = params.toString();\n return text ? `?${text}` : \"\";\n}\n\n/**\n * A value kept in the URL's search parameter `key`: `const [type, setType] = useRouteState(\"type\", { values: TYPES, default: \"auto\" })`\n * with `const TYPES = [\"auto\", \"lease\", \"contract\", \"invoice\", \"other\"] as const`. The value is typed from the list, an\n * unknown one in the address reads as the default, the default is not written, other parameters are kept.\n * `key` undefined makes the hook inert (it returns the default) so a component can call it unconditionally.\n */\nexport function useRouteState<V extends string>(key: string | undefined, { values, default: fallback, history = \"push\" }: RouteStateOptions<V>): readonly [V, (next: V) => void] {\n const adapter = React.useContext(AdapterContext);\n const search = React.useSyncExternalStore(adapter.subscribe, adapter.search, () => \"\");\n const value = key === undefined ? fallback : readRouteValue(search, key, { values, default: fallback });\n const set = React.useCallback(\n (next: V) => {\n if (key === undefined) return;\n adapter.navigate(writeRouteValue(adapter.search(), key, next, fallback), { replace: history === \"replace\" });\n },\n [adapter, key, fallback, history],\n );\n return [value, set] as const;\n}\n\n/** What a selection component spreads on its root: `value` and `onValueChange` bound to the URL when `routeKey` is set. */\nexport interface RouteBindable {\n value?: string | null;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n}\n\n/** The props of a selection component bound to the URL (`routeKey`), or its own, unchanged, when there is no `routeKey`. */\nexport function useRouteBinding<P extends RouteBindable>(routeKey: string | undefined, routeValues: readonly string[] | undefined, props: P): P {\n const initial = props.defaultValue ?? props.value ?? routeValues?.[0] ?? \"\";\n const [value, set] = useRouteState<string>(routeKey, { values: routeValues, default: initial });\n if (routeKey === undefined) return props;\n return {\n ...props,\n value,\n defaultValue: undefined,\n onValueChange: (next: string) => {\n set(next);\n props.onValueChange?.(next);\n },\n };\n}\n"],"mappings":"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","names":["React","jsx","jsx"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BlockLink,
|
|
3
3
|
isExternal
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FVGFPB73.js";
|
|
5
5
|
import {
|
|
6
6
|
ArrowGlyph,
|
|
7
7
|
ExternalGlyph
|
|
@@ -50,4 +50,4 @@ export {
|
|
|
50
50
|
cardHoverClass,
|
|
51
51
|
LinkCard
|
|
52
52
|
};
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
53
|
+
//# sourceMappingURL=chunk-7JG3VR4C.js.map
|
|
@@ -12,10 +12,10 @@ function BlockLink({
|
|
|
12
12
|
}) {
|
|
13
13
|
if (external) return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
14
14
|
const Comp = Link;
|
|
15
|
-
return /* @__PURE__ */ jsx(Comp, { href, ...props });
|
|
15
|
+
return /* @__PURE__ */ jsx(Comp, { href, rel, ...props });
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export {
|
|
19
19
|
BlockLink
|
|
20
20
|
};
|
|
21
|
-
//# sourceMappingURL=chunk-
|
|
21
|
+
//# sourceMappingURL=chunk-ENOS6ETI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} {...props} />;\n}\n"],"mappings":";;;AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,
|
|
1
|
+
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} rel={rel} {...props} />;\n}\n"],"mappings":";;;AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,MAAY,KAAW,GAAG,OAAO;AAChD;","names":[]}
|
|
@@ -10,11 +10,11 @@ function BlockLink({
|
|
|
10
10
|
}) {
|
|
11
11
|
if (external) return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
12
12
|
const Comp = Link;
|
|
13
|
-
return /* @__PURE__ */ jsx(Comp, { href, ...props });
|
|
13
|
+
return /* @__PURE__ */ jsx(Comp, { href, rel, ...props });
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export {
|
|
17
17
|
isExternal,
|
|
18
18
|
BlockLink
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=chunk-
|
|
20
|
+
//# sourceMappingURL=chunk-FVGFPB73.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} {...props} />;\n}\n"],"mappings":";AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,
|
|
1
|
+
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} rel={rel} {...props} />;\n}\n"],"mappings":";AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,MAAY,KAAW,GAAG,OAAO;AAChD;","names":[]}
|
package/dist/cover-hero.js
CHANGED
package/dist/link-card.js
CHANGED
package/dist/media-grid.js
CHANGED
|
@@ -82,7 +82,7 @@ function BlockLink({
|
|
|
82
82
|
}) {
|
|
83
83
|
if (external) return /* @__PURE__ */ jsx3("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
84
84
|
const Comp = Link;
|
|
85
|
-
return /* @__PURE__ */ jsx3(Comp, { href, ...props });
|
|
85
|
+
return /* @__PURE__ */ jsx3(Comp, { href, rel, ...props });
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// src/media-grid/section-hint.tsx
|