@krizaka/ui 3.53.0 → 3.55.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/README.md +1 -0
- package/dist/account-menu.d.ts +6 -2
- package/dist/account-menu.js +8 -1
- package/dist/account-menu.js.map +1 -1
- package/dist/account-settings.js +28 -88
- package/dist/account-settings.js.map +1 -1
- package/dist/anatomy-plate.d.ts +4 -1
- package/dist/anatomy-plate.js +4 -0
- package/dist/anatomy-plate.js.map +1 -1
- package/dist/app-header/search.d.ts +63 -0
- package/dist/app-header/search.js +70 -0
- package/dist/app-header/search.js.map +1 -0
- package/dist/app-header.d.ts +88 -4
- package/dist/app-header.js +63 -5
- package/dist/app-header.js.map +1 -1
- package/dist/app-shell.js +31 -40
- package/dist/app-shell.js.map +1 -1
- package/dist/argument-card.js +3 -3
- package/dist/bird-plate.d.ts +3 -1
- package/dist/bird-plate.js +2 -2
- package/dist/bird-plate.js.map +1 -1
- package/dist/blocks.css +202 -27
- package/dist/chapter.d.ts +20 -3
- package/dist/chapter.js +82 -31
- package/dist/chapter.js.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/chat.js.map +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/chip.js +5 -98
- package/dist/chip.js.map +1 -1
- package/dist/choice-grid.js +28 -88
- package/dist/choice-grid.js.map +1 -1
- package/dist/{chunk-YGIN2YIY.js → chunk-3X3OF4TI.js} +2 -2
- package/dist/chunk-3X3OF4TI.js.map +1 -0
- package/dist/chunk-5VEVYDVC.js +11 -0
- package/dist/chunk-5VEVYDVC.js.map +1 -0
- package/dist/chunk-7U5TXA5Q.js +105 -0
- package/dist/chunk-7U5TXA5Q.js.map +1 -0
- package/dist/{chunk-KBQD6HE3.js → chunk-AEP3K4YD.js} +3 -3
- package/dist/{chunk-KBQD6HE3.js.map → chunk-AEP3K4YD.js.map} +1 -1
- package/dist/chunk-BDIU5LZB.js +18 -0
- package/dist/chunk-BDIU5LZB.js.map +1 -0
- package/dist/chunk-CSRKYZ53.js +39 -0
- package/dist/chunk-CSRKYZ53.js.map +1 -0
- package/dist/chunk-HEKDKM5Y.js +128 -0
- package/dist/chunk-HEKDKM5Y.js.map +1 -0
- package/dist/chunk-KGLRZMCY.js +16 -0
- package/dist/chunk-KGLRZMCY.js.map +1 -0
- package/dist/chunk-KID32IRJ.js +18 -0
- package/dist/chunk-KID32IRJ.js.map +1 -0
- package/dist/{chunk-ZQW7LF4Y.js → chunk-OIMXKRXF.js} +2 -2
- package/dist/{chunk-YHKTYFOQ.js → chunk-QWKCNSPF.js} +271 -47
- package/dist/chunk-QWKCNSPF.js.map +1 -0
- package/dist/{chunk-4LYKBSOG.js → chunk-USPOIQV5.js} +2 -2
- package/dist/chunk-USPOIQV5.js.map +1 -0
- package/dist/{chunk-7NRSPHAF.js → chunk-VB7MWE2N.js} +2 -2
- package/dist/{chunk-7NRSPHAF.js.map → chunk-VB7MWE2N.js.map} +1 -1
- package/dist/chunk-VIPSZXO4.js +103 -0
- package/dist/chunk-VIPSZXO4.js.map +1 -0
- package/dist/chunk-YCZ7N6Q6.js +385 -0
- package/dist/chunk-YCZ7N6Q6.js.map +1 -0
- package/dist/code-block.js +81 -98
- package/dist/code-block.js.map +1 -1
- package/dist/combobox.js +2 -2
- package/dist/component-page.d.ts +4 -1
- package/dist/component-page.js +5 -0
- package/dist/component-page.js.map +1 -1
- package/dist/continue-prompt.d.ts +4 -1
- package/dist/continue-prompt.js +4 -0
- package/dist/continue-prompt.js.map +1 -1
- package/dist/data-table.d.ts +60 -4
- package/dist/data-table.js +19 -7
- package/dist/date-picker.js +2 -2
- package/dist/date-picker.js.map +1 -1
- package/dist/detail-layout.d.ts +28 -17
- package/dist/detail-layout.js +73 -16
- package/dist/detail-layout.js.map +1 -1
- package/dist/doodle.d.ts +21 -0
- package/dist/doodle.js +39 -0
- package/dist/doodle.js.map +1 -0
- package/dist/drop-overlay.d.ts +12 -4
- package/dist/drop-overlay.js +16 -6
- package/dist/drop-overlay.js.map +1 -1
- package/dist/elephant.d.ts +2 -0
- package/dist/elephant.js +4 -0
- package/dist/elephant.js.map +1 -1
- package/dist/field.js +1 -1
- package/dist/field.js.map +1 -1
- package/dist/filter-bar.js +2 -2
- package/dist/force-update-screen.d.ts +5 -1
- package/dist/force-update-screen.js +4 -0
- package/dist/force-update-screen.js.map +1 -1
- package/dist/gallery-page.d.ts +4 -1
- package/dist/gallery-page.js +4 -0
- package/dist/gallery-page.js.map +1 -1
- package/dist/genui.js +5 -5
- package/dist/image-cropper.d.ts +10 -2
- package/dist/image-cropper.js +4 -0
- package/dist/image-cropper.js.map +1 -1
- package/dist/kanban.d.ts +3 -0
- package/dist/kanban.js +4 -0
- package/dist/kanban.js.map +1 -1
- package/dist/landscape.d.ts +4 -1
- package/dist/landscape.js +4 -0
- package/dist/landscape.js.map +1 -1
- package/dist/list.js +1 -1
- package/dist/maintenance-screen.d.ts +5 -1
- package/dist/maintenance-screen.js +4 -0
- package/dist/maintenance-screen.js.map +1 -1
- package/dist/map.js +6 -0
- package/dist/map.js.map +1 -1
- package/dist/markdown.d.ts +5 -1
- package/dist/markdown.js +12 -5
- package/dist/markdown.js.map +1 -1
- package/dist/match-dialog.d.ts +4 -1
- package/dist/match-dialog.js +4 -0
- package/dist/match-dialog.js.map +1 -1
- package/dist/media-capture.d.ts +6 -1
- package/dist/media-capture.js +4 -0
- package/dist/media-capture.js.map +1 -1
- package/dist/meter.js +5 -121
- package/dist/meter.js.map +1 -1
- package/dist/native/map.js +6 -0
- package/dist/native/map.js.map +1 -1
- package/dist/native/markdown.d.ts +9 -2
- package/dist/native/markdown.js +46 -7
- package/dist/native/markdown.js.map +1 -1
- package/dist/native/media-capture.d.ts +1 -0
- package/dist/native/media-capture.js +5 -0
- package/dist/native/media-capture.js.map +1 -1
- package/dist/native/vertical-video.d.ts +8 -2
- package/dist/native/vertical-video.js +6 -0
- package/dist/native/vertical-video.js.map +1 -1
- package/dist/native.d.ts +94 -4
- package/dist/native.js +1236 -1110
- package/dist/native.js.map +1 -1
- package/dist/nav-bar/me.d.ts +32 -0
- package/dist/nav-bar/me.js +23 -0
- package/dist/nav-bar/me.js.map +1 -0
- package/dist/nav-bar.d.ts +60 -2
- package/dist/nav-bar.js +92 -48
- package/dist/nav-bar.js.map +1 -1
- package/dist/notification-preferences.d.ts +151 -0
- package/dist/notification-preferences.js +77 -0
- package/dist/notification-preferences.js.map +1 -0
- package/dist/page-header.js +1 -1
- package/dist/page-header.js.map +1 -1
- package/dist/pointer-light.js +5 -0
- package/dist/pointer-light.js.map +1 -1
- package/dist/product-page.d.ts +4 -1
- package/dist/product-page.js +4 -0
- package/dist/product-page.js.map +1 -1
- package/dist/profile-card.d.ts +119 -1
- package/dist/profile-card.js +68 -21
- package/dist/profile-card.js.map +1 -1
- package/dist/promise-card.d.ts +4 -1
- package/dist/promise-card.js +4 -0
- package/dist/promise-card.js.map +1 -1
- package/dist/quota-meter.d.ts +113 -0
- package/dist/quota-meter.js +58 -0
- package/dist/quota-meter.js.map +1 -0
- package/dist/radio-group.js +6 -8
- package/dist/radio-group.js.map +1 -1
- package/dist/rail-nav.d.ts +18 -2
- package/dist/rail-nav.js +25 -2
- package/dist/rail-nav.js.map +1 -1
- package/dist/retro-tv.d.ts +30 -0
- package/dist/retro-tv.js +124 -0
- package/dist/retro-tv.js.map +1 -0
- package/dist/router.d.ts +12 -1
- package/dist/router.js +85 -8
- package/dist/router.js.map +1 -1
- package/dist/scroll-stage.d.ts +5 -1
- package/dist/scroll-stage.js +5 -0
- package/dist/scroll-stage.js.map +1 -1
- package/dist/search-field.js +1 -1
- package/dist/showcase.d.ts +9 -2
- package/dist/showcase.js +5 -0
- package/dist/showcase.js.map +1 -1
- package/dist/signature.d.ts +19 -0
- package/dist/signature.js +39 -0
- package/dist/signature.js.map +1 -0
- package/dist/site-footer.js +1 -1
- package/dist/sites.js +1 -1
- package/dist/sites.js.map +1 -1
- package/dist/slot.d.ts +1 -1
- package/dist/stat.js +1 -1
- package/dist/stat.js.map +1 -1
- package/dist/status-page.d.ts +4 -1
- package/dist/status-page.js +5 -0
- package/dist/status-page.js.map +1 -1
- package/dist/stuck.d.ts +27 -0
- package/dist/stuck.js +26 -0
- package/dist/stuck.js.map +1 -0
- package/dist/swipe-deck.d.ts +9 -2
- package/dist/swipe-deck.js +5 -0
- package/dist/swipe-deck.js.map +1 -1
- package/dist/switch.js +4 -32
- package/dist/switch.js.map +1 -1
- package/dist/tabs.d.ts +47 -8
- package/dist/tabs.js +62 -12
- package/dist/tabs.js.map +1 -1
- package/dist/tag-input.js +2 -2
- package/dist/tag-selector.js +1 -1
- package/dist/terminal-replay.d.ts +4 -1
- package/dist/terminal-replay.js +4 -0
- package/dist/terminal-replay.js.map +1 -1
- package/dist/tree-view.js +4 -0
- package/dist/tree-view.js.map +1 -1
- package/dist/update-prompt.d.ts +5 -1
- package/dist/update-prompt.js +4 -0
- package/dist/update-prompt.js.map +1 -1
- package/dist/video-player.js +7 -376
- package/dist/video-player.js.map +1 -1
- package/dist/video-trimmer.d.ts +6 -1
- package/dist/video-trimmer.js +4 -0
- package/dist/video-trimmer.js.map +1 -1
- package/package.json +143 -31
- package/registry/account-menu.json +9 -8
- package/registry/account-settings.json +2 -2
- package/registry/achievement.json +3 -4
- package/registry/action-bar.json +3 -3
- package/registry/action-sheet.json +1 -0
- package/registry/activity-feed.json +2 -1
- package/registry/agenda.json +1 -1
- package/registry/alert.json +1 -1
- package/registry/anatomy-plate.json +13 -5
- package/registry/app-header.json +470 -23
- package/registry/app-shell.json +2 -2
- package/registry/argument-card.json +1 -1
- package/registry/audio-player.json +1 -1
- package/registry/auth-layout.json +1 -1
- package/registry/avatar.json +3 -2
- package/registry/badge.json +2 -1
- package/registry/bird-plate.json +16 -2
- package/registry/button.json +7 -6
- package/registry/captcha.json +1 -1
- package/registry/card-grid.json +1 -1
- package/registry/card.json +7 -6
- package/registry/catalogue-page.json +3 -4
- package/registry/changelog-page.json +3 -5
- package/registry/chapter.json +46 -10
- package/registry/chat.json +3 -2
- package/registry/checkbox.json +4 -3
- package/registry/chip-link.json +2 -2
- package/registry/chip-row.json +2 -2
- package/registry/chip.json +3 -2
- package/registry/choice-grid.json +3 -4
- package/registry/code-block.json +1 -1
- package/registry/combobox.json +3 -2
- package/registry/command.json +2 -2
- package/registry/comparison-table.json +1 -1
- package/registry/component-page.json +14 -5
- package/registry/confirm-button.json +4 -4
- package/registry/contact-page.json +1 -1
- package/registry/continue-prompt.json +13 -5
- package/registry/countdown.json +4 -3
- package/registry/cover-hero.json +3 -4
- package/registry/cta-panel.json +1 -1
- package/registry/dashboard-layout.json +1 -1
- package/registry/data-table.json +63 -7
- package/registry/date-picker.json +5 -4
- package/registry/decision-list.json +1 -1
- package/registry/description-list.json +2 -1
- package/registry/detail-layout.json +30 -6
- package/registry/dialog.json +7 -6
- package/registry/docs-article-page.json +3 -4
- 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 +3 -5
- package/registry/doodle.json +209 -0
- package/registry/drop-overlay.json +30 -16
- package/registry/dropdown-menu.json +2 -2
- package/registry/elephant.json +15 -7
- package/registry/empty-state.json +2 -1
- package/registry/engine-flow.json +1 -1
- package/registry/error-page.json +3 -5
- package/registry/examples/app-header/family.d.ts +4 -0
- package/registry/examples/app-header/family.js +41 -0
- package/registry/examples/app-header/family.tsx +37 -0
- package/registry/examples/app-header/native/family.d.ts +4 -0
- package/registry/examples/app-header/native/family.dark.png +0 -0
- package/registry/examples/app-header/native/family.js +25 -0
- package/registry/examples/app-header/native/family.light.png +0 -0
- package/registry/examples/app-header/native/family.tsx +33 -0
- package/registry/examples/chapter/album.d.ts +4 -0
- package/registry/examples/chapter/album.js +34 -0
- package/registry/examples/chapter/album.tsx +30 -0
- package/registry/examples/chapter/in-ruled-page.d.ts +4 -0
- package/registry/examples/chapter/in-ruled-page.js +23 -0
- package/registry/examples/chapter/in-ruled-page.tsx +19 -0
- package/registry/examples/data-table/applicant-files.d.ts +4 -0
- package/registry/examples/data-table/applicant-files.js +24 -0
- package/registry/examples/data-table/applicant-files.tsx +23 -0
- package/registry/examples/data-table/checks.d.ts +4 -0
- package/registry/examples/data-table/checks.js +25 -0
- package/registry/examples/data-table/checks.tsx +24 -0
- package/registry/examples/detail-layout/profile.d.ts +4 -0
- package/registry/examples/detail-layout/profile.js +26 -0
- package/registry/examples/detail-layout/profile.tsx +21 -0
- package/registry/examples/doodle/kinds.d.ts +4 -0
- package/registry/examples/doodle/kinds.js +17 -0
- package/registry/examples/doodle/kinds.tsx +14 -0
- package/registry/examples/doodle/margin.d.ts +4 -0
- package/registry/examples/doodle/margin.js +17 -0
- package/registry/examples/doodle/margin.tsx +17 -0
- package/registry/examples/markdown/native/basic.dark.png +0 -0
- package/registry/examples/markdown/native/basic.light.png +0 -0
- package/registry/examples/markdown/native/wide-table.d.ts +4 -0
- package/registry/examples/markdown/native/wide-table.dark.png +0 -0
- package/registry/examples/markdown/native/wide-table.js +23 -0
- package/registry/examples/markdown/native/wide-table.light.png +0 -0
- package/registry/examples/markdown/native/wide-table.tsx +22 -0
- package/registry/examples/markdown/wide-table.d.ts +4 -0
- package/registry/examples/markdown/wide-table.js +28 -0
- package/registry/examples/markdown/wide-table.tsx +23 -0
- package/registry/examples/nav-bar/family-product.js +2 -4
- package/registry/examples/nav-bar/family-product.tsx +3 -5
- package/registry/examples/notification-preferences/default.d.ts +4 -0
- package/registry/examples/notification-preferences/default.js +29 -0
- package/registry/examples/notification-preferences/default.tsx +28 -0
- package/registry/examples/profile-card/banner.d.ts +4 -0
- package/registry/examples/profile-card/banner.js +28 -0
- package/registry/examples/profile-card/banner.tsx +24 -0
- package/registry/examples/profile-card/native/banner.d.ts +4 -0
- package/registry/examples/profile-card/native/banner.dark.png +0 -0
- package/registry/examples/profile-card/native/banner.js +22 -0
- package/registry/examples/profile-card/native/banner.light.png +0 -0
- package/registry/examples/profile-card/native/banner.tsx +18 -0
- package/registry/examples/quota-meter/default.d.ts +4 -0
- package/registry/examples/quota-meter/default.js +26 -0
- package/registry/examples/quota-meter/default.tsx +20 -0
- package/registry/examples/quota-meter/full.d.ts +4 -0
- package/registry/examples/quota-meter/full.js +25 -0
- package/registry/examples/quota-meter/full.tsx +18 -0
- package/registry/examples/rail-nav/shortcuts.d.ts +4 -0
- package/registry/examples/rail-nav/shortcuts.js +49 -0
- package/registry/examples/rail-nav/shortcuts.tsx +40 -0
- package/registry/examples/retro-tv/cabinet.d.ts +4 -0
- package/registry/examples/retro-tv/cabinet.js +12 -0
- package/registry/examples/retro-tv/cabinet.tsx +7 -0
- package/registry/examples/retro-tv/portable.d.ts +4 -0
- package/registry/examples/retro-tv/portable.js +12 -0
- package/registry/examples/retro-tv/portable.tsx +7 -0
- package/registry/examples/signature/both.d.ts +4 -0
- package/registry/examples/signature/both.js +11 -0
- package/registry/examples/signature/both.tsx +6 -0
- package/registry/examples/signature/variants.d.ts +4 -0
- package/registry/examples/signature/variants.js +14 -0
- package/registry/examples/signature/variants.tsx +11 -0
- package/registry/examples/stuck/card.d.ts +4 -0
- package/registry/examples/stuck/card.js +13 -0
- package/registry/examples/stuck/card.tsx +14 -0
- package/registry/examples/stuck/holds.d.ts +4 -0
- package/registry/examples/stuck/holds.js +12 -0
- package/registry/examples/stuck/holds.tsx +16 -0
- package/registry/examples/stuck/tag.d.ts +4 -0
- package/registry/examples/stuck/tag.js +12 -0
- package/registry/examples/stuck/tag.tsx +13 -0
- package/registry/examples/tabs/binder.d.ts +4 -0
- package/registry/examples/tabs/binder.js +22 -0
- package/registry/examples/tabs/binder.tsx +20 -0
- package/registry/examples/tabs/native/binder.d.ts +4 -0
- package/registry/examples/tabs/native/binder.dark.png +0 -0
- package/registry/examples/tabs/native/binder.js +26 -0
- package/registry/examples/tabs/native/binder.light.png +0 -0
- package/registry/examples/tabs/native/binder.tsx +22 -0
- package/registry/fab.json +1 -0
- package/registry/field.json +3 -2
- package/registry/file-upload.json +6 -11
- package/registry/filter-bar.json +2 -2
- package/registry/flock.json +3 -4
- package/registry/footnote.json +2 -3
- package/registry/force-update-screen.json +14 -5
- package/registry/form.json +5 -4
- package/registry/gallery-page.json +14 -5
- package/registry/genui.json +2 -2
- package/registry/glossary-term.json +1 -1
- package/registry/glossary.json +1 -1
- package/registry/glow-card.json +2 -2
- package/registry/goal-gauge.json +2 -1
- package/registry/header.json +1 -0
- package/registry/how-it-works-page.json +3 -5
- package/registry/image-cropper.json +13 -5
- package/registry/image-viewer.json +3 -4
- package/registry/index.json +306 -91
- package/registry/iso.json +1 -1
- package/registry/kanban.json +13 -5
- package/registry/kbd.json +1 -1
- package/registry/kpi-explained.json +2 -2
- package/registry/landing-page.json +3 -5
- package/registry/landscape.json +13 -5
- package/registry/language-switch.json +1 -1
- package/registry/legal-page.json +1 -1
- package/registry/link-card.json +1 -1
- package/registry/list.json +2 -1
- package/registry/loader.json +2 -1
- package/registry/longform-page.json +1 -1
- package/registry/maintenance-screen.json +14 -5
- package/registry/map.json +3 -2
- package/registry/markdown.json +86 -9
- 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 +12 -11
- package/registry/mascots.json +2 -1
- package/registry/match-dialog.json +14 -5
- package/registry/media-capture.json +14 -5
- package/registry/media-gallery.json +3 -5
- package/registry/media-grid.json +1 -1
- package/registry/media-picker.json +2 -3
- package/registry/meta-row.json +2 -1
- package/registry/meter.json +4 -3
- package/registry/nav-bar.json +100 -9
- package/registry/next-actions.json +1 -1
- package/registry/notification-preferences.json +250 -0
- package/registry/number-ticker.json +2 -1
- package/registry/onboarding.json +1 -0
- package/registry/opening-hours.json +1 -1
- package/registry/otp-input.json +1 -0
- package/registry/page-header.json +2 -2
- package/registry/page-hero.json +1 -1
- package/registry/page-index.json +1 -1
- package/registry/page.json +3 -3
- package/registry/pagination.json +2 -1
- package/registry/permission-prompt.json +2 -2
- package/registry/photo-grid.json +4 -4
- package/registry/pointer-light.json +6 -2
- package/registry/popover.json +2 -2
- package/registry/pricing-page.json +4 -6
- package/registry/product-page.json +14 -5
- package/registry/profile-card.json +232 -8
- package/registry/progress.json +4 -3
- package/registry/promise-card.json +13 -5
- package/registry/pull-to-refresh.json +1 -0
- package/registry/quota-meter.json +308 -0
- package/registry/radio-group.json +4 -3
- package/registry/rail-nav.json +48 -10
- package/registry/recipes.json +1 -1
- package/registry/retro-tv.json +478 -0
- package/registry/router.json +3 -3
- package/registry/screen.json +1 -0
- package/registry/scroll-stage.json +14 -5
- package/registry/search-field.json +3 -2
- package/registry/section-backdrop.json +1 -1
- package/registry/segmented.json +1 -0
- package/registry/separator.json +2 -2
- package/registry/service-card.json +1 -1
- package/registry/settings-layout.json +2 -1
- package/registry/showcase.json +14 -5
- package/registry/signature.json +185 -0
- package/registry/site-footer.json +3 -3
- package/registry/sites.json +2 -2
- package/registry/skeleton.json +2 -1
- package/registry/skip-link.json +1 -1
- package/registry/slider.json +5 -4
- package/registry/slot-picker.json +1 -1
- package/registry/slot.json +2 -2
- package/registry/specimen-tag.json +1 -1
- package/registry/spinner.json +4 -3
- package/registry/splash-handoff.json +1 -0
- package/registry/split-view.json +1 -1
- package/registry/stage-banner.json +2 -3
- package/registry/stat.json +2 -2
- package/registry/status-page.json +13 -5
- package/registry/step-progress.json +2 -1
- package/registry/step-showcase.json +3 -5
- package/registry/stepper.json +2 -1
- package/registry/sticky-action.json +1 -1
- package/registry/stuck.json +219 -0
- package/registry/swipe-deck.json +14 -5
- package/registry/swipeable-row.json +1 -0
- package/registry/switch.json +3 -2
- package/registry/tab-bar.json +1 -0
- package/registry/tabs.json +154 -22
- package/registry/tag-input.json +1 -1
- package/registry/tag-selector.json +2 -1
- package/registry/taped-photo.json +1 -1
- package/registry/terminal-replay.json +14 -5
- package/registry/text-style.json +5 -5
- package/registry/theme.json +2 -1
- package/registry/toast.json +2 -1
- package/registry/toc.json +1 -1
- package/registry/tooltip.json +2 -2
- package/registry/tree-view.json +6 -2
- package/registry/txt.json +1 -0
- package/registry/update-prompt.json +14 -5
- package/registry/upload-queue.json +1 -1
- package/registry/verified-badge.json +6 -6
- package/registry/vertical-video.json +8 -3
- package/registry/video-player.json +5 -6
- package/registry/video-trimmer.json +13 -5
- package/registry/virtual.json +2 -2
- package/registry/waveform.json +4 -3
- package/dist/chunk-4LYKBSOG.js.map +0 -1
- package/dist/chunk-HHFWK2HH.js +0 -163
- package/dist/chunk-HHFWK2HH.js.map +0 -1
- package/dist/chunk-R3LTSMS5.js +0 -75
- package/dist/chunk-R3LTSMS5.js.map +0 -1
- package/dist/chunk-YGIN2YIY.js.map +0 -1
- package/dist/chunk-YHKTYFOQ.js.map +0 -1
- /package/dist/{chunk-ZQW7LF4Y.js.map → chunk-OIMXKRXF.js.map} +0 -0
package/README.md
CHANGED
|
@@ -191,6 +191,7 @@ light or a product's — is a set of tokens.
|
|
|
191
191
|
| `@krizaka/ui/date-picker` | `DatePicker`, `DateRangePicker` (`presets`), `Calendar` — ISO dates, the locale's names through `@krizaka/intl`, `min`/`max`/`isDateDisabled`, the APG grid keyboard | client |
|
|
192
192
|
| `@krizaka/ui/search-field` | `SearchField` (`onSearch` debounced, `onSubmit`, `shortcut` ⌘K, `suggestions`, `clearLabel`, `landmark`) | client |
|
|
193
193
|
| `@krizaka/ui/video-player` | `VideoPlayer` (`src` or a signed-source function, `loadHls={() => import("hls.js")}` (optional peer, loaded only without native HLS), `tracks`, `playbackRates`, `preload`, `pauseWhenHidden`, `overlay` for a gate, `labels`; keyboard Space/K, J/L, arrows, M, F, C) | client |
|
|
194
|
+
| `@krizaka/ui/retro-tv` | `RetroTv` (vertical `VideoPlayer` in a `cabinet` or `portable` frame, `channel`, `off`, `tracks`; muted autoplay while on screen, lazy by default) | client |
|
|
194
195
|
| `@krizaka/ui/file-upload` | `Dropzone` (`accept`, `maxSize`, `maxFiles`, refusals with reasons), `UploadList` (preview, progress, speed, pause/resume/retry/cancel), `useUploadQueue` (`upload(file, { signal, onProgress, resumed })`: Tus-ready without depending on it; `retries`, `backoff`, `shouldRetry` — a queue of `@krizaka/pacer`), `acceptsFile`, `formatBytes` | client |
|
|
195
196
|
| `@krizaka/ui/media-capture` | `MediaCapture` (`mode` photo·video·both, `facing`, `maxDuration`, permission asked on a gesture, the file picker as the way out, `onCapture({ blob, kind, url })`) | client |
|
|
196
197
|
| `@krizaka/ui/video-trimmer` | `VideoTrimmer` (`duration`, `value` [start, end], `minLength`, `step`/`largeStep`, `frames` or children, `time` + `onSeek`, `classNames` per part, `renderHandle`) | client |
|
package/dist/account-menu.d.ts
CHANGED
|
@@ -29,8 +29,12 @@ interface AccountMenuProps {
|
|
|
29
29
|
email?: string;
|
|
30
30
|
/** The picture: `src`, or `defaultAvatar` (`{ brand, seed }`) for the product's default person. */
|
|
31
31
|
avatar?: Omit<AvatarProps, "size">;
|
|
32
|
-
/**
|
|
33
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Show the name beside the avatar in the trigger: `true` or `"sm"` from 640 px, `"lg"` from 1024 px (the family's top
|
|
34
|
+
* bar, where search and the counts take the room below it), `false` never.
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
showName?: boolean | "sm" | "lg";
|
|
34
38
|
/** Where to go: profile, settings… */
|
|
35
39
|
links?: readonly AccountMenuLink[];
|
|
36
40
|
/** The app's link component (Next's `Link`); an `<a>` otherwise. */
|
package/dist/account-menu.js
CHANGED
|
@@ -92,7 +92,14 @@ function AccountMenu({ label, name, email, avatar, showName = true, links = [],
|
|
|
92
92
|
className: cn("flex items-center gap-2.5 rounded-lg p-1 transition-colors duration-150 hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring", className),
|
|
93
93
|
children: [
|
|
94
94
|
/* @__PURE__ */ jsx2(Avatar, { size: "sm", fallback: title.charAt(0).toUpperCase() || "?", ...avatar }),
|
|
95
|
-
showName && title && /* @__PURE__ */ jsx2(
|
|
95
|
+
showName && title && /* @__PURE__ */ jsx2(
|
|
96
|
+
"span",
|
|
97
|
+
{
|
|
98
|
+
"aria-hidden": true,
|
|
99
|
+
"data-name": title,
|
|
100
|
+
className: cn("hidden max-w-40 truncate text-sm font-medium text-fg-secondary after:content-[attr(data-name)]", showName === "lg" ? "lg:inline-block" : "sm:inline-block")
|
|
101
|
+
}
|
|
102
|
+
)
|
|
96
103
|
]
|
|
97
104
|
}
|
|
98
105
|
),
|
package/dist/account-menu.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dropdown-menu/dropdown-menu.tsx","../src/floating.ts","../src/account-menu/account-menu.tsx"],"sourcesContent":["// Client (a portal). Radix does the roving focus, the arrows, Home/End, typeahead, Escape and the focus return.\nimport { DropdownMenu as MenuPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\nexport const menu = tv({\n slots: {\n content: cn(floating, \"min-w-48 max-h-(--radix-dropdown-menu-content-available-height) overflow-y-auto overflow-x-hidden overscroll-contain p-1 origin-(--radix-dropdown-menu-content-transform-origin)\"),\n item:\n \"relative flex cursor-pointer select-none items-center gap-2 rounded-md px-2.5 py-2 text-sm text-fg outline-hidden transition-colors \" +\n \"data-highlighted:bg-surface-3 data-disabled:pointer-events-none data-disabled:opacity-40 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 \" +\n \"[&>svg]:text-fg-secondary\",\n indicator: \"ml-auto flex h-4 w-4 items-center justify-center text-fg-accent\",\n label: \"px-2.5 pb-1 pt-2 text-[11px] font-semibold text-fg-secondary\",\n separator: \"-mx-1 my-1 h-px bg-border-subtle\",\n },\n variants: {\n // The label reads in the danger text role (≥ 4.5:1 on the menu surface, both themes); the icon and the highlight\n // carry the danger fill.\n tone: { default: {}, danger: { item: \"text-fg-danger data-highlighted:bg-danger/15 [&>svg]:text-danger\" } },\n },\n defaultVariants: { tone: \"default\" },\n});\nconst s = menu();\n\nexport type DropdownMenuContentProps = React.ComponentProps<typeof MenuPrimitive.Content> & {\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function DropdownMenuContent({ sideOffset = 6, align = \"end\", collisionPadding = 8, container, className, ...props }: DropdownMenuContentProps) {\n return (\n <MenuPrimitive.Portal container={container}>\n <MenuPrimitive.Content sideOffset={sideOffset} align={align} collisionPadding={collisionPadding} className={s.content({ className })} {...props} />\n </MenuPrimitive.Portal>\n );\n}\n\nexport type DropdownMenuItemProps = React.ComponentProps<typeof MenuPrimitive.Item> & {\n /** `danger` for a destructive action: the icon and the highlight carry the danger, the label stays legible. */\n tone?: \"default\" | \"danger\";\n};\n\n/** An action. `tone=\"danger\"` for a destructive one; `onSelect` runs it (the menu closes). */\nexport function DropdownMenuItem({ tone, className, ...props }: DropdownMenuItemProps) {\n return <MenuPrimitive.Item data-tone={tone ?? \"default\"} className={menu({ tone }).item({ className })} {...props} />;\n}\n\n/** A toggled option: `checked` + `onCheckedChange`. */\nexport function DropdownMenuCheckboxItem({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.CheckboxItem>) {\n return (\n <MenuPrimitive.CheckboxItem className={s.item({ className })} {...props}>\n {children}\n <MenuPrimitive.ItemIndicator className={s.indicator()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </MenuPrimitive.ItemIndicator>\n </MenuPrimitive.CheckboxItem>\n );\n}\n\n/** A submenu's trigger: an item that opens `DropdownMenu.SubContent`, with a chevron. */\nexport function DropdownMenuSubTrigger({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.SubTrigger>) {\n return (\n <MenuPrimitive.SubTrigger className={s.item({ className: cn(\"data-[state=open]:bg-surface-3\", className) })} {...props}>\n {children}\n <svg className=\"ml-auto !h-4 !w-4 text-fg-secondary\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </MenuPrimitive.SubTrigger>\n );\n}\n\n/** The submenu's panel (same material as the menu). */\nexport function DropdownMenuSubContent({ sideOffset = 4, collisionPadding = 8, className, ...props }: React.ComponentProps<typeof MenuPrimitive.SubContent>) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.SubContent sideOffset={sideOffset} collisionPadding={collisionPadding} className={s.content({ className: cn(\"max-h-(--radix-dropdown-menu-content-available-height)\", className) })} {...props} />\n </MenuPrimitive.Portal>\n );\n}\n\n/** One choice among several (`DropdownMenu.RadioGroup` holds the value): a language, a sort order. */\nexport function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.RadioItem>) {\n return (\n <MenuPrimitive.RadioItem className={s.item({ className })} {...props}>\n {children}\n <MenuPrimitive.ItemIndicator className={s.indicator()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </MenuPrimitive.ItemIndicator>\n </MenuPrimitive.RadioItem>\n );\n}\n\nexport function DropdownMenuLabel({ className, ...props }: React.ComponentProps<typeof MenuPrimitive.Label>) {\n return <MenuPrimitive.Label className={s.label({ className })} {...props} />;\n}\n\nexport function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof MenuPrimitive.Separator>) {\n return <MenuPrimitive.Separator className={s.separator({ className })} {...props} />;\n}\n\n/** `DropdownMenu.Root/Trigger/Content/Item/CheckboxItem/Label/Separator/Group`. `open`/`defaultOpen` + `onOpenChange`. */\nexport const DropdownMenu = {\n Root: MenuPrimitive.Root,\n Trigger: MenuPrimitive.Trigger,\n Content: DropdownMenuContent,\n Item: DropdownMenuItem,\n CheckboxItem: DropdownMenuCheckboxItem,\n Label: DropdownMenuLabel,\n Separator: DropdownMenuSeparator,\n Group: MenuPrimitive.Group,\n Sub: MenuPrimitive.Sub,\n SubTrigger: DropdownMenuSubTrigger,\n SubContent: DropdownMenuSubContent,\n RadioGroup: MenuPrimitive.RadioGroup,\n RadioItem: DropdownMenuRadioItem,\n};\n","// The one surface of everything that floats next to its trigger (popover, menu, tooltip): a raised surface, a border,\n// the large shadow and the `kz-pop` entrance from the side Radix measured (`--radix-*-transform-origin`).\nexport const floating =\n \"kz-pop z-50 rounded-lg border border-border-default bg-surface-2 text-fg shadow-lg outline-hidden\";\n","// Client (a portal). The signed-in person's menu under their avatar — who you are first (picture, name, e-mail), then\n// the places (profile, settings), the language as a compact submenu, the extras, and Sign out (a quiet item, not a\n// red alert). Built on DropdownMenu, so the keyboard, the focus return and the collisions are Radix's.\nimport * as React from \"react\";\n\nimport { Avatar, type AvatarProps } from \"../avatar/avatar\";\nimport { cn } from \"../cn\";\nimport { DropdownMenu } from \"../dropdown-menu/dropdown-menu\";\n\nexport interface AccountMenuLink {\n id: string;\n label: string;\n href: string;\n /** A signature icon. */\n icon?: React.ReactNode;\n}\n\nexport interface AccountMenuLanguage {\n /** The row's words (`Language`). */\n label: string;\n /** The current value (`en`). */\n value: string;\n options: readonly { value: string; label: string }[];\n onChange: (value: string) => void;\n}\n\nexport interface AccountMenuProps {\n /** The trigger's accessible name (`Account`). */\n label: string;\n /** Their name; falls back to the e-mail. */\n name?: string;\n /** Their e-mail, shown under the name. */\n email?: string;\n /** The picture: `src`, or `defaultAvatar` (`{ brand, seed }`) for the product's default person. */\n avatar?: Omit<AvatarProps, \"size\">;\n /** Show the name beside the avatar in the trigger from the `sm` breakpoint. */\n showName?: boolean;\n /** Where to go: profile, settings… */\n links?: readonly AccountMenuLink[];\n /** The app's link component (Next's `Link`); an `<a>` otherwise. */\n linkAs?: React.ElementType;\n /** The language, as a submenu that shows the current one. */\n language?: AccountMenuLanguage;\n /** Extra rows between the language and Sign out (a theme switch…). */\n children?: React.ReactNode;\n /** The last row: its words, what it does, an optional icon. */\n signOut: { label: string; onSelect: () => void; icon?: React.ReactNode };\n /** Classes for the trigger. */\n className?: string;\n}\n\n/** The account menu: avatar trigger → identity header, links, language submenu, Sign out. */\nexport function AccountMenu({ label, name, email, avatar, showName = true, links = [], linkAs: Link = \"a\", language, children, signOut, className }: AccountMenuProps) {\n const title = name || email || \"\";\n const current = language?.options.find((o) => o.value === language.value)?.label;\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger\n aria-label={label}\n className={cn(\"flex items-center gap-2.5 rounded-lg p-1 transition-colors duration-150 hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\", className)}\n >\n <Avatar size=\"sm\" fallback={title.charAt(0).toUpperCase() || \"?\"} {...avatar} />\n {/* Drawn by CSS: the name is not text of the button, so its accessible name stays `label` with no label-content-name-mismatch. */}\n {showName && title && <span aria-hidden data-name={title} className=\"hidden max-w-40 truncate text-sm font-medium text-fg-secondary after:content-[attr(data-name)] sm:inline-block\" />}\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\" className=\"w-64\">\n <DropdownMenu.Label className=\"flex items-center gap-3 py-2 normal-case tracking-normal\">\n <Avatar size=\"md\" fallback={title.charAt(0).toUpperCase() || \"?\"} {...avatar} />\n <span className=\"min-w-0\">\n <span className=\"block truncate text-sm font-semibold text-fg\">{title}</span>\n {name && email && name !== email && <span className=\"block truncate text-xs font-normal text-fg-secondary\">{email}</span>}\n </span>\n </DropdownMenu.Label>\n {links.length > 0 && <DropdownMenu.Separator />}\n {links.map((link) => (\n <DropdownMenu.Item key={link.id} asChild>\n <Link href={link.href}>\n {link.icon}\n {link.label}\n </Link>\n </DropdownMenu.Item>\n ))}\n {(language || children) && <DropdownMenu.Separator />}\n {language && (\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n {language.label}\n {current && <span className=\"ml-auto mr-1 text-xs text-fg-secondary\">{current}</span>}\n </DropdownMenu.SubTrigger>\n <DropdownMenu.SubContent>\n <DropdownMenu.RadioGroup value={language.value} onValueChange={language.onChange}>\n {language.options.map((o) => (\n <DropdownMenu.RadioItem key={o.value} value={o.value}>\n {o.label}\n </DropdownMenu.RadioItem>\n ))}\n </DropdownMenu.RadioGroup>\n </DropdownMenu.SubContent>\n </DropdownMenu.Sub>\n )}\n {children}\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => signOut.onSelect()}>\n {signOut.icon}\n {signOut.label}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/dropdown-menu/dropdown-menu.tsx","../src/floating.ts","../src/account-menu/account-menu.tsx"],"sourcesContent":["// Client (a portal). Radix does the roving focus, the arrows, Home/End, typeahead, Escape and the focus return.\nimport { DropdownMenu as MenuPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\nexport const menu = tv({\n slots: {\n content: cn(floating, \"min-w-48 max-h-(--radix-dropdown-menu-content-available-height) overflow-y-auto overflow-x-hidden overscroll-contain p-1 origin-(--radix-dropdown-menu-content-transform-origin)\"),\n item:\n \"relative flex cursor-pointer select-none items-center gap-2 rounded-md px-2.5 py-2 text-sm text-fg outline-hidden transition-colors \" +\n \"data-highlighted:bg-surface-3 data-disabled:pointer-events-none data-disabled:opacity-40 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 \" +\n \"[&>svg]:text-fg-secondary\",\n indicator: \"ml-auto flex h-4 w-4 items-center justify-center text-fg-accent\",\n label: \"px-2.5 pb-1 pt-2 text-[11px] font-semibold text-fg-secondary\",\n separator: \"-mx-1 my-1 h-px bg-border-subtle\",\n },\n variants: {\n // The label reads in the danger text role (≥ 4.5:1 on the menu surface, both themes); the icon and the highlight\n // carry the danger fill.\n tone: { default: {}, danger: { item: \"text-fg-danger data-highlighted:bg-danger/15 [&>svg]:text-danger\" } },\n },\n defaultVariants: { tone: \"default\" },\n});\nconst s = menu();\n\nexport type DropdownMenuContentProps = React.ComponentProps<typeof MenuPrimitive.Content> & {\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function DropdownMenuContent({ sideOffset = 6, align = \"end\", collisionPadding = 8, container, className, ...props }: DropdownMenuContentProps) {\n return (\n <MenuPrimitive.Portal container={container}>\n <MenuPrimitive.Content sideOffset={sideOffset} align={align} collisionPadding={collisionPadding} className={s.content({ className })} {...props} />\n </MenuPrimitive.Portal>\n );\n}\n\nexport type DropdownMenuItemProps = React.ComponentProps<typeof MenuPrimitive.Item> & {\n /** `danger` for a destructive action: the icon and the highlight carry the danger, the label stays legible. */\n tone?: \"default\" | \"danger\";\n};\n\n/** An action. `tone=\"danger\"` for a destructive one; `onSelect` runs it (the menu closes). */\nexport function DropdownMenuItem({ tone, className, ...props }: DropdownMenuItemProps) {\n return <MenuPrimitive.Item data-tone={tone ?? \"default\"} className={menu({ tone }).item({ className })} {...props} />;\n}\n\n/** A toggled option: `checked` + `onCheckedChange`. */\nexport function DropdownMenuCheckboxItem({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.CheckboxItem>) {\n return (\n <MenuPrimitive.CheckboxItem className={s.item({ className })} {...props}>\n {children}\n <MenuPrimitive.ItemIndicator className={s.indicator()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </MenuPrimitive.ItemIndicator>\n </MenuPrimitive.CheckboxItem>\n );\n}\n\n/** A submenu's trigger: an item that opens `DropdownMenu.SubContent`, with a chevron. */\nexport function DropdownMenuSubTrigger({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.SubTrigger>) {\n return (\n <MenuPrimitive.SubTrigger className={s.item({ className: cn(\"data-[state=open]:bg-surface-3\", className) })} {...props}>\n {children}\n <svg className=\"ml-auto !h-4 !w-4 text-fg-secondary\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </MenuPrimitive.SubTrigger>\n );\n}\n\n/** The submenu's panel (same material as the menu). */\nexport function DropdownMenuSubContent({ sideOffset = 4, collisionPadding = 8, className, ...props }: React.ComponentProps<typeof MenuPrimitive.SubContent>) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.SubContent sideOffset={sideOffset} collisionPadding={collisionPadding} className={s.content({ className: cn(\"max-h-(--radix-dropdown-menu-content-available-height)\", className) })} {...props} />\n </MenuPrimitive.Portal>\n );\n}\n\n/** One choice among several (`DropdownMenu.RadioGroup` holds the value): a language, a sort order. */\nexport function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.RadioItem>) {\n return (\n <MenuPrimitive.RadioItem className={s.item({ className })} {...props}>\n {children}\n <MenuPrimitive.ItemIndicator className={s.indicator()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </MenuPrimitive.ItemIndicator>\n </MenuPrimitive.RadioItem>\n );\n}\n\nexport function DropdownMenuLabel({ className, ...props }: React.ComponentProps<typeof MenuPrimitive.Label>) {\n return <MenuPrimitive.Label className={s.label({ className })} {...props} />;\n}\n\nexport function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof MenuPrimitive.Separator>) {\n return <MenuPrimitive.Separator className={s.separator({ className })} {...props} />;\n}\n\n/** `DropdownMenu.Root/Trigger/Content/Item/CheckboxItem/Label/Separator/Group`. `open`/`defaultOpen` + `onOpenChange`. */\nexport const DropdownMenu = {\n Root: MenuPrimitive.Root,\n Trigger: MenuPrimitive.Trigger,\n Content: DropdownMenuContent,\n Item: DropdownMenuItem,\n CheckboxItem: DropdownMenuCheckboxItem,\n Label: DropdownMenuLabel,\n Separator: DropdownMenuSeparator,\n Group: MenuPrimitive.Group,\n Sub: MenuPrimitive.Sub,\n SubTrigger: DropdownMenuSubTrigger,\n SubContent: DropdownMenuSubContent,\n RadioGroup: MenuPrimitive.RadioGroup,\n RadioItem: DropdownMenuRadioItem,\n};\n","// The one surface of everything that floats next to its trigger (popover, menu, tooltip): a raised surface, a border,\n// the large shadow and the `kz-pop` entrance from the side Radix measured (`--radix-*-transform-origin`).\nexport const floating =\n \"kz-pop z-50 rounded-lg border border-border-default bg-surface-2 text-fg shadow-lg outline-hidden\";\n","// Client (a portal). The signed-in person's menu under their avatar — who you are first (picture, name, e-mail), then\n// the places (profile, settings), the language as a compact submenu, the extras, and Sign out (a quiet item, not a\n// red alert). Built on DropdownMenu, so the keyboard, the focus return and the collisions are Radix's.\nimport * as React from \"react\";\n\nimport { Avatar, type AvatarProps } from \"../avatar/avatar\";\nimport { cn } from \"../cn\";\nimport { DropdownMenu } from \"../dropdown-menu/dropdown-menu\";\n\nexport interface AccountMenuLink {\n id: string;\n label: string;\n href: string;\n /** A signature icon. */\n icon?: React.ReactNode;\n}\n\nexport interface AccountMenuLanguage {\n /** The row's words (`Language`). */\n label: string;\n /** The current value (`en`). */\n value: string;\n options: readonly { value: string; label: string }[];\n onChange: (value: string) => void;\n}\n\nexport interface AccountMenuProps {\n /** The trigger's accessible name (`Account`). */\n label: string;\n /** Their name; falls back to the e-mail. */\n name?: string;\n /** Their e-mail, shown under the name. */\n email?: string;\n /** The picture: `src`, or `defaultAvatar` (`{ brand, seed }`) for the product's default person. */\n avatar?: Omit<AvatarProps, \"size\">;\n /**\n * Show the name beside the avatar in the trigger: `true` or `\"sm\"` from 640 px, `\"lg\"` from 1024 px (the family's top\n * bar, where search and the counts take the room below it), `false` never.\n * @default true\n */\n showName?: boolean | \"sm\" | \"lg\";\n /** Where to go: profile, settings… */\n links?: readonly AccountMenuLink[];\n /** The app's link component (Next's `Link`); an `<a>` otherwise. */\n linkAs?: React.ElementType;\n /** The language, as a submenu that shows the current one. */\n language?: AccountMenuLanguage;\n /** Extra rows between the language and Sign out (a theme switch…). */\n children?: React.ReactNode;\n /** The last row: its words, what it does, an optional icon. */\n signOut: { label: string; onSelect: () => void; icon?: React.ReactNode };\n /** Classes for the trigger. */\n className?: string;\n}\n\n/** The account menu: avatar trigger → identity header, links, language submenu, Sign out. */\nexport function AccountMenu({ label, name, email, avatar, showName = true, links = [], linkAs: Link = \"a\", language, children, signOut, className }: AccountMenuProps) {\n const title = name || email || \"\";\n const current = language?.options.find((o) => o.value === language.value)?.label;\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger\n aria-label={label}\n className={cn(\"flex items-center gap-2.5 rounded-lg p-1 transition-colors duration-150 hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\", className)}\n >\n <Avatar size=\"sm\" fallback={title.charAt(0).toUpperCase() || \"?\"} {...avatar} />\n {/* Drawn by CSS: the name is not text of the button, so its accessible name stays `label` with no label-content-name-mismatch. */}\n {showName && title && (\n <span\n aria-hidden\n data-name={title}\n className={cn(\"hidden max-w-40 truncate text-sm font-medium text-fg-secondary after:content-[attr(data-name)]\", showName === \"lg\" ? \"lg:inline-block\" : \"sm:inline-block\")}\n />\n )}\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\" className=\"w-64\">\n <DropdownMenu.Label className=\"flex items-center gap-3 py-2 normal-case tracking-normal\">\n <Avatar size=\"md\" fallback={title.charAt(0).toUpperCase() || \"?\"} {...avatar} />\n <span className=\"min-w-0\">\n <span className=\"block truncate text-sm font-semibold text-fg\">{title}</span>\n {name && email && name !== email && <span className=\"block truncate text-xs font-normal text-fg-secondary\">{email}</span>}\n </span>\n </DropdownMenu.Label>\n {links.length > 0 && <DropdownMenu.Separator />}\n {links.map((link) => (\n <DropdownMenu.Item key={link.id} asChild>\n <Link href={link.href}>\n {link.icon}\n {link.label}\n </Link>\n </DropdownMenu.Item>\n ))}\n {(language || children) && <DropdownMenu.Separator />}\n {language && (\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n {language.label}\n {current && <span className=\"ml-auto mr-1 text-xs text-fg-secondary\">{current}</span>}\n </DropdownMenu.SubTrigger>\n <DropdownMenu.SubContent>\n <DropdownMenu.RadioGroup value={language.value} onValueChange={language.onChange}>\n {language.options.map((o) => (\n <DropdownMenu.RadioItem key={o.value} value={o.value}>\n {o.label}\n </DropdownMenu.RadioItem>\n ))}\n </DropdownMenu.RadioGroup>\n </DropdownMenu.SubContent>\n </DropdownMenu.Sub>\n )}\n {children}\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => signOut.onSelect()}>\n {signOut.icon}\n {signOut.label}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|
package/dist/account-settings.js
CHANGED
|
@@ -118,78 +118,18 @@ function AvatarPicker({ label, showLabel, description, dense, options, upload, c
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// src/account-settings/choice-cards.tsx
|
|
121
|
-
import * as
|
|
121
|
+
import * as React3 from "react";
|
|
122
122
|
|
|
123
123
|
// src/radio-group/radio-group.tsx
|
|
124
124
|
import { RadioGroup as RadioGroupPrimitive2 } from "radix-ui";
|
|
125
|
-
|
|
126
|
-
// src/router/route-state.tsx
|
|
127
|
-
import * as React2 from "react";
|
|
128
|
-
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
129
|
-
var CHANGE = "kz-route-state";
|
|
130
|
-
var browserAdapter = {
|
|
131
|
-
search: () => typeof window === "undefined" ? "" : window.location.search,
|
|
132
|
-
navigate: (search, { replace }) => {
|
|
133
|
-
const url = `${window.location.pathname}${search}${window.location.hash}`;
|
|
134
|
-
window.history[replace ? "replaceState" : "pushState"](window.history.state, "", url);
|
|
135
|
-
window.dispatchEvent(new Event(CHANGE));
|
|
136
|
-
},
|
|
137
|
-
subscribe: (onChange) => {
|
|
138
|
-
window.addEventListener("popstate", onChange);
|
|
139
|
-
window.addEventListener(CHANGE, onChange);
|
|
140
|
-
return () => {
|
|
141
|
-
window.removeEventListener("popstate", onChange);
|
|
142
|
-
window.removeEventListener(CHANGE, onChange);
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
var AdapterContext = React2.createContext(browserAdapter);
|
|
147
|
-
function readRouteValue(search, key, { values, default: fallback }) {
|
|
148
|
-
const raw = new URLSearchParams(search).get(key);
|
|
149
|
-
if (raw === null) return fallback;
|
|
150
|
-
return !values || values.includes(raw) ? raw : fallback;
|
|
151
|
-
}
|
|
152
|
-
function writeRouteValue(search, key, value, fallback) {
|
|
153
|
-
const params = new URLSearchParams(search);
|
|
154
|
-
if (value === fallback) params.delete(key);
|
|
155
|
-
else params.set(key, value);
|
|
156
|
-
const text = params.toString();
|
|
157
|
-
return text ? `?${text}` : "";
|
|
158
|
-
}
|
|
159
|
-
function useRouteState(key, { values, default: fallback, history = "push" }) {
|
|
160
|
-
const adapter = React2.useContext(AdapterContext);
|
|
161
|
-
const search = React2.useSyncExternalStore(adapter.subscribe, adapter.search, () => "");
|
|
162
|
-
const value = key === void 0 ? fallback : readRouteValue(search, key, { values, default: fallback });
|
|
163
|
-
const set = React2.useCallback(
|
|
164
|
-
(next) => {
|
|
165
|
-
if (key === void 0) return;
|
|
166
|
-
adapter.navigate(writeRouteValue(adapter.search(), key, next, fallback), { replace: history === "replace" });
|
|
167
|
-
},
|
|
168
|
-
[adapter, key, fallback, history]
|
|
169
|
-
);
|
|
170
|
-
return [value, set];
|
|
171
|
-
}
|
|
172
|
-
function useRouteBinding(routeKey, routeValues, props) {
|
|
173
|
-
const initial = props.defaultValue ?? props.value ?? routeValues?.[0] ?? "";
|
|
174
|
-
const [value, set] = useRouteState(routeKey, { values: routeValues, default: initial });
|
|
175
|
-
if (routeKey === void 0) return props;
|
|
176
|
-
return {
|
|
177
|
-
...props,
|
|
178
|
-
value,
|
|
179
|
-
defaultValue: void 0,
|
|
180
|
-
onValueChange: (next) => {
|
|
181
|
-
set(next);
|
|
182
|
-
props.onValueChange?.(next);
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
}
|
|
125
|
+
import { useRouteBinding } from "@krizaka/ui/router";
|
|
186
126
|
|
|
187
127
|
// src/sliding-indicator.ts
|
|
188
|
-
import * as
|
|
189
|
-
var useIsoLayoutEffect = typeof window === "undefined" ?
|
|
128
|
+
import * as React2 from "react";
|
|
129
|
+
var useIsoLayoutEffect = typeof window === "undefined" ? React2.useEffect : React2.useLayoutEffect;
|
|
190
130
|
function useSlidingIndicator({ item, active, prefer, follow = false }) {
|
|
191
|
-
const ref =
|
|
192
|
-
const place =
|
|
131
|
+
const ref = React2.useRef(null);
|
|
132
|
+
const place = React2.useCallback((target) => {
|
|
193
133
|
const list = ref.current;
|
|
194
134
|
if (!list) return;
|
|
195
135
|
if (!(target instanceof HTMLElement) || !list.contains(target)) {
|
|
@@ -204,7 +144,7 @@ function useSlidingIndicator({ item, active, prefer, follow = false }) {
|
|
|
204
144
|
list.style.setProperty("--kz-ind-h", `${a.height}px`);
|
|
205
145
|
list.setAttribute("data-indicator", "on");
|
|
206
146
|
}, []);
|
|
207
|
-
const rest =
|
|
147
|
+
const rest = React2.useCallback(
|
|
208
148
|
() => {
|
|
209
149
|
const list = ref.current;
|
|
210
150
|
const hovered = follow ? list?.querySelector(`${item}:hover`) : null;
|
|
@@ -212,7 +152,7 @@ function useSlidingIndicator({ item, active, prefer, follow = false }) {
|
|
|
212
152
|
},
|
|
213
153
|
[place, active, prefer, item, follow]
|
|
214
154
|
);
|
|
215
|
-
const follow_ =
|
|
155
|
+
const follow_ = React2.useCallback((target) => {
|
|
216
156
|
const hit = target instanceof Element ? target.closest(item) : null;
|
|
217
157
|
if (hit && ref.current?.contains(hit)) place(hit);
|
|
218
158
|
else rest();
|
|
@@ -244,16 +184,16 @@ import { createTV } from "tailwind-variants";
|
|
|
244
184
|
var tv2 = createTV({ twMergeConfig });
|
|
245
185
|
|
|
246
186
|
// src/radio-group/radio-group.tsx
|
|
247
|
-
import { jsx as
|
|
187
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
248
188
|
var radioGroup = tv2({
|
|
249
189
|
slots: {
|
|
250
190
|
root: "grid gap-2 data-[orientation=horizontal]:flex data-[orientation=horizontal]:flex-wrap",
|
|
251
|
-
item: "peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-
|
|
191
|
+
item: "peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-control bg-surface-1 inset-shadow-well transition-colors focus-visible:outline-hidden focus-visible:focus-ring hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:shadow-glow aria-invalid:border-danger",
|
|
252
192
|
dot: "h-2 w-2 rounded-full bg-on-accent",
|
|
253
193
|
label: "flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-70",
|
|
254
194
|
card: "group relative flex min-w-0 flex-col items-start gap-1 rounded-2xl border border-border-default bg-surface-1 bg-sheen p-4 pr-10 text-left text-sm text-fg inset-shadow-edge transition-[border-color,background-color,box-shadow,transform] duration-200 hover:border-border-strong active:scale-[0.99] motion-reduce:transition-none motion-reduce:active:scale-100 focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger data-[state=checked]:border-accent data-[state=checked]:bg-accent-soft data-[state=checked]:shadow-glow",
|
|
255
195
|
// The card's check: an empty ring at rest, the accent filled with its check once chosen.
|
|
256
|
-
cardCheck: "absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-
|
|
196
|
+
cardCheck: "absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-control bg-surface-1 text-on-accent transition-colors group-data-[state=checked]:border-accent group-data-[state=checked]:bg-accent",
|
|
257
197
|
// The tactile key: on a ledge (its lower edge), its hairline stronger on hover, pressed in while held and once chosen.
|
|
258
198
|
button: "relative inline-flex min-h-12 min-w-12 select-none flex-col items-center justify-center gap-0.5 rounded-xl border border-border-default bg-surface-2 bg-sheen px-4 py-2 text-sm font-semibold text-fg inset-shadow-edge shadow-[0_4px_0_0_var(--kz-border-strong)] transition-[transform,box-shadow,background-color,border-color,color] duration-100 ease-out motion-reduce:transition-none hover:border-border-strong active:translate-y-[3px] active:shadow-[0_1px_0_0_var(--kz-border-strong)] focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger data-[state=checked]:translate-y-[3px] data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:bg-fill-shade data-[state=checked]:text-on-accent data-[state=checked]:inset-shadow-edge-fill data-[state=checked]:shadow-[0_1px_0_0_var(--kz-accent-hover)]",
|
|
259
199
|
buttonHint: "text-[11px] font-medium text-fg-secondary group-data-[state=checked]:text-on-accent",
|
|
@@ -275,7 +215,7 @@ function RadioGroupRoot({ label, invalid, variant = "list", className, routeKey,
|
|
|
275
215
|
const props = useRouteBinding(routeKey, routeValues, rest);
|
|
276
216
|
const { ref } = useSlidingIndicator({ item: "[role=radio]", active: "[role=radio][data-state=checked]" });
|
|
277
217
|
const segmented = variant === "segmented";
|
|
278
|
-
return /* @__PURE__ */
|
|
218
|
+
return /* @__PURE__ */ jsx5(
|
|
279
219
|
RadioGroupPrimitive2.Root,
|
|
280
220
|
{
|
|
281
221
|
ref: segmented ? ref : void 0,
|
|
@@ -290,59 +230,59 @@ function RadioGroupRoot({ label, invalid, variant = "list", className, routeKey,
|
|
|
290
230
|
);
|
|
291
231
|
}
|
|
292
232
|
function RadioGroupItem({ className, children, ...props }) {
|
|
293
|
-
const item = /* @__PURE__ */
|
|
233
|
+
const item = /* @__PURE__ */ jsx5(RadioGroupPrimitive2.Item, { className: s.item({ className: children ? "mt-0.5" : className }), ...props, children: /* @__PURE__ */ jsx5(RadioGroupPrimitive2.Indicator, { className: s.dot() }) });
|
|
294
234
|
if (!children) return item;
|
|
295
235
|
return /* @__PURE__ */ jsxs5("label", { className: s.label({ className }), children: [
|
|
296
236
|
item,
|
|
297
|
-
/* @__PURE__ */
|
|
237
|
+
/* @__PURE__ */ jsx5("span", { className: "min-w-0", children })
|
|
298
238
|
] });
|
|
299
239
|
}
|
|
300
240
|
function RadioGroupCard({ className, children, ...props }) {
|
|
301
241
|
return /* @__PURE__ */ jsxs5(RadioGroupPrimitive2.Item, { className: s.card({ className }), ...props, children: [
|
|
302
242
|
children,
|
|
303
|
-
/* @__PURE__ */
|
|
243
|
+
/* @__PURE__ */ jsx5("span", { "aria-hidden": true, className: s.cardCheck(), children: /* @__PURE__ */ jsx5(RadioGroupPrimitive2.Indicator, { forceMount: true, className: "inline-flex data-[state=unchecked]:hidden", children: /* @__PURE__ */ jsx5(CheckGlyph, { className: "h-3 w-3" }) }) })
|
|
304
244
|
] });
|
|
305
245
|
}
|
|
306
246
|
function RadioGroupButton({ className, children, hint, ...props }) {
|
|
307
247
|
return /* @__PURE__ */ jsxs5(RadioGroupPrimitive2.Item, { className: s.button({ className: ["group", className].filter(Boolean).join(" ") }), ...props, children: [
|
|
308
|
-
/* @__PURE__ */
|
|
309
|
-
hint ? /* @__PURE__ */
|
|
248
|
+
/* @__PURE__ */ jsx5("span", { children }),
|
|
249
|
+
hint ? /* @__PURE__ */ jsx5("span", { className: s.buttonHint(), children: hint }) : null
|
|
310
250
|
] });
|
|
311
251
|
}
|
|
312
252
|
function RadioGroupSegment({ className, ...props }) {
|
|
313
|
-
return /* @__PURE__ */
|
|
253
|
+
return /* @__PURE__ */ jsx5(RadioGroupPrimitive2.Item, { className: s.segment({ className }), ...props });
|
|
314
254
|
}
|
|
315
255
|
var RadioGroup = { Root: RadioGroupRoot, Item: RadioGroupItem, Card: RadioGroupCard, Button: RadioGroupButton, Segment: RadioGroupSegment };
|
|
316
256
|
|
|
317
257
|
// src/account-settings/choice-cards.tsx
|
|
318
|
-
import { jsx as
|
|
258
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
319
259
|
function ChoiceCards({ label, showLabel, description, options, className, ...props }) {
|
|
320
|
-
const base =
|
|
321
|
-
const group = /* @__PURE__ */
|
|
260
|
+
const base = React3.useId();
|
|
261
|
+
const group = /* @__PURE__ */ jsx6(RadioGroup.Root, { variant: "cards", label, "aria-labelledby": showLabel ? `${base}-label` : void 0, className: ["grid grid-cols-1 gap-3 sm:grid-cols-2", !showLabel && className].filter(Boolean).join(" "), ...props, children: options.map((option) => {
|
|
322
262
|
const describedBy = option.description ? `${base}-${option.id}` : void 0;
|
|
323
263
|
return /* @__PURE__ */ jsxs6(RadioGroup.Card, { value: option.id, disabled: option.disabled, "aria-describedby": describedBy, children: [
|
|
324
264
|
/* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-2.5 font-semibold text-fg [&>svg]:h-5 [&>svg]:w-5 [&>svg]:text-accent", children: [
|
|
325
265
|
option.icon,
|
|
326
266
|
option.title
|
|
327
267
|
] }),
|
|
328
|
-
option.description ? /* @__PURE__ */
|
|
268
|
+
option.description ? /* @__PURE__ */ jsx6("span", { id: describedBy, className: "text-sm font-normal text-fg-secondary", children: option.description }) : null
|
|
329
269
|
] }, option.id);
|
|
330
270
|
}) });
|
|
331
271
|
if (!showLabel) return group;
|
|
332
272
|
return /* @__PURE__ */ jsxs6("div", { className: ["flex flex-col gap-3", className].filter(Boolean).join(" "), children: [
|
|
333
|
-
/* @__PURE__ */
|
|
273
|
+
/* @__PURE__ */ jsx6(GroupHead, { id: `${base}-label`, label, description }),
|
|
334
274
|
group
|
|
335
275
|
] });
|
|
336
276
|
}
|
|
337
277
|
|
|
338
278
|
// src/account-settings/language-picker.tsx
|
|
339
|
-
import * as
|
|
340
|
-
import { jsx as
|
|
279
|
+
import * as React4 from "react";
|
|
280
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
341
281
|
function LanguagePicker({ label, showLabel = true, description, languages, className, ...props }) {
|
|
342
|
-
const id =
|
|
282
|
+
const id = React4.useId();
|
|
343
283
|
return /* @__PURE__ */ jsxs7("div", { className: ["flex flex-col gap-2", className].filter(Boolean).join(" "), children: [
|
|
344
|
-
showLabel ? /* @__PURE__ */
|
|
345
|
-
/* @__PURE__ */
|
|
284
|
+
showLabel ? /* @__PURE__ */ jsx7(GroupHead, { id: `${id}-label`, label, description }) : null,
|
|
285
|
+
/* @__PURE__ */ jsx7(RadioGroup.Root, { variant: "segmented", "aria-label": showLabel ? void 0 : String(label), "aria-labelledby": showLabel ? `${id}-label` : void 0, ...props, children: languages.map((language) => /* @__PURE__ */ jsx7(RadioGroup.Segment, { value: language.code, lang: language.code, children: language.name }, language.code)) })
|
|
346
286
|
] });
|
|
347
287
|
}
|
|
348
288
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/badge/badge.tsx","../src/badge/recipe.ts","../src/account-settings/account-profile-card.tsx","../src/account-settings/avatar-picker.tsx","../src/account-settings/group-head.tsx","../src/account-settings/choice-cards.tsx","../src/radio-group/radio-group.tsx","../src/router/route-state.tsx","../src/sliding-indicator.ts","../src/tv.ts","../src/account-settings/language-picker.tsx"],"sourcesContent":["// Server-safe: no hook, no context.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { badgeRecipe } from \"./recipe\";\n\n// Status tones are soft (a tint, a coloured dot, a text role): the invariant status tokens are too light to carry\n// small text on a light surface, or to sit under white text (WCAG AA).\nexport const badgeVariants = tv(badgeRecipe);\n\nexport type BadgeVariants = VariantProps<typeof badgeVariants>;\n\nexport type BadgeProps = React.ComponentProps<\"span\"> &\n BadgeVariants & {\n /**\n * neutral · accent · success · warning · danger (soft tints, the text stays a text role) · scrim (on a media).\n * @default \"neutral\"\n */\n tone?: BadgeVariants[\"tone\"];\n /**\n * sm · md.\n * @default \"sm\"\n */\n size?: BadgeVariants[\"size\"];\n /** Makes the `dot` pulse (stopped under reduced motion). */\n pulse?: BadgeVariants[\"pulse\"];\n /** A small dot before the text, in the tone's colour (pulsing with `pulse`). */\n dot?: boolean;\n };\n\nexport function Badge({ tone, size, pulse, dot, className, children, ...props }: BadgeProps) {\n return (\n <span data-tone={tone ?? \"neutral\"} className={badgeVariants({ tone, size, pulse, className })} {...props}>\n {dot && <span data-dot=\"\" aria-hidden className=\"h-1.5 w-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n","// The badge's tones and sizes, written once as classes of the Krizaka tokens: the web wears them with `tv(badgeRecipe)`,\n// React Native reads the same classes into styles (native/badge.tsx). Status tones are soft (a tint, a coloured dot, a\n// text role): the invariant status tokens are too light to carry small text on a light surface, or to sit under white\n// text (WCAG AA).\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const badgeRecipe = defineRecipe({\n base: \"inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-sm font-semibold \",\n variants: {\n tone: {\n neutral: \"bg-surface-3 text-fg-secondary\",\n accent: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40 [&>[data-dot]]:bg-accent\",\n success: \"bg-success/15 text-fg ring-1 ring-inset ring-success/40 [&>[data-dot]]:bg-success\",\n warning: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40 [&>[data-dot]]:bg-warning\",\n danger: \"bg-danger/15 text-fg ring-1 ring-inset ring-danger/40 [&>[data-dot]]:bg-danger\",\n /** On a media: veil and text invariant, identical in both themes. */\n scrim: \"bg-scrim text-fg-on-media backdrop-blur-md\",\n },\n size: { sm: \"px-2 py-0.5 text-[10px]\", md: \"px-2.5 py-1 text-[11px]\" },\n pulse: { true: \"[&>[data-dot]]:motion-safe:animate-pulse\" },\n },\n defaultVariants: { tone: \"neutral\", size: \"sm\" },\n});\n","// Server-safe. Who the account is, at a glance: the picture with its change action, the name, the e-mail and whether it is\n// verified, since when. The head of a profile section.\nimport type * as React from \"react\";\n\nimport { Avatar, type AvatarProps } from \"../avatar/avatar\";\nimport { Badge } from \"../badge/badge\";\nimport { cn } from \"../cn\";\n\nexport type AccountProfileCardProps = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n /** The name (the card's heading). */\n name: string;\n /** The e-mail address. */\n email: string;\n /** Whether the address is verified. */\n verified: boolean;\n /** “Verified” — passed translated. */\n verifiedLabel: string;\n /** “Not verified” — passed translated. */\n unverifiedLabel: string;\n /** “Member since October 2026” — formatted by the app, in the viewer's language. */\n memberSince?: string;\n /** The picture: the person's photo, or the default avatar of the brand. */\n avatar?: Pick<AvatarProps, \"src\" | \"defaultAvatar\" | \"fallback\">;\n /** Beside the picture: the change action (a `Button`). */\n action?: React.ReactNode;\n /**\n * One calm line for a settings row: a medium picture beside the name and the e-mail, no wrapping.\n * @default false\n */\n compact?: boolean;\n};\n\n/** The account's identity card: picture, name, verified e-mail, member since. */\nexport function AccountProfileCard({ name, email, verified, verifiedLabel, unverifiedLabel, memberSince, avatar, action, compact, className, ...props }: AccountProfileCardProps) {\n return (\n <section aria-label={name} className={cn(\"flex items-center gap-3\", !compact && \"flex-col items-start gap-4 sm:flex-row sm:gap-5\", className)} {...props}>\n <div className=\"flex shrink-0 flex-col items-center gap-2\">\n <Avatar size={compact ? \"md\" : \"xl\"} alt=\"\" fallback={name.slice(0, 1)} {...avatar} />\n {action}\n </div>\n <div className=\"flex min-w-0 flex-col gap-1\">\n <h2 className={cn(\"m-0 truncate font-bold text-fg\", compact ? \"text-sm font-medium\" : \"text-lg\")}>{name}</h2>\n <p className=\"m-0 flex flex-wrap items-center gap-2 text-sm text-fg-secondary\">\n <span className=\"min-w-0 truncate\">{email}</span>\n <Badge tone={verified ? \"success\" : \"warning\"} dot>\n {verified ? verifiedLabel : unverifiedLabel}\n </Badge>\n </p>\n {memberSince ? <p className=\"text-sm text-fg-secondary\">{memberSince}</p> : null}\n </div>\n </section>\n );\n}\n","// Client (a radio group). The pictures of a person to choose from — the family's default avatars, a few photos — as a grid of\n// round tiles: one named radiogroup, one tab stop, the arrows choose, a ring and a check on the chosen one.\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { type DefaultAvatar, defaultAvatarUrl } from \"../avatar/default-avatar\";\nimport { cn } from \"../cn\";\nimport { CheckGlyph } from \"../glyphs\";\nimport { GroupHead } from \"./group-head\";\n\nexport interface AvatarOption {\n /** The value of the choice. */\n id: string;\n /** Its name for assistive technology (“Teinte 3”) — passed translated. */\n label: string;\n /** A picture's address; otherwise `defaultAvatar` draws one of the family's pictures. */\n src?: string;\n /** One of Krizaka's default pictures (`{ brand, tone }`). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport type AvatarPickerProps = Omit<React.ComponentProps<typeof RadioGroupPrimitive.Root>, \"children\" | \"onChange\" | \"dir\"> & {\n /** The group's accessible name (“Profile picture”) — passed translated. */\n label: string;\n /**\n * Smaller tiles, for a settings row.\n * @default false\n */\n dense?: boolean;\n /** Shows the label above the grid, with `description` under it. */\n showLabel?: boolean;\n /** One line under the visible label: what it changes. */\n description?: React.ReactNode;\n /** The pictures. */\n options: readonly AvatarOption[];\n /** The chosen id (controlled). */\n value?: string;\n /** The viewer chooses another picture. */\n onValueChange?: (id: string) => void;\n /** After the pictures, in the grid: the upload action (a `Button`, a file input's label). Not a radio. */\n upload?: React.ReactNode;\n};\n\nconst pictureOf = (option: AvatarOption) => option.src ?? (option.defaultAvatar ? defaultAvatarUrl(option.defaultAvatar, { size: 256 }) : undefined);\n\n/** A grid of pictures to choose from, with an upload beside them: a radio group, never a row of loose radios. */\nexport function AvatarPicker({ label, showLabel, description, dense, options, upload, className, ...props }: AvatarPickerProps) {\n const id = React.useId();\n const group = (\n <RadioGroupPrimitive.Root aria-label={label} aria-labelledby={showLabel ? id : undefined} className={cn(dense ? \"flex flex-wrap gap-2.5\" : \"grid grid-cols-[repeat(auto-fill,minmax(4.25rem,1fr))] gap-3\", !showLabel && className)} {...props}>\n {options.map((option) => (\n <RadioGroupPrimitive.Item\n key={option.id}\n value={option.id}\n aria-label={option.label}\n className={cn(\n \"group/avatar relative shrink-0 rounded-full\", dense ? \"h-12 w-12\" : \"aspect-square w-full\",\n \" outline-none transition-shadow duration-200 motion-reduce:transition-none\",\n \"ring-1 ring-border-default hover:ring-border-strong focus-visible:focus-ring data-[state=checked]:ring-2 data-[state=checked]:ring-accent\",\n )}\n >\n <img src={pictureOf(option)} alt=\"\" draggable={false} className=\"h-full w-full rounded-full bg-surface-3 object-cover\" />\n <span\n aria-hidden\n className=\"absolute -bottom-0.5 -right-0.5 hidden h-5 w-5 items-center justify-center rounded-full border-2 border-surface-1 bg-accent text-on-accent group-data-[state=checked]/avatar:inline-flex\"\n >\n <CheckGlyph className=\"h-3 w-3\" />\n </span>\n </RadioGroupPrimitive.Item>\n ))}\n {upload ? <div className=\"flex aspect-square w-full items-center justify-center\">{upload}</div> : null}\n </RadioGroupPrimitive.Root>\n );\n if (!showLabel) return group;\n return (\n <div className={cn(\"flex flex-col gap-3\", className)}>\n <GroupHead id={id} label={label} description={description} />\n {group}\n </div>\n );\n}\n","import type * as React from \"react\";\n\n/** The visible label (and one line of help) of a radio group: the group's `aria-labelledby` points at it. */\nexport function GroupHead({ id, label, description }: { id: string; label: React.ReactNode; description?: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-0.5\">\n <span id={id} className=\"text-sm font-medium text-fg\">\n {label}\n </span>\n {description ? <span className=\"text-sm text-fg-secondary\">{description}</span> : null}\n </div>\n );\n}\n","// Client (a radio group). A single choice as selectable cards — an icon, a title, one line: the side of a lease, a plan, a\n// way to get the answer. Built on `RadioGroup.Card`, so the arrows choose, the card is the radio, the check lights up.\nimport * as React from \"react\";\n\nimport { RadioGroup } from \"../radio-group\";\nimport { GroupHead } from \"./group-head\";\n\nexport interface ChoiceCardOption {\n /** The value of the choice. */\n id: string;\n /** Its name, short. */\n title: React.ReactNode;\n /** One line under the title: what it means. It describes the radio. */\n description?: React.ReactNode;\n /** A glyph before the title (decorative). */\n icon?: React.ReactNode;\n disabled?: boolean;\n}\n\nexport type ChoiceCardsProps = Omit<React.ComponentProps<typeof RadioGroup.Root>, \"children\" | \"variant\" | \"label\"> & {\n /** The question (“Which side of the lease are you?”) — the group's accessible name, passed translated. */\n label: string;\n /** Shows the question above the cards, with `description` under it. */\n showLabel?: boolean;\n /** One line under the visible question. */\n description?: React.ReactNode;\n /** The choices. */\n options: readonly ChoiceCardOption[];\n /** The chosen id (controlled). */\n value?: string;\n /** The viewer chooses another card. */\n onValueChange?: (id: string) => void;\n};\n\n/** Cards to choose one from: a radio group where each card has an icon, a title and a description. */\nexport function ChoiceCards({ label, showLabel, description, options, className, ...props }: ChoiceCardsProps) {\n const base = React.useId();\n const group = (\n <RadioGroup.Root variant=\"cards\" label={label} aria-labelledby={showLabel ? `${base}-label` : undefined} className={[\"grid grid-cols-1 gap-3 sm:grid-cols-2\", !showLabel && className].filter(Boolean).join(\" \")} {...props}>\n {options.map((option) => {\n const describedBy = option.description ? `${base}-${option.id}` : undefined;\n return (\n <RadioGroup.Card key={option.id} value={option.id} disabled={option.disabled} aria-describedby={describedBy}>\n <span className=\"flex items-center gap-2.5 font-semibold text-fg [&>svg]:h-5 [&>svg]:w-5 [&>svg]:text-accent\">\n {option.icon}\n {option.title}\n </span>\n {option.description ? (\n <span id={describedBy} className=\"text-sm font-normal text-fg-secondary\">\n {option.description}\n </span>\n ) : null}\n </RadioGroup.Card>\n );\n })}\n </RadioGroup.Root>\n );\n if (!showLabel) return group;\n return (\n <div className={[\"flex flex-col gap-3\", className].filter(Boolean).join(\" \")}>\n <GroupHead id={`${base}-label`} label={label} description={description} />\n {group}\n </div>\n );\n}\n","// Client (a context). Radix RadioGroup: role=\"radiogroup\" / \"radio\", one tab stop, the arrows move and select, a\n// hidden input inside a form. Four looks, one behaviour:\n// - `RadioGroup.Item`: a dot and its words (a settings list);\n// - `RadioGroup.Card`: a whole card is the radio — an amount, a pack, a plan — its check lit when chosen;\n// - `RadioGroup.Button`: a tactile key that presses in — raised on a ledge, sunk when chosen (a size, a tip, a level);\n// - `RadioGroup.Segment` in `<RadioGroup.Root variant=\"segmented\">`: a segmented control, one light gliding to the choice.\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { CheckGlyph } from \"../glyphs\";\nimport { useRouteBinding } from \"../router\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { tv } from \"../tv\";\n\nexport const radioGroup = tv({\n slots: {\n root: \"grid gap-2 data-[orientation=horizontal]:flex data-[orientation=horizontal]:flex-wrap\",\n item:\n \"peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-strong bg-surface-1 inset-shadow-well transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:shadow-glow aria-invalid:border-danger\",\n dot: \"h-2 w-2 rounded-full bg-on-accent\",\n label: \"flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-70\",\n card:\n \"group relative flex min-w-0 flex-col items-start gap-1 rounded-2xl border border-border-default bg-surface-1 bg-sheen p-4 pr-10 text-left text-sm text-fg inset-shadow-edge \" +\n \"transition-[border-color,background-color,box-shadow,transform] duration-200 hover:border-border-strong active:scale-[0.99] motion-reduce:transition-none motion-reduce:active:scale-100 \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent-soft data-[state=checked]:shadow-glow\",\n // The card's check: an empty ring at rest, the accent filled with its check once chosen.\n cardCheck:\n \"absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-strong bg-surface-1 text-on-accent transition-colors \" +\n \"group-data-[state=checked]:border-accent group-data-[state=checked]:bg-accent\",\n // The tactile key: on a ledge (its lower edge), its hairline stronger on hover, pressed in while held and once chosen.\n button:\n \"relative inline-flex min-h-12 min-w-12 select-none flex-col items-center justify-center gap-0.5 rounded-xl border border-border-default bg-surface-2 bg-sheen px-4 py-2 \" +\n \"text-sm font-semibold text-fg inset-shadow-edge shadow-[0_4px_0_0_var(--kz-border-strong)] \" +\n \"transition-[transform,box-shadow,background-color,border-color,color] duration-100 ease-out motion-reduce:transition-none \" +\n \"hover:border-border-strong \" +\n \"active:translate-y-[3px] active:shadow-[0_1px_0_0_var(--kz-border-strong)] \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:translate-y-[3px] data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:bg-fill-shade \" +\n \"data-[state=checked]:text-on-accent data-[state=checked]:inset-shadow-edge-fill data-[state=checked]:shadow-[0_1px_0_0_var(--kz-accent-hover)]\",\n buttonHint: \"text-[11px] font-medium text-fg-secondary group-data-[state=checked]:text-on-accent\",\n segmented:\n \"relative isolate inline-grid auto-cols-fr grid-flow-col gap-1 rounded-xl border border-border-default bg-surface-2 p-1 inset-shadow-well \" +\n \"before:pointer-events-none before:absolute before:left-0 before:top-0 before:-z-10 before:h-(--kz-ind-h) before:w-(--kz-ind-w) \" +\n \"before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) before:rounded-lg before:border before:border-border-default before:bg-surface-0 before:bg-sheen \" +\n \"before:opacity-0 before:shadow-raised before:transition-[translate,width,height,opacity] before:duration-300 motion-reduce:before:transition-none data-[indicator=on]:before:opacity-100\",\n segment:\n \"inline-flex min-h-9 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-lg px-3.5 text-sm font-semibold text-fg-secondary transition-colors \" +\n \"hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border data-[state=checked]:border-border-default data-[state=checked]:bg-surface-0 data-[state=checked]:text-fg data-[state=checked]:shadow-raised \" +\n \"group-data-[indicator=on]/seg:data-[state=checked]:border-transparent group-data-[indicator=on]/seg:data-[state=checked]:bg-transparent group-data-[indicator=on]/seg:data-[state=checked]:shadow-none\",\n },\n variants: {\n variant: {\n list: {},\n cards: { root: \"grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-3\" },\n buttons: { root: \"flex flex-wrap gap-2.5 pb-1\" },\n segmented: {},\n },\n },\n defaultVariants: { variant: \"list\" },\n});\nconst s = radioGroup();\n\nexport type RadioGroupRootProps = React.ComponentProps<typeof RadioGroupPrimitive.Root> & {\n /** The group's accessible name — passed translated (or `aria-labelledby` a visible heading). */\n label?: string;\n /** Marks every radio invalid: aria-invalid (pair it with a `Field.Error`). */\n invalid?: boolean;\n /**\n * The layout of the radios: `list` (dots), `cards` (a grid of `Card`s), `buttons` (a row of tactile `Button`s), or\n * `segmented` (a track of `Segment`s, one light gliding to the choice).\n * @default \"list\"\n */\n variant?: \"list\" | \"cards\" | \"buttons\" | \"segmented\";\n /** Binds the choice to this search parameter of the URL (`?kind=…`): the URL is the state — for a view's selection (a segmented switch), not a form field. */\n routeKey?: string;\n /** The values the parameter may hold (the radios' `value`s); the first is the default unless `defaultValue` says otherwise. */\n routeValues?: readonly string[];\n};\n\n/** `value`/`defaultValue` + `onValueChange`, `orientation`, `required`, `name` for a form, `variant` for the layout. */\nexport function RadioGroupRoot({ label, invalid, variant = \"list\", className, routeKey, routeValues, ...rest }: RadioGroupRootProps) {\n const props = useRouteBinding(routeKey, routeValues, rest);\n const { ref } = useSlidingIndicator<HTMLDivElement>({ item: \"[role=radio]\", active: \"[role=radio][data-state=checked]\" });\n const segmented = variant === \"segmented\";\n return (\n <RadioGroupPrimitive.Root\n ref={segmented ? ref : undefined}\n aria-label={label}\n aria-invalid={invalid || undefined}\n data-invalid={invalid ? \"\" : undefined}\n data-variant={variant}\n orientation={segmented ? \"horizontal\" : props.orientation}\n className={segmented ? s.segmented({ className: [\"group/seg\", className].filter(Boolean).join(\" \") }) : radioGroup({ variant }).root({ className })}\n {...props}\n />\n );\n}\n\nexport type RadioGroupItemProps = Omit<React.ComponentProps<typeof RadioGroupPrimitive.Item>, \"children\"> & {\n /** The words next to the dot, clickable. Otherwise name it with `Field.Label htmlFor` or `aria-label`. */\n children?: React.ReactNode;\n};\n\n/** A radio: a dot, and its words when given. */\nexport function RadioGroupItem({ className, children, ...props }: RadioGroupItemProps) {\n const item = (\n <RadioGroupPrimitive.Item className={s.item({ className: children ? \"mt-0.5\" : className })} {...props}>\n <RadioGroupPrimitive.Indicator className={s.dot()} />\n </RadioGroupPrimitive.Item>\n );\n if (!children) return item;\n return (\n <label className={s.label({ className })}>\n {item}\n <span className=\"min-w-0\">{children}</span>\n </label>\n );\n}\n\n/** A whole card as the radio: its content is the radio's name; its check lights up when chosen. */\nexport function RadioGroupCard({ className, children, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return (\n <RadioGroupPrimitive.Item className={s.card({ className })} {...props}>\n {children}\n <span aria-hidden className={s.cardCheck()}>\n <RadioGroupPrimitive.Indicator forceMount className=\"inline-flex data-[state=unchecked]:hidden\">\n <CheckGlyph className=\"h-3 w-3\" />\n </RadioGroupPrimitive.Indicator>\n </span>\n </RadioGroupPrimitive.Item>\n );\n}\n\nexport type RadioGroupButtonProps = React.ComponentProps<typeof RadioGroupPrimitive.Item> & {\n /** A second line under the words (\"+15 %\"), part of the radio's name. */\n hint?: React.ReactNode;\n};\n\n/** A tactile key: raised on its ledge, pressed in while held and once chosen — sizes, a tip, a level. */\nexport function RadioGroupButton({ className, children, hint, ...props }: RadioGroupButtonProps) {\n return (\n <RadioGroupPrimitive.Item className={s.button({ className: [\"group\", className].filter(Boolean).join(\" \") })} {...props}>\n <span>{children}</span>\n {hint ? <span className={s.buttonHint()}>{hint}</span> : null}\n </RadioGroupPrimitive.Item>\n );\n}\n\n/** A segment of a `variant=\"segmented\"` group: equal widths, one light gliding to the choice. */\nexport function RadioGroupSegment({ className, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return <RadioGroupPrimitive.Item className={s.segment({ className })} {...props} />;\n}\n\n/** `RadioGroup.Root/Item/Card/Button/Segment`. */\nexport const RadioGroup = { Root: RadioGroupRoot, Item: RadioGroupItem, Card: RadioGroupCard, Button: RadioGroupButton, Segment: RadioGroupSegment };\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","// The shared sliding indicator (NavBar, Tabs): one element that glides from item to item instead of each item lighting\n// up on its own. It writes the target's box as CSS variables on the list (`--kz-ind-x/y/w/h`) and `data-indicator=\"on\"`\n// — no re-render, no animation frame: the glide is a CSS transition (none under reduced motion). Before hydration the\n// items keep their own active style, so nothing flashes.\nimport * as React from \"react\";\n\nconst useIsoLayoutEffect = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\n/**\n * `item`: the selector of an item; `active`: of the current one, where the light rests; `prefer`: an item that, when\n * present, holds the light before the current one (the NavBar's open menu); `follow`: the light follows the pointer\n * and the focus — over anything that is not an item (an open menu's panel) it goes back to rest.\n */\nexport function useSlidingIndicator<T extends HTMLElement>({ item, active, prefer, follow = false }: { item: string; active: string; prefer?: string; follow?: boolean }) {\n const ref = React.useRef<T>(null);\n const place = React.useCallback((target: Element | null) => {\n const list = ref.current;\n if (!list) return;\n if (!(target instanceof HTMLElement) || !list.contains(target)) {\n list.removeAttribute(\"data-indicator\");\n return;\n }\n const a = target.getBoundingClientRect();\n const b = list.getBoundingClientRect();\n list.style.setProperty(\"--kz-ind-x\", `${a.left - b.left + list.scrollLeft}px`);\n list.style.setProperty(\"--kz-ind-y\", `${a.top - b.top + list.scrollTop}px`);\n list.style.setProperty(\"--kz-ind-w\", `${a.width}px`);\n list.style.setProperty(\"--kz-ind-h\", `${a.height}px`);\n list.setAttribute(\"data-indicator\", \"on\");\n }, []);\n const rest = React.useCallback(\n () => {\n const list = ref.current;\n // An item re-rendered under a resting pointer (a menu closing) keeps the light the pointer gave it.\n const hovered = follow ? list?.querySelector(`${item}:hover`) : null;\n place((prefer ? list?.querySelector(prefer) : null) ?? hovered ?? list?.querySelector(active) ?? null);\n },\n [place, active, prefer, item, follow],\n );\n const follow_ = React.useCallback((target: EventTarget) => {\n const hit = target instanceof Element ? target.closest(item) : null;\n if (hit && ref.current?.contains(hit)) place(hit);\n else rest();\n }, [item, place, rest]);\n\n useIsoLayoutEffect(() => {\n const list = ref.current;\n if (!list) return;\n rest();\n const resize = new ResizeObserver(rest);\n resize.observe(list);\n const changes = new MutationObserver(rest);\n changes.observe(list, { subtree: true, attributes: true, attributeFilter: [\"data-state\", \"aria-current\", \"data-active\"] });\n return () => {\n resize.disconnect();\n changes.disconnect();\n };\n }, [rest]);\n\n const handlers = follow\n ? {\n onPointerOver: (e: React.PointerEvent) => follow_(e.target),\n onPointerLeave: rest,\n onFocus: (e: React.FocusEvent) => follow_(e.target),\n onBlur: rest,\n }\n : {};\n return { ref, handlers };\n}\n","import { createTV } from \"tailwind-variants\";\n\nimport { twMergeConfig } from \"./cn\";\n\n/** `tv` with the preset's utilities known to the merge engine (`twMergeConfig`): what a primitive wearing the material is styled with. */\nexport const tv = createTV({ twMergeConfig });\n","// Client (a radio group). The language of the account, labelled, each language named in its own language, saved per user\n// (the caller saves on change or with its section). Segmented: one light gliding to the choice.\nimport * as React from \"react\";\n\nimport { RadioGroup } from \"../radio-group\";\nimport { GroupHead } from \"./group-head\";\n\nexport interface LanguageOption {\n /** The BCP 47 code (`fr`, `en`): the value, and the `lang` of the name. */\n code: string;\n /** Its native name (`Français`, `English`) — never the current language's name for it. */\n name: string;\n}\n\nexport type LanguagePickerProps = Omit<React.ComponentProps<typeof RadioGroup.Root>, \"children\" | \"variant\" | \"label\" | \"aria-labelledby\"> & {\n /** The visible label (“Language”) — passed translated. */\n label: React.ReactNode;\n /**\n * Shows the label above the control; `false` when a `SettingsRow` already says it (the group keeps its accessible name).\n * @default true\n */\n showLabel?: boolean;\n /** One line under it: what it changes. */\n description?: React.ReactNode;\n /** The languages offered. */\n languages: readonly LanguageOption[];\n /** The chosen code (controlled). */\n value?: string;\n /** The viewer chooses another language. */\n onValueChange?: (code: string) => void;\n};\n\n/** The language control of an account page: a labelled segmented choice, native names. */\nexport function LanguagePicker({ label, showLabel = true, description, languages, className, ...props }: LanguagePickerProps) {\n const id = React.useId();\n return (\n <div className={[\"flex flex-col gap-2\", className].filter(Boolean).join(\" \")}>\n {showLabel ? <GroupHead id={`${id}-label`} label={label} description={description} /> : null}\n <RadioGroup.Root variant=\"segmented\" aria-label={showLabel ? undefined : String(label)} aria-labelledby={showLabel ? `${id}-label` : undefined} {...props}>\n {languages.map((language) => (\n <RadioGroup.Segment key={language.code} value={language.code} lang={language.code}>\n {language.name}\n </RadioGroup.Segment>\n ))}\n </RadioGroup.Root>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","jsx","jsxs","React","RadioGroupPrimitive","React","jsx","React","tv","jsx","jsxs","tv","RadioGroupPrimitive","jsx","jsxs","React","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/badge/badge.tsx","../src/badge/recipe.ts","../src/account-settings/account-profile-card.tsx","../src/account-settings/avatar-picker.tsx","../src/account-settings/group-head.tsx","../src/account-settings/choice-cards.tsx","../src/radio-group/radio-group.tsx","../src/sliding-indicator.ts","../src/tv.ts","../src/account-settings/language-picker.tsx"],"sourcesContent":["// Server-safe: no hook, no context.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { badgeRecipe } from \"./recipe\";\n\n// Status tones are soft (a tint, a coloured dot, a text role): the invariant status tokens are too light to carry\n// small text on a light surface, or to sit under white text (WCAG AA).\nexport const badgeVariants = tv(badgeRecipe);\n\nexport type BadgeVariants = VariantProps<typeof badgeVariants>;\n\nexport type BadgeProps = React.ComponentProps<\"span\"> &\n BadgeVariants & {\n /**\n * neutral · accent · success · warning · danger (soft tints, the text stays a text role) · scrim (on a media).\n * @default \"neutral\"\n */\n tone?: BadgeVariants[\"tone\"];\n /**\n * sm · md.\n * @default \"sm\"\n */\n size?: BadgeVariants[\"size\"];\n /** Makes the `dot` pulse (stopped under reduced motion). */\n pulse?: BadgeVariants[\"pulse\"];\n /** A small dot before the text, in the tone's colour (pulsing with `pulse`). */\n dot?: boolean;\n };\n\nexport function Badge({ tone, size, pulse, dot, className, children, ...props }: BadgeProps) {\n return (\n <span data-tone={tone ?? \"neutral\"} className={badgeVariants({ tone, size, pulse, className })} {...props}>\n {dot && <span data-dot=\"\" aria-hidden className=\"h-1.5 w-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n","// The badge's tones and sizes, written once as classes of the Krizaka tokens: the web wears them with `tv(badgeRecipe)`,\n// React Native reads the same classes into styles (native/badge.tsx). Status tones are soft (a tint, a coloured dot, a\n// text role): the invariant status tokens are too light to carry small text on a light surface, or to sit under white\n// text (WCAG AA).\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const badgeRecipe = defineRecipe({\n base: \"inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-sm font-semibold \",\n variants: {\n tone: {\n neutral: \"bg-surface-3 text-fg-secondary\",\n accent: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40 [&>[data-dot]]:bg-accent\",\n success: \"bg-success/15 text-fg ring-1 ring-inset ring-success/40 [&>[data-dot]]:bg-success\",\n warning: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40 [&>[data-dot]]:bg-warning\",\n danger: \"bg-danger/15 text-fg ring-1 ring-inset ring-danger/40 [&>[data-dot]]:bg-danger\",\n /** On a media: veil and text invariant, identical in both themes. */\n scrim: \"bg-scrim text-fg-on-media backdrop-blur-md\",\n },\n size: { sm: \"px-2 py-0.5 text-[10px]\", md: \"px-2.5 py-1 text-[11px]\" },\n pulse: { true: \"[&>[data-dot]]:motion-safe:animate-pulse\" },\n },\n defaultVariants: { tone: \"neutral\", size: \"sm\" },\n});\n","// Server-safe. Who the account is, at a glance: the picture with its change action, the name, the e-mail and whether it is\n// verified, since when. The head of a profile section.\nimport type * as React from \"react\";\n\nimport { Avatar, type AvatarProps } from \"../avatar/avatar\";\nimport { Badge } from \"../badge/badge\";\nimport { cn } from \"../cn\";\n\nexport type AccountProfileCardProps = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n /** The name (the card's heading). */\n name: string;\n /** The e-mail address. */\n email: string;\n /** Whether the address is verified. */\n verified: boolean;\n /** “Verified” — passed translated. */\n verifiedLabel: string;\n /** “Not verified” — passed translated. */\n unverifiedLabel: string;\n /** “Member since October 2026” — formatted by the app, in the viewer's language. */\n memberSince?: string;\n /** The picture: the person's photo, or the default avatar of the brand. */\n avatar?: Pick<AvatarProps, \"src\" | \"defaultAvatar\" | \"fallback\">;\n /** Beside the picture: the change action (a `Button`). */\n action?: React.ReactNode;\n /**\n * One calm line for a settings row: a medium picture beside the name and the e-mail, no wrapping.\n * @default false\n */\n compact?: boolean;\n};\n\n/** The account's identity card: picture, name, verified e-mail, member since. */\nexport function AccountProfileCard({ name, email, verified, verifiedLabel, unverifiedLabel, memberSince, avatar, action, compact, className, ...props }: AccountProfileCardProps) {\n return (\n <section aria-label={name} className={cn(\"flex items-center gap-3\", !compact && \"flex-col items-start gap-4 sm:flex-row sm:gap-5\", className)} {...props}>\n <div className=\"flex shrink-0 flex-col items-center gap-2\">\n <Avatar size={compact ? \"md\" : \"xl\"} alt=\"\" fallback={name.slice(0, 1)} {...avatar} />\n {action}\n </div>\n <div className=\"flex min-w-0 flex-col gap-1\">\n <h2 className={cn(\"m-0 truncate font-bold text-fg\", compact ? \"text-sm font-medium\" : \"text-lg\")}>{name}</h2>\n <p className=\"m-0 flex flex-wrap items-center gap-2 text-sm text-fg-secondary\">\n <span className=\"min-w-0 truncate\">{email}</span>\n <Badge tone={verified ? \"success\" : \"warning\"} dot>\n {verified ? verifiedLabel : unverifiedLabel}\n </Badge>\n </p>\n {memberSince ? <p className=\"text-sm text-fg-secondary\">{memberSince}</p> : null}\n </div>\n </section>\n );\n}\n","// Client (a radio group). The pictures of a person to choose from — the family's default avatars, a few photos — as a grid of\n// round tiles: one named radiogroup, one tab stop, the arrows choose, a ring and a check on the chosen one.\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { type DefaultAvatar, defaultAvatarUrl } from \"../avatar/default-avatar\";\nimport { cn } from \"../cn\";\nimport { CheckGlyph } from \"../glyphs\";\nimport { GroupHead } from \"./group-head\";\n\nexport interface AvatarOption {\n /** The value of the choice. */\n id: string;\n /** Its name for assistive technology (“Teinte 3”) — passed translated. */\n label: string;\n /** A picture's address; otherwise `defaultAvatar` draws one of the family's pictures. */\n src?: string;\n /** One of Krizaka's default pictures (`{ brand, tone }`). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport type AvatarPickerProps = Omit<React.ComponentProps<typeof RadioGroupPrimitive.Root>, \"children\" | \"onChange\" | \"dir\"> & {\n /** The group's accessible name (“Profile picture”) — passed translated. */\n label: string;\n /**\n * Smaller tiles, for a settings row.\n * @default false\n */\n dense?: boolean;\n /** Shows the label above the grid, with `description` under it. */\n showLabel?: boolean;\n /** One line under the visible label: what it changes. */\n description?: React.ReactNode;\n /** The pictures. */\n options: readonly AvatarOption[];\n /** The chosen id (controlled). */\n value?: string;\n /** The viewer chooses another picture. */\n onValueChange?: (id: string) => void;\n /** After the pictures, in the grid: the upload action (a `Button`, a file input's label). Not a radio. */\n upload?: React.ReactNode;\n};\n\nconst pictureOf = (option: AvatarOption) => option.src ?? (option.defaultAvatar ? defaultAvatarUrl(option.defaultAvatar, { size: 256 }) : undefined);\n\n/** A grid of pictures to choose from, with an upload beside them: a radio group, never a row of loose radios. */\nexport function AvatarPicker({ label, showLabel, description, dense, options, upload, className, ...props }: AvatarPickerProps) {\n const id = React.useId();\n const group = (\n <RadioGroupPrimitive.Root aria-label={label} aria-labelledby={showLabel ? id : undefined} className={cn(dense ? \"flex flex-wrap gap-2.5\" : \"grid grid-cols-[repeat(auto-fill,minmax(4.25rem,1fr))] gap-3\", !showLabel && className)} {...props}>\n {options.map((option) => (\n <RadioGroupPrimitive.Item\n key={option.id}\n value={option.id}\n aria-label={option.label}\n className={cn(\n \"group/avatar relative shrink-0 rounded-full\", dense ? \"h-12 w-12\" : \"aspect-square w-full\",\n \" outline-none transition-shadow duration-200 motion-reduce:transition-none\",\n \"ring-1 ring-border-default hover:ring-border-strong focus-visible:focus-ring data-[state=checked]:ring-2 data-[state=checked]:ring-accent\",\n )}\n >\n <img src={pictureOf(option)} alt=\"\" draggable={false} className=\"h-full w-full rounded-full bg-surface-3 object-cover\" />\n <span\n aria-hidden\n className=\"absolute -bottom-0.5 -right-0.5 hidden h-5 w-5 items-center justify-center rounded-full border-2 border-surface-1 bg-accent text-on-accent group-data-[state=checked]/avatar:inline-flex\"\n >\n <CheckGlyph className=\"h-3 w-3\" />\n </span>\n </RadioGroupPrimitive.Item>\n ))}\n {upload ? <div className=\"flex aspect-square w-full items-center justify-center\">{upload}</div> : null}\n </RadioGroupPrimitive.Root>\n );\n if (!showLabel) return group;\n return (\n <div className={cn(\"flex flex-col gap-3\", className)}>\n <GroupHead id={id} label={label} description={description} />\n {group}\n </div>\n );\n}\n","import type * as React from \"react\";\n\n/** The visible label (and one line of help) of a radio group: the group's `aria-labelledby` points at it. */\nexport function GroupHead({ id, label, description }: { id: string; label: React.ReactNode; description?: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-0.5\">\n <span id={id} className=\"text-sm font-medium text-fg\">\n {label}\n </span>\n {description ? <span className=\"text-sm text-fg-secondary\">{description}</span> : null}\n </div>\n );\n}\n","// Client (a radio group). A single choice as selectable cards — an icon, a title, one line: the side of a lease, a plan, a\n// way to get the answer. Built on `RadioGroup.Card`, so the arrows choose, the card is the radio, the check lights up.\nimport * as React from \"react\";\n\nimport { RadioGroup } from \"../radio-group\";\nimport { GroupHead } from \"./group-head\";\n\nexport interface ChoiceCardOption {\n /** The value of the choice. */\n id: string;\n /** Its name, short. */\n title: React.ReactNode;\n /** One line under the title: what it means. It describes the radio. */\n description?: React.ReactNode;\n /** A glyph before the title (decorative). */\n icon?: React.ReactNode;\n disabled?: boolean;\n}\n\nexport type ChoiceCardsProps = Omit<React.ComponentProps<typeof RadioGroup.Root>, \"children\" | \"variant\" | \"label\"> & {\n /** The question (“Which side of the lease are you?”) — the group's accessible name, passed translated. */\n label: string;\n /** Shows the question above the cards, with `description` under it. */\n showLabel?: boolean;\n /** One line under the visible question. */\n description?: React.ReactNode;\n /** The choices. */\n options: readonly ChoiceCardOption[];\n /** The chosen id (controlled). */\n value?: string;\n /** The viewer chooses another card. */\n onValueChange?: (id: string) => void;\n};\n\n/** Cards to choose one from: a radio group where each card has an icon, a title and a description. */\nexport function ChoiceCards({ label, showLabel, description, options, className, ...props }: ChoiceCardsProps) {\n const base = React.useId();\n const group = (\n <RadioGroup.Root variant=\"cards\" label={label} aria-labelledby={showLabel ? `${base}-label` : undefined} className={[\"grid grid-cols-1 gap-3 sm:grid-cols-2\", !showLabel && className].filter(Boolean).join(\" \")} {...props}>\n {options.map((option) => {\n const describedBy = option.description ? `${base}-${option.id}` : undefined;\n return (\n <RadioGroup.Card key={option.id} value={option.id} disabled={option.disabled} aria-describedby={describedBy}>\n <span className=\"flex items-center gap-2.5 font-semibold text-fg [&>svg]:h-5 [&>svg]:w-5 [&>svg]:text-accent\">\n {option.icon}\n {option.title}\n </span>\n {option.description ? (\n <span id={describedBy} className=\"text-sm font-normal text-fg-secondary\">\n {option.description}\n </span>\n ) : null}\n </RadioGroup.Card>\n );\n })}\n </RadioGroup.Root>\n );\n if (!showLabel) return group;\n return (\n <div className={[\"flex flex-col gap-3\", className].filter(Boolean).join(\" \")}>\n <GroupHead id={`${base}-label`} label={label} description={description} />\n {group}\n </div>\n );\n}\n","// Client (a context). Radix RadioGroup: role=\"radiogroup\" / \"radio\", one tab stop, the arrows move and select, a\n// hidden input inside a form. Four looks, one behaviour:\n// - `RadioGroup.Item`: a dot and its words (a settings list);\n// - `RadioGroup.Card`: a whole card is the radio — an amount, a pack, a plan — its check lit when chosen;\n// - `RadioGroup.Button`: a tactile key that presses in — raised on a ledge, sunk when chosen (a size, a tip, a level);\n// - `RadioGroup.Segment` in `<RadioGroup.Root variant=\"segmented\">`: a segmented control, one light gliding to the choice.\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { CheckGlyph } from \"../glyphs\";\nimport { useRouteBinding } from \"../router\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { tv } from \"../tv\";\n\nexport const radioGroup = tv({\n slots: {\n root: \"grid gap-2 data-[orientation=horizontal]:flex data-[orientation=horizontal]:flex-wrap\",\n item:\n \"peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-control bg-surface-1 inset-shadow-well transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:shadow-glow aria-invalid:border-danger\",\n dot: \"h-2 w-2 rounded-full bg-on-accent\",\n label: \"flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-70\",\n card:\n \"group relative flex min-w-0 flex-col items-start gap-1 rounded-2xl border border-border-default bg-surface-1 bg-sheen p-4 pr-10 text-left text-sm text-fg inset-shadow-edge \" +\n \"transition-[border-color,background-color,box-shadow,transform] duration-200 hover:border-border-strong active:scale-[0.99] motion-reduce:transition-none motion-reduce:active:scale-100 \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent-soft data-[state=checked]:shadow-glow\",\n // The card's check: an empty ring at rest, the accent filled with its check once chosen.\n cardCheck:\n \"absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-control bg-surface-1 text-on-accent transition-colors \" +\n \"group-data-[state=checked]:border-accent group-data-[state=checked]:bg-accent\",\n // The tactile key: on a ledge (its lower edge), its hairline stronger on hover, pressed in while held and once chosen.\n button:\n \"relative inline-flex min-h-12 min-w-12 select-none flex-col items-center justify-center gap-0.5 rounded-xl border border-border-default bg-surface-2 bg-sheen px-4 py-2 \" +\n \"text-sm font-semibold text-fg inset-shadow-edge shadow-[0_4px_0_0_var(--kz-border-strong)] \" +\n \"transition-[transform,box-shadow,background-color,border-color,color] duration-100 ease-out motion-reduce:transition-none \" +\n \"hover:border-border-strong \" +\n \"active:translate-y-[3px] active:shadow-[0_1px_0_0_var(--kz-border-strong)] \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:translate-y-[3px] data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:bg-fill-shade \" +\n \"data-[state=checked]:text-on-accent data-[state=checked]:inset-shadow-edge-fill data-[state=checked]:shadow-[0_1px_0_0_var(--kz-accent-hover)]\",\n buttonHint: \"text-[11px] font-medium text-fg-secondary group-data-[state=checked]:text-on-accent\",\n segmented:\n \"relative isolate inline-grid auto-cols-fr grid-flow-col gap-1 rounded-xl border border-border-default bg-surface-2 p-1 inset-shadow-well \" +\n \"before:pointer-events-none before:absolute before:left-0 before:top-0 before:-z-10 before:h-(--kz-ind-h) before:w-(--kz-ind-w) \" +\n \"before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) before:rounded-lg before:border before:border-border-default before:bg-surface-0 before:bg-sheen \" +\n \"before:opacity-0 before:shadow-raised before:transition-[translate,width,height,opacity] before:duration-300 motion-reduce:before:transition-none data-[indicator=on]:before:opacity-100\",\n segment:\n \"inline-flex min-h-9 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-lg px-3.5 text-sm font-semibold text-fg-secondary transition-colors \" +\n \"hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border data-[state=checked]:border-border-default data-[state=checked]:bg-surface-0 data-[state=checked]:text-fg data-[state=checked]:shadow-raised \" +\n \"group-data-[indicator=on]/seg:data-[state=checked]:border-transparent group-data-[indicator=on]/seg:data-[state=checked]:bg-transparent group-data-[indicator=on]/seg:data-[state=checked]:shadow-none\",\n },\n variants: {\n variant: {\n list: {},\n cards: { root: \"grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-3\" },\n buttons: { root: \"flex flex-wrap gap-2.5 pb-1\" },\n segmented: {},\n },\n },\n defaultVariants: { variant: \"list\" },\n});\nconst s = radioGroup();\n\nexport type RadioGroupRootProps = React.ComponentProps<typeof RadioGroupPrimitive.Root> & {\n /** The group's accessible name — passed translated (or `aria-labelledby` a visible heading). */\n label?: string;\n /** Marks every radio invalid: aria-invalid (pair it with a `Field.Error`). */\n invalid?: boolean;\n /**\n * The layout of the radios: `list` (dots), `cards` (a grid of `Card`s), `buttons` (a row of tactile `Button`s), or\n * `segmented` (a track of `Segment`s, one light gliding to the choice).\n * @default \"list\"\n */\n variant?: \"list\" | \"cards\" | \"buttons\" | \"segmented\";\n /** Binds the choice to this search parameter of the URL (`?kind=…`): the URL is the state — for a view's selection (a segmented switch), not a form field. */\n routeKey?: string;\n /** The values the parameter may hold (the radios' `value`s); the first is the default unless `defaultValue` says otherwise. */\n routeValues?: readonly string[];\n};\n\n/** `value`/`defaultValue` + `onValueChange`, `orientation`, `required`, `name` for a form, `variant` for the layout. */\nexport function RadioGroupRoot({ label, invalid, variant = \"list\", className, routeKey, routeValues, ...rest }: RadioGroupRootProps) {\n const props = useRouteBinding(routeKey, routeValues, rest);\n const { ref } = useSlidingIndicator<HTMLDivElement>({ item: \"[role=radio]\", active: \"[role=radio][data-state=checked]\" });\n const segmented = variant === \"segmented\";\n return (\n <RadioGroupPrimitive.Root\n ref={segmented ? ref : undefined}\n aria-label={label}\n aria-invalid={invalid || undefined}\n data-invalid={invalid ? \"\" : undefined}\n data-variant={variant}\n orientation={segmented ? \"horizontal\" : props.orientation}\n className={segmented ? s.segmented({ className: [\"group/seg\", className].filter(Boolean).join(\" \") }) : radioGroup({ variant }).root({ className })}\n {...props}\n />\n );\n}\n\nexport type RadioGroupItemProps = Omit<React.ComponentProps<typeof RadioGroupPrimitive.Item>, \"children\"> & {\n /** The words next to the dot, clickable. Otherwise name it with `Field.Label htmlFor` or `aria-label`. */\n children?: React.ReactNode;\n};\n\n/** A radio: a dot, and its words when given. */\nexport function RadioGroupItem({ className, children, ...props }: RadioGroupItemProps) {\n const item = (\n <RadioGroupPrimitive.Item className={s.item({ className: children ? \"mt-0.5\" : className })} {...props}>\n <RadioGroupPrimitive.Indicator className={s.dot()} />\n </RadioGroupPrimitive.Item>\n );\n if (!children) return item;\n return (\n <label className={s.label({ className })}>\n {item}\n <span className=\"min-w-0\">{children}</span>\n </label>\n );\n}\n\n/** A whole card as the radio: its content is the radio's name; its check lights up when chosen. */\nexport function RadioGroupCard({ className, children, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return (\n <RadioGroupPrimitive.Item className={s.card({ className })} {...props}>\n {children}\n <span aria-hidden className={s.cardCheck()}>\n <RadioGroupPrimitive.Indicator forceMount className=\"inline-flex data-[state=unchecked]:hidden\">\n <CheckGlyph className=\"h-3 w-3\" />\n </RadioGroupPrimitive.Indicator>\n </span>\n </RadioGroupPrimitive.Item>\n );\n}\n\nexport type RadioGroupButtonProps = React.ComponentProps<typeof RadioGroupPrimitive.Item> & {\n /** A second line under the words (\"+15 %\"), part of the radio's name. */\n hint?: React.ReactNode;\n};\n\n/** A tactile key: raised on its ledge, pressed in while held and once chosen — sizes, a tip, a level. */\nexport function RadioGroupButton({ className, children, hint, ...props }: RadioGroupButtonProps) {\n return (\n <RadioGroupPrimitive.Item className={s.button({ className: [\"group\", className].filter(Boolean).join(\" \") })} {...props}>\n <span>{children}</span>\n {hint ? <span className={s.buttonHint()}>{hint}</span> : null}\n </RadioGroupPrimitive.Item>\n );\n}\n\n/** A segment of a `variant=\"segmented\"` group: equal widths, one light gliding to the choice. */\nexport function RadioGroupSegment({ className, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return <RadioGroupPrimitive.Item className={s.segment({ className })} {...props} />;\n}\n\n/** `RadioGroup.Root/Item/Card/Button/Segment`. */\nexport const RadioGroup = { Root: RadioGroupRoot, Item: RadioGroupItem, Card: RadioGroupCard, Button: RadioGroupButton, Segment: RadioGroupSegment };\n","// The shared sliding indicator (NavBar, Tabs): one element that glides from item to item instead of each item lighting\n// up on its own. It writes the target's box as CSS variables on the list (`--kz-ind-x/y/w/h`) and `data-indicator=\"on\"`\n// — no re-render, no animation frame: the glide is a CSS transition (none under reduced motion). Before hydration the\n// items keep their own active style, so nothing flashes.\nimport * as React from \"react\";\n\nconst useIsoLayoutEffect = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\n/**\n * `item`: the selector of an item; `active`: of the current one, where the light rests; `prefer`: an item that, when\n * present, holds the light before the current one (the NavBar's open menu); `follow`: the light follows the pointer\n * and the focus — over anything that is not an item (an open menu's panel) it goes back to rest.\n */\nexport function useSlidingIndicator<T extends HTMLElement>({ item, active, prefer, follow = false }: { item: string; active: string; prefer?: string; follow?: boolean }) {\n const ref = React.useRef<T>(null);\n const place = React.useCallback((target: Element | null) => {\n const list = ref.current;\n if (!list) return;\n if (!(target instanceof HTMLElement) || !list.contains(target)) {\n list.removeAttribute(\"data-indicator\");\n return;\n }\n const a = target.getBoundingClientRect();\n const b = list.getBoundingClientRect();\n list.style.setProperty(\"--kz-ind-x\", `${a.left - b.left + list.scrollLeft}px`);\n list.style.setProperty(\"--kz-ind-y\", `${a.top - b.top + list.scrollTop}px`);\n list.style.setProperty(\"--kz-ind-w\", `${a.width}px`);\n list.style.setProperty(\"--kz-ind-h\", `${a.height}px`);\n list.setAttribute(\"data-indicator\", \"on\");\n }, []);\n const rest = React.useCallback(\n () => {\n const list = ref.current;\n // An item re-rendered under a resting pointer (a menu closing) keeps the light the pointer gave it.\n const hovered = follow ? list?.querySelector(`${item}:hover`) : null;\n place((prefer ? list?.querySelector(prefer) : null) ?? hovered ?? list?.querySelector(active) ?? null);\n },\n [place, active, prefer, item, follow],\n );\n const follow_ = React.useCallback((target: EventTarget) => {\n const hit = target instanceof Element ? target.closest(item) : null;\n if (hit && ref.current?.contains(hit)) place(hit);\n else rest();\n }, [item, place, rest]);\n\n useIsoLayoutEffect(() => {\n const list = ref.current;\n if (!list) return;\n rest();\n const resize = new ResizeObserver(rest);\n resize.observe(list);\n const changes = new MutationObserver(rest);\n changes.observe(list, { subtree: true, attributes: true, attributeFilter: [\"data-state\", \"aria-current\", \"data-active\"] });\n return () => {\n resize.disconnect();\n changes.disconnect();\n };\n }, [rest]);\n\n const handlers = follow\n ? {\n onPointerOver: (e: React.PointerEvent) => follow_(e.target),\n onPointerLeave: rest,\n onFocus: (e: React.FocusEvent) => follow_(e.target),\n onBlur: rest,\n }\n : {};\n return { ref, handlers };\n}\n","import { createTV } from \"tailwind-variants\";\n\nimport { twMergeConfig } from \"./cn\";\n\n/** `tv` with the preset's utilities known to the merge engine (`twMergeConfig`): what a primitive wearing the material is styled with. */\nexport const tv = createTV({ twMergeConfig });\n","// Client (a radio group). The language of the account, labelled, each language named in its own language, saved per user\n// (the caller saves on change or with its section). Segmented: one light gliding to the choice.\nimport * as React from \"react\";\n\nimport { RadioGroup } from \"../radio-group\";\nimport { GroupHead } from \"./group-head\";\n\nexport interface LanguageOption {\n /** The BCP 47 code (`fr`, `en`): the value, and the `lang` of the name. */\n code: string;\n /** Its native name (`Français`, `English`) — never the current language's name for it. */\n name: string;\n}\n\nexport type LanguagePickerProps = Omit<React.ComponentProps<typeof RadioGroup.Root>, \"children\" | \"variant\" | \"label\" | \"aria-labelledby\"> & {\n /** The visible label (“Language”) — passed translated. */\n label: React.ReactNode;\n /**\n * Shows the label above the control; `false` when a `SettingsRow` already says it (the group keeps its accessible name).\n * @default true\n */\n showLabel?: boolean;\n /** One line under it: what it changes. */\n description?: React.ReactNode;\n /** The languages offered. */\n languages: readonly LanguageOption[];\n /** The chosen code (controlled). */\n value?: string;\n /** The viewer chooses another language. */\n onValueChange?: (code: string) => void;\n};\n\n/** The language control of an account page: a labelled segmented choice, native names. */\nexport function LanguagePicker({ label, showLabel = true, description, languages, className, ...props }: LanguagePickerProps) {\n const id = React.useId();\n return (\n <div className={[\"flex flex-col gap-2\", className].filter(Boolean).join(\" \")}>\n {showLabel ? <GroupHead id={`${id}-label`} label={label} description={description} /> : null}\n <RadioGroup.Root variant=\"segmented\" aria-label={showLabel ? undefined : String(label)} aria-labelledby={showLabel ? `${id}-label` : undefined} {...props}>\n {languages.map((language) => (\n <RadioGroup.Segment key={language.code} value={language.code} lang={language.code}>\n {language.name}\n </RadioGroup.Segment>\n ))}\n </RadioGroup.Root>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAEA,SAAS,UAA6B;;;ACI/B,IAAM,cAAc,aAAa;AAAA,EACtC,MAAM;AAAA,EACN,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA;AAAA,MAER,OAAO;AAAA,IACT;AAAA,IACA,MAAM,EAAE,IAAI,2BAA2B,IAAI,0BAA0B;AAAA,IACrE,OAAO,EAAE,MAAM,2CAA2C;AAAA,EAC5D;AAAA,EACA,iBAAiB,EAAE,MAAM,WAAW,MAAM,KAAK;AACjD,CAAC;;;ADUG,SACU,KADV;AAxBG,IAAM,gBAAgB,GAAG,WAAW;AAsBpC,SAAS,MAAM,EAAE,MAAM,MAAM,OAAO,KAAK,WAAW,UAAU,GAAG,MAAM,GAAe;AAC3F,SACE,qBAAC,UAAK,aAAW,QAAQ,WAAW,WAAW,cAAc,EAAE,MAAM,MAAM,OAAO,UAAU,CAAC,GAAI,GAAG,OACjG;AAAA,WAAO,oBAAC,UAAK,YAAS,IAAG,eAAW,MAAC,WAAU,uCAAsC;AAAA,IACrF;AAAA,KACH;AAEJ;;;AEDM,SACE,OAAAA,MADF,QAAAC,aAAA;AAHC,SAAS,mBAAmB,EAAE,MAAM,OAAO,UAAU,eAAe,iBAAiB,aAAa,QAAQ,QAAQ,SAAS,WAAW,GAAG,MAAM,GAA4B;AAChL,SACE,gBAAAA,MAAC,aAAQ,cAAY,MAAM,WAAW,GAAG,2BAA2B,CAAC,WAAW,mDAAmD,SAAS,GAAI,GAAG,OACjJ;AAAA,oBAAAA,MAAC,SAAI,WAAU,6CACb;AAAA,sBAAAD,KAAC,UAAO,MAAM,UAAU,OAAO,MAAM,KAAI,IAAG,UAAU,KAAK,MAAM,GAAG,CAAC,GAAI,GAAG,QAAQ;AAAA,MACnF;AAAA,OACH;AAAA,IACA,gBAAAC,MAAC,SAAI,WAAU,+BACb;AAAA,sBAAAD,KAAC,QAAG,WAAW,GAAG,kCAAkC,UAAU,wBAAwB,SAAS,GAAI,gBAAK;AAAA,MACxG,gBAAAC,MAAC,OAAE,WAAU,mEACX;AAAA,wBAAAD,KAAC,UAAK,WAAU,oBAAoB,iBAAM;AAAA,QAC1C,gBAAAA,KAAC,SAAM,MAAM,WAAW,YAAY,WAAW,KAAG,MAC/C,qBAAW,gBAAgB,iBAC9B;AAAA,SACF;AAAA,MACC,cAAc,gBAAAA,KAAC,OAAE,WAAU,6BAA6B,uBAAY,IAAO;AAAA,OAC9E;AAAA,KACF;AAEJ;;;AClDA,SAAS,cAAc,2BAA2B;AAClD,YAAY,WAAW;;;ACEnB,SACE,OAAAE,MADF,QAAAC,aAAA;AAFG,SAAS,UAAU,EAAE,IAAI,OAAO,YAAY,GAA0E;AAC3H,SACE,gBAAAA,MAAC,SAAI,WAAU,yBACb;AAAA,oBAAAD,KAAC,UAAK,IAAQ,WAAU,+BACrB,iBACH;AAAA,IACC,cAAc,gBAAAA,KAAC,UAAK,WAAU,6BAA6B,uBAAY,IAAU;AAAA,KACpF;AAEJ;;;ADuCQ,SAUE,OAAAE,MAVF,QAAAC,aAAA;AARR,IAAM,YAAY,CAAC,WAAyB,OAAO,QAAQ,OAAO,gBAAgB,iBAAiB,OAAO,eAAe,EAAE,MAAM,IAAI,CAAC,IAAI;AAGnI,SAAS,aAAa,EAAE,OAAO,WAAW,aAAa,OAAO,SAAS,QAAQ,WAAW,GAAG,MAAM,GAAsB;AAC9H,QAAM,KAAW,YAAM;AACvB,QAAM,QACJ,gBAAAA,MAAC,oBAAoB,MAApB,EAAyB,cAAY,OAAO,mBAAiB,YAAY,KAAK,QAAW,WAAW,GAAG,QAAQ,2BAA2B,gEAAgE,CAAC,aAAa,SAAS,GAAI,GAAG,OACtO;AAAA,YAAQ,IAAI,CAAC,WACZ,gBAAAA;AAAA,MAAC,oBAAoB;AAAA,MAApB;AAAA,QAEC,OAAO,OAAO;AAAA,QACd,cAAY,OAAO;AAAA,QACnB,WAAW;AAAA,UACT;AAAA,UAA+C,QAAQ,cAAc;AAAA,UACrE;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,0BAAAD,KAAC,SAAI,KAAK,UAAU,MAAM,GAAG,KAAI,IAAG,WAAW,OAAO,WAAU,wDAAuD;AAAA,UACvH,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,eAAW;AAAA,cACX,WAAU;AAAA,cAEV,0BAAAA,KAAC,cAAW,WAAU,WAAU;AAAA;AAAA,UAClC;AAAA;AAAA;AAAA,MAfK,OAAO;AAAA,IAgBd,CACD;AAAA,IACA,SAAS,gBAAAA,KAAC,SAAI,WAAU,yDAAyD,kBAAO,IAAS;AAAA,KACpG;AAEF,MAAI,CAAC,UAAW,QAAO;AACvB,SACE,gBAAAC,MAAC,SAAI,WAAW,GAAG,uBAAuB,SAAS,GACjD;AAAA,oBAAAD,KAAC,aAAU,IAAQ,OAAc,aAA0B;AAAA,IAC1D;AAAA,KACH;AAEJ;;;AE9EA,YAAYE,YAAW;;;ACIvB,SAAS,cAAcC,4BAA2B;AAIlD,SAAS,uBAAuB;;;ACNhC,YAAYC,YAAW;AAEvB,IAAM,qBAAqB,OAAO,WAAW,cAAoB,mBAAkB;AAO5E,SAAS,oBAA2C,EAAE,MAAM,QAAQ,QAAQ,SAAS,MAAM,GAAwE;AACxK,QAAM,MAAY,cAAU,IAAI;AAChC,QAAM,QAAc,mBAAY,CAAC,WAA2B;AAC1D,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,KAAM;AACX,QAAI,EAAE,kBAAkB,gBAAgB,CAAC,KAAK,SAAS,MAAM,GAAG;AAC9D,WAAK,gBAAgB,gBAAgB;AACrC;AAAA,IACF;AACA,UAAM,IAAI,OAAO,sBAAsB;AACvC,UAAM,IAAI,KAAK,sBAAsB;AACrC,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,OAAO,EAAE,OAAO,KAAK,UAAU,IAAI;AAC7E,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,IAAI;AAC1E,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,KAAK,IAAI;AACnD,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,MAAM,IAAI;AACpD,SAAK,aAAa,kBAAkB,IAAI;AAAA,EAC1C,GAAG,CAAC,CAAC;AACL,QAAM,OAAa;AAAA,IACjB,MAAM;AACJ,YAAM,OAAO,IAAI;AAEjB,YAAM,UAAU,SAAS,MAAM,cAAc,GAAG,IAAI,QAAQ,IAAI;AAChE,aAAO,SAAS,MAAM,cAAc,MAAM,IAAI,SAAS,WAAW,MAAM,cAAc,MAAM,KAAK,IAAI;AAAA,IACvG;AAAA,IACA,CAAC,OAAO,QAAQ,QAAQ,MAAM,MAAM;AAAA,EACtC;AACA,QAAM,UAAgB,mBAAY,CAAC,WAAwB;AACzD,UAAM,MAAM,kBAAkB,UAAU,OAAO,QAAQ,IAAI,IAAI;AAC/D,QAAI,OAAO,IAAI,SAAS,SAAS,GAAG,EAAG,OAAM,GAAG;AAAA,QAC3C,MAAK;AAAA,EACZ,GAAG,CAAC,MAAM,OAAO,IAAI,CAAC;AAEtB,qBAAmB,MAAM;AACvB,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,KAAM;AACX,SAAK;AACL,UAAM,SAAS,IAAI,eAAe,IAAI;AACtC,WAAO,QAAQ,IAAI;AACnB,UAAM,UAAU,IAAI,iBAAiB,IAAI;AACzC,YAAQ,QAAQ,MAAM,EAAE,SAAS,MAAM,YAAY,MAAM,iBAAiB,CAAC,cAAc,gBAAgB,aAAa,EAAE,CAAC;AACzH,WAAO,MAAM;AACX,aAAO,WAAW;AAClB,cAAQ,WAAW;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,WAAW,SACb;AAAA,IACE,eAAe,CAAC,MAA0B,QAAQ,EAAE,MAAM;AAAA,IAC1D,gBAAgB;AAAA,IAChB,SAAS,CAAC,MAAwB,QAAQ,EAAE,MAAM;AAAA,IAClD,QAAQ;AAAA,EACV,IACA,CAAC;AACL,SAAO,EAAE,KAAK,SAAS;AACzB;;;ACpEA,SAAS,gBAAgB;AAKlB,IAAMC,MAAK,SAAS,EAAE,cAAc,CAAC;;;AFoFxC,gBAAAC,MA2BA,QAAAC,aA3BA;AA3EG,IAAM,aAAaC,IAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MACE;AAAA,IAGF,KAAK;AAAA,IACL,OAAO;AAAA,IACP,MACE;AAAA;AAAA,IAKF,WACE;AAAA;AAAA,IAGF,QACE;AAAA,IAQF,YAAY;AAAA,IACZ,WACE;AAAA,IAIF,SACE;AAAA,EAIJ;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,MACP,MAAM,CAAC;AAAA,MACP,OAAO,EAAE,MAAM,uDAAuD;AAAA,MACtE,SAAS,EAAE,MAAM,8BAA8B;AAAA,MAC/C,WAAW,CAAC;AAAA,IACd;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,SAAS,OAAO;AACrC,CAAC;AACD,IAAM,IAAI,WAAW;AAoBd,SAAS,eAAe,EAAE,OAAO,SAAS,UAAU,QAAQ,WAAW,UAAU,aAAa,GAAG,KAAK,GAAwB;AACnI,QAAM,QAAQ,gBAAgB,UAAU,aAAa,IAAI;AACzD,QAAM,EAAE,IAAI,IAAI,oBAAoC,EAAE,MAAM,gBAAgB,QAAQ,mCAAmC,CAAC;AACxH,QAAM,YAAY,YAAY;AAC9B,SACE,gBAAAF;AAAA,IAACG,qBAAoB;AAAA,IAApB;AAAA,MACC,KAAK,YAAY,MAAM;AAAA,MACvB,cAAY;AAAA,MACZ,gBAAc,WAAW;AAAA,MACzB,gBAAc,UAAU,KAAK;AAAA,MAC7B,gBAAc;AAAA,MACd,aAAa,YAAY,eAAe,MAAM;AAAA,MAC9C,WAAW,YAAY,EAAE,UAAU,EAAE,WAAW,CAAC,aAAa,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,CAAC,IAAI,WAAW,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC;AAAA,MACjJ,GAAG;AAAA;AAAA,EACN;AAEJ;AAQO,SAAS,eAAe,EAAE,WAAW,UAAU,GAAG,MAAM,GAAwB;AACrF,QAAM,OACJ,gBAAAH,KAACG,qBAAoB,MAApB,EAAyB,WAAW,EAAE,KAAK,EAAE,WAAW,WAAW,WAAW,UAAU,CAAC,GAAI,GAAG,OAC/F,0BAAAH,KAACG,qBAAoB,WAApB,EAA8B,WAAW,EAAE,IAAI,GAAG,GACrD;AAEF,MAAI,CAAC,SAAU,QAAO;AACtB,SACE,gBAAAF,MAAC,WAAM,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,GACpC;AAAA;AAAA,IACD,gBAAAD,KAAC,UAAK,WAAU,WAAW,UAAS;AAAA,KACtC;AAEJ;AAGO,SAAS,eAAe,EAAE,WAAW,UAAU,GAAG,MAAM,GAA0D;AACvH,SACE,gBAAAC,MAACE,qBAAoB,MAApB,EAAyB,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC7D;AAAA;AAAA,IACD,gBAAAH,KAAC,UAAK,eAAW,MAAC,WAAW,EAAE,UAAU,GACvC,0BAAAA,KAACG,qBAAoB,WAApB,EAA8B,YAAU,MAAC,WAAU,6CAClD,0BAAAH,KAAC,cAAW,WAAU,WAAU,GAClC,GACF;AAAA,KACF;AAEJ;AAQO,SAAS,iBAAiB,EAAE,WAAW,UAAU,MAAM,GAAG,MAAM,GAA0B;AAC/F,SACE,gBAAAC,MAACE,qBAAoB,MAApB,EAAyB,WAAW,EAAE,OAAO,EAAE,WAAW,CAAC,SAAS,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,CAAC,GAAI,GAAG,OAChH;AAAA,oBAAAH,KAAC,UAAM,UAAS;AAAA,IACf,OAAO,gBAAAA,KAAC,UAAK,WAAW,EAAE,WAAW,GAAI,gBAAK,IAAU;AAAA,KAC3D;AAEJ;AAGO,SAAS,kBAAkB,EAAE,WAAW,GAAG,MAAM,GAA0D;AAChH,SAAO,gBAAAA,KAACG,qBAAoB,MAApB,EAAyB,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AACnF;AAGO,IAAM,aAAa,EAAE,MAAM,gBAAgB,MAAM,gBAAgB,MAAM,gBAAgB,QAAQ,kBAAkB,SAAS,kBAAkB;;;ADnHvI,SAKE,OAAAC,MALF,QAAAC,aAAA;AARL,SAAS,YAAY,EAAE,OAAO,WAAW,aAAa,SAAS,WAAW,GAAG,MAAM,GAAqB;AAC7G,QAAM,OAAa,aAAM;AACzB,QAAM,QACJ,gBAAAD,KAAC,WAAW,MAAX,EAAgB,SAAQ,SAAQ,OAAc,mBAAiB,YAAY,GAAG,IAAI,WAAW,QAAW,WAAW,CAAC,yCAAyC,CAAC,aAAa,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,OACnN,kBAAQ,IAAI,CAAC,WAAW;AACvB,UAAM,cAAc,OAAO,cAAc,GAAG,IAAI,IAAI,OAAO,EAAE,KAAK;AAClE,WACE,gBAAAC,MAAC,WAAW,MAAX,EAAgC,OAAO,OAAO,IAAI,UAAU,OAAO,UAAU,oBAAkB,aAC9F;AAAA,sBAAAA,MAAC,UAAK,WAAU,+FACb;AAAA,eAAO;AAAA,QACP,OAAO;AAAA,SACV;AAAA,MACC,OAAO,cACN,gBAAAD,KAAC,UAAK,IAAI,aAAa,WAAU,yCAC9B,iBAAO,aACV,IACE;AAAA,SATgB,OAAO,EAU7B;AAAA,EAEJ,CAAC,GACH;AAEF,MAAI,CAAC,UAAW,QAAO;AACvB,SACE,gBAAAC,MAAC,SAAI,WAAW,CAAC,uBAAuB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GACzE;AAAA,oBAAAD,KAAC,aAAU,IAAI,GAAG,IAAI,UAAU,OAAc,aAA0B;AAAA,IACvE;AAAA,KACH;AAEJ;;;AI9DA,YAAYE,YAAW;AAkCnB,SACe,OAAAC,MADf,QAAAC,aAAA;AAHG,SAAS,eAAe,EAAE,OAAO,YAAY,MAAM,aAAa,WAAW,WAAW,GAAG,MAAM,GAAwB;AAC5H,QAAM,KAAW,aAAM;AACvB,SACE,gBAAAA,MAAC,SAAI,WAAW,CAAC,uBAAuB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GACxE;AAAA,gBAAY,gBAAAD,KAAC,aAAU,IAAI,GAAG,EAAE,UAAU,OAAc,aAA0B,IAAK;AAAA,IACxF,gBAAAA,KAAC,WAAW,MAAX,EAAgB,SAAQ,aAAY,cAAY,YAAY,SAAY,OAAO,KAAK,GAAG,mBAAiB,YAAY,GAAG,EAAE,WAAW,QAAY,GAAG,OACjJ,oBAAU,IAAI,CAAC,aACd,gBAAAA,KAAC,WAAW,SAAX,EAAuC,OAAO,SAAS,MAAM,MAAM,SAAS,MAC1E,mBAAS,QADa,SAAS,IAElC,CACD,GACH;AAAA,KACF;AAEJ;","names":["jsx","jsxs","jsx","jsxs","jsx","jsxs","React","RadioGroupPrimitive","React","tv","jsx","jsxs","tv","RadioGroupPrimitive","jsx","jsxs","React","jsx","jsxs"]}
|
package/dist/anatomy-plate.d.ts
CHANGED
|
@@ -20,7 +20,10 @@ type AnatomyPlateProps = Omit<React.HTMLAttributes<HTMLElement>, "title"> & {
|
|
|
20
20
|
/** The specimen's scale on a wide screen (it is drawn at 1 on a phone). @default 1.6 */
|
|
21
21
|
scale?: number;
|
|
22
22
|
};
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* A component's anatomy as a naturalist's plate: the specimen in the middle, its numbered parts and their reasons around it.
|
|
25
|
+
* @deprecated Since 3.55 (ADR-006, krizaka-ui#674): no product uses it. Removed in 4.0.
|
|
26
|
+
*/
|
|
24
27
|
declare function AnatomyPlate({ title, subtitle, parts, children, scale, className, style, ...props }: AnatomyPlateProps): React.JSX.Element;
|
|
25
28
|
|
|
26
29
|
export { type AnatomyPart, AnatomyPlate, type AnatomyPlateProps };
|
package/dist/anatomy-plate.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
warnDeprecated
|
|
3
|
+
} from "./chunk-KGLRZMCY.js";
|
|
1
4
|
import {
|
|
2
5
|
cn
|
|
3
6
|
} from "./chunk-W675RFOA.js";
|
|
@@ -5,6 +8,7 @@ import {
|
|
|
5
8
|
// src/anatomy-plate/anatomy-plate.tsx
|
|
6
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
10
|
function AnatomyPlate({ title, subtitle, parts, children, scale = 1.6, className, style, ...props }) {
|
|
11
|
+
warnDeprecated("anatomy-plate");
|
|
8
12
|
const numbered = parts.map((p, i) => ({ ...p, n: i + 1, side: p.side ?? (i % 2 === 0 ? "left" : "right") }));
|
|
9
13
|
const column = (side) => /* @__PURE__ */ jsx("ol", { className: "kz-anatomy-parts", "data-side": side, children: numbered.filter((p) => p.side === side).map((p) => /* @__PURE__ */ jsxs("li", { value: p.n, className: "kz-anatomy-part", children: [
|
|
10
14
|
/* @__PURE__ */ jsx("span", { className: "kz-anatomy-n", "aria-hidden": true, children: p.n }),
|