@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/dist/radio-group.js
CHANGED
|
@@ -2,29 +2,27 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CheckGlyph
|
|
4
4
|
} from "./chunk-KDXRYUD3.js";
|
|
5
|
-
import {
|
|
6
|
-
useSlidingIndicator
|
|
7
|
-
} from "./chunk-4QN5YJ3D.js";
|
|
8
|
-
import {
|
|
9
|
-
useRouteBinding
|
|
10
|
-
} from "./chunk-R3LTSMS5.js";
|
|
11
5
|
import {
|
|
12
6
|
tv
|
|
13
7
|
} from "./chunk-HJFRHYCI.js";
|
|
8
|
+
import {
|
|
9
|
+
useSlidingIndicator
|
|
10
|
+
} from "./chunk-4QN5YJ3D.js";
|
|
14
11
|
import "./chunk-NSLXEDIS.js";
|
|
15
12
|
|
|
16
13
|
// src/radio-group/radio-group.tsx
|
|
17
14
|
import { RadioGroup as RadioGroupPrimitive } from "radix-ui";
|
|
15
|
+
import { useRouteBinding } from "@krizaka/ui/router";
|
|
18
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
17
|
var radioGroup = tv({
|
|
20
18
|
slots: {
|
|
21
19
|
root: "grid gap-2 data-[orientation=horizontal]:flex data-[orientation=horizontal]:flex-wrap",
|
|
22
|
-
item: "peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-
|
|
20
|
+
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",
|
|
23
21
|
dot: "h-2 w-2 rounded-full bg-on-accent",
|
|
24
22
|
label: "flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-70",
|
|
25
23
|
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",
|
|
26
24
|
// The card's check: an empty ring at rest, the accent filled with its check once chosen.
|
|
27
|
-
cardCheck: "absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-
|
|
25
|
+
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",
|
|
28
26
|
// The tactile key: on a ledge (its lower edge), its hairline stronger on hover, pressed in while held and once chosen.
|
|
29
27
|
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)]",
|
|
30
28
|
buttonHint: "text-[11px] font-medium text-fg-secondary group-data-[state=checked]:text-on-accent",
|
package/dist/radio-group.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/radio-group/radio-group.tsx"],"sourcesContent":["// 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"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/radio-group/radio-group.tsx"],"sourcesContent":["// 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"],"mappings":"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","names":[]}
|
package/dist/rail-nav.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ declare const railNav: tailwind_variants.TVReturnType<{
|
|
|
14
14
|
toggle?: tailwind_variants.ClassValue;
|
|
15
15
|
shell?: tailwind_variants.ClassValue;
|
|
16
16
|
foot?: tailwind_variants.ClassValue;
|
|
17
|
+
shortcuts?: tailwind_variants.ClassValue;
|
|
18
|
+
shortcutsHeading?: tailwind_variants.ClassValue;
|
|
17
19
|
icon?: tailwind_variants.ClassValue;
|
|
18
20
|
badge?: tailwind_variants.ClassValue;
|
|
19
21
|
root?: tailwind_variants.ClassValue;
|
|
@@ -31,6 +33,8 @@ declare const railNav: tailwind_variants.TVReturnType<{
|
|
|
31
33
|
toggle?: tailwind_variants.ClassValue;
|
|
32
34
|
shell?: tailwind_variants.ClassValue;
|
|
33
35
|
foot?: tailwind_variants.ClassValue;
|
|
36
|
+
shortcuts?: tailwind_variants.ClassValue;
|
|
37
|
+
shortcutsHeading?: tailwind_variants.ClassValue;
|
|
34
38
|
icon?: tailwind_variants.ClassValue;
|
|
35
39
|
badge?: tailwind_variants.ClassValue;
|
|
36
40
|
root?: tailwind_variants.ClassValue;
|
|
@@ -44,6 +48,8 @@ declare const railNav: tailwind_variants.TVReturnType<{
|
|
|
44
48
|
group: string;
|
|
45
49
|
main: string;
|
|
46
50
|
foot: string;
|
|
51
|
+
shortcuts: string;
|
|
52
|
+
shortcutsHeading: string;
|
|
47
53
|
item: string;
|
|
48
54
|
icon: string;
|
|
49
55
|
label: string;
|
|
@@ -61,6 +67,8 @@ declare const railNav: tailwind_variants.TVReturnType<{
|
|
|
61
67
|
toggle?: tailwind_variants.ClassValue;
|
|
62
68
|
shell?: tailwind_variants.ClassValue;
|
|
63
69
|
foot?: tailwind_variants.ClassValue;
|
|
70
|
+
shortcuts?: tailwind_variants.ClassValue;
|
|
71
|
+
shortcutsHeading?: tailwind_variants.ClassValue;
|
|
64
72
|
icon?: tailwind_variants.ClassValue;
|
|
65
73
|
badge?: tailwind_variants.ClassValue;
|
|
66
74
|
root?: tailwind_variants.ClassValue;
|
|
@@ -74,6 +82,8 @@ declare const railNav: tailwind_variants.TVReturnType<{
|
|
|
74
82
|
group: string;
|
|
75
83
|
main: string;
|
|
76
84
|
foot: string;
|
|
85
|
+
shortcuts: string;
|
|
86
|
+
shortcutsHeading: string;
|
|
77
87
|
item: string;
|
|
78
88
|
icon: string;
|
|
79
89
|
label: string;
|
|
@@ -87,6 +97,8 @@ declare const railNav: tailwind_variants.TVReturnType<{
|
|
|
87
97
|
group: string;
|
|
88
98
|
main: string;
|
|
89
99
|
foot: string;
|
|
100
|
+
shortcuts: string;
|
|
101
|
+
shortcutsHeading: string;
|
|
90
102
|
item: string;
|
|
91
103
|
icon: string;
|
|
92
104
|
label: string;
|
|
@@ -109,11 +121,15 @@ type RailNavRootProps = Omit<React.ComponentProps<"nav">, "children"> & {
|
|
|
109
121
|
children: React.ReactNode;
|
|
110
122
|
/** At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. `RailNav.Item`s or a control with `data-rail-item`. */
|
|
111
123
|
footer?: React.ReactNode;
|
|
124
|
+
/** The product's shortcuts (`RailNav.Item`s: a saved view, a client, « New invoice »), a group above the footer and the expand toggle. Desktop only: a phone's tab bar keeps its destinations. */
|
|
125
|
+
shortcuts?: React.ReactNode;
|
|
126
|
+
/** The shortcuts' heading (« Raccourcis », « Shortcuts ») — passed translated: the group's name, shown once the rail is expanded. */
|
|
127
|
+
shortcutsLabel?: string;
|
|
112
128
|
/** Adds a button that widens the rail to show the words (desktop only). Needs `expandLabels`. */
|
|
113
129
|
expandable?: boolean;
|
|
114
130
|
/** Controlled width (pair with `onExpandedChange` to keep the choice). */
|
|
115
131
|
expanded?: boolean;
|
|
116
|
-
/** The starting width when uncontrolled. */
|
|
132
|
+
/** The starting width when uncontrolled. Unset: expanded from 1280 px (the words fit there), narrow below — until the person toggles it. */
|
|
117
133
|
defaultExpanded?: boolean;
|
|
118
134
|
/** Called when the toggle widens or narrows the rail. */
|
|
119
135
|
onExpandedChange?: (expanded: boolean) => void;
|
|
@@ -121,7 +137,7 @@ type RailNavRootProps = Omit<React.ComponentProps<"nav">, "children"> & {
|
|
|
121
137
|
expandLabels?: readonly [string, string];
|
|
122
138
|
};
|
|
123
139
|
/** The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone. */
|
|
124
|
-
declare function RailNavRoot({ label, mark, accent, children, footer, expandable, expanded: controlled, defaultExpanded, onExpandedChange, expandLabels, className, onKeyDown, ...props }: RailNavRootProps): React.JSX.Element;
|
|
140
|
+
declare function RailNavRoot({ label, mark, accent, children, footer, shortcuts, shortcutsLabel, expandable, expanded: controlled, defaultExpanded, onExpandedChange, expandLabels, className, onKeyDown, ...props }: RailNavRootProps): React.JSX.Element;
|
|
125
141
|
type RailNavItemProps = Omit<React.ComponentProps<"a">, "children"> & {
|
|
126
142
|
/** The item's icon (a signature icon of `@krizaka/icons`): all that shows on a desktop rail. */
|
|
127
143
|
icon: React.ReactNode;
|
package/dist/rail-nav.js
CHANGED
|
@@ -60,6 +60,10 @@ var railNav = tv({
|
|
|
60
60
|
group: "flex min-w-0 flex-row items-stretch md:flex-col md:items-center md:gap-1 md:px-1.5 md:group-data-expanded/rail:items-stretch",
|
|
61
61
|
main: "max-md:grow-(--rail-n) md:flex-1 md:py-2",
|
|
62
62
|
foot: "max-md:grow-(--rail-n) md:border-t md:border-border-subtle md:py-2",
|
|
63
|
+
// The shortcuts: the product's quick ways in (a saved view, a client, « new invoice »), desktop only — a phone's tab bar
|
|
64
|
+
// keeps its five destinations. Their heading shows once the rail is expanded; collapsed, it names the group.
|
|
65
|
+
shortcuts: "hidden md:flex md:border-t md:border-border-subtle md:py-2",
|
|
66
|
+
shortcutsHeading: "sr-only md:group-data-expanded/rail:not-sr-only md:group-data-expanded/rail:px-3.5 md:group-data-expanded/rail:pb-1 md:group-data-expanded/rail:pt-1 text-[11px] font-semibold text-fg-secondary",
|
|
63
67
|
item: "group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0",
|
|
64
68
|
icon: "relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5",
|
|
65
69
|
label: "max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only",
|
|
@@ -82,6 +86,17 @@ function RailNavBody({ className, ...props }) {
|
|
|
82
86
|
return /* @__PURE__ */ jsx2("div", { className: s.body({ className }), ...props });
|
|
83
87
|
}
|
|
84
88
|
var count = (node) => React.Children.toArray(node).length;
|
|
89
|
+
var WIDE = "(min-width: 80rem)";
|
|
90
|
+
var subscribeWide = (onChange) => {
|
|
91
|
+
if (typeof window === "undefined" || !window.matchMedia) return () => void 0;
|
|
92
|
+
const query = window.matchMedia(WIDE);
|
|
93
|
+
query.addEventListener("change", onChange);
|
|
94
|
+
return () => query.removeEventListener("change", onChange);
|
|
95
|
+
};
|
|
96
|
+
var isWide = () => typeof window !== "undefined" && Boolean(window.matchMedia?.(WIDE).matches);
|
|
97
|
+
function useWide() {
|
|
98
|
+
return React.useSyncExternalStore(subscribeWide, isWide, () => false);
|
|
99
|
+
}
|
|
85
100
|
function moveFocus(event) {
|
|
86
101
|
const keys = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 };
|
|
87
102
|
const step = keys[event.key];
|
|
@@ -103,9 +118,11 @@ function RailNavRoot({
|
|
|
103
118
|
accent,
|
|
104
119
|
children,
|
|
105
120
|
footer,
|
|
121
|
+
shortcuts,
|
|
122
|
+
shortcutsLabel,
|
|
106
123
|
expandable,
|
|
107
124
|
expanded: controlled,
|
|
108
|
-
defaultExpanded
|
|
125
|
+
defaultExpanded,
|
|
109
126
|
onExpandedChange,
|
|
110
127
|
expandLabels,
|
|
111
128
|
className,
|
|
@@ -113,7 +130,9 @@ function RailNavRoot({
|
|
|
113
130
|
...props
|
|
114
131
|
}) {
|
|
115
132
|
const [own, setOwn] = React.useState(defaultExpanded);
|
|
116
|
-
const
|
|
133
|
+
const wide = useWide();
|
|
134
|
+
const headingId = React.useId();
|
|
135
|
+
const expanded = expandable ? controlled ?? own ?? wide : false;
|
|
117
136
|
const toggle = () => {
|
|
118
137
|
if (controlled === void 0) setOwn(!expanded);
|
|
119
138
|
onExpandedChange?.(!expanded);
|
|
@@ -133,6 +152,10 @@ function RailNavRoot({
|
|
|
133
152
|
children: [
|
|
134
153
|
mark && /* @__PURE__ */ jsx2("div", { "data-brand-mark": true, className: s.mark(), children: mark }),
|
|
135
154
|
/* @__PURE__ */ jsx2("div", { className: s.group({ className: s.main() }), style: { ["--rail-n"]: Math.max(count(children), 1) }, children }),
|
|
155
|
+
shortcuts && /* @__PURE__ */ jsxs2("div", { role: "group", "aria-labelledby": shortcutsLabel ? headingId : void 0, "data-rail-shortcuts": "", className: s.group({ className: s.shortcuts() }), children: [
|
|
156
|
+
shortcutsLabel && /* @__PURE__ */ jsx2("p", { id: headingId, className: s.shortcutsHeading(), children: shortcutsLabel }),
|
|
157
|
+
shortcuts
|
|
158
|
+
] }),
|
|
136
159
|
(footer || expandable) && /* @__PURE__ */ jsxs2("div", { className: s.group({ className: s.foot() }), style: { ["--rail-n"]: Math.max(count(footer), 1) }, children: [
|
|
137
160
|
footer,
|
|
138
161
|
expandable && expandLabels && /* @__PURE__ */ jsxs2("button", { type: "button", "data-rail-item": true, className: s.toggle(), "aria-expanded": expanded, onClick: toggle, children: [
|
package/dist/rail-nav.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tooltip/tooltip.tsx","../src/floating.ts","../src/rail-nav/rail-nav.tsx"],"sourcesContent":["// Client (a portal). A short label for a control, on hover after `delayDuration` and on keyboard focus at once;\n// Escape dismisses it. It names nothing: the control keeps its own accessible name (an IconButton's `label`).\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\n/** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\nexport type TooltipProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Content>, \"content\" | \"children\"> & {\n /** What the tooltip says — passed translated. */\n content: React.ReactNode;\n /** The trigger, rendered as is (`asChild`): a focusable element. */\n children: React.ReactNode;\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Hover delay in ms before it opens (300 by default). */\n delayDuration?: number;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function Tooltip({\n content,\n children,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration = 300,\n container,\n sideOffset = 6,\n collisionPadding = 8,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipPrimitive.Provider delayDuration={delayDuration}>\n <TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(floating, \"max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)\", className)}\n {...props}\n >\n {content}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\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 (the expand state, the arrow keys, the tooltip). The compact navigation of an application, read from Orazaka's\n// web client: a vertical rail of icons on a desktop — the product's mark on top, a tooltip on each icon, the current one\n// marked by an accent bar on its left edge, a footer for settings and the account — that becomes a bottom tab bar on a\n// phone. The same nodes in both: only the layout changes, so the items, their order and their words are written once.\n// The mark lives in the rail on a desktop; on a phone, where the rail has no room for it, `AppHeader` shows it (the rule\n// « one mark visible at every width »). Brand-aware through the tokens: `accent` scopes `.brand-<id>`.\nimport { Tooltip } from \"@krizaka/ui/tooltip\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph } from \"../glyphs\";\nimport type { BrandId } from \"../marks/ProductLogo\";\n\nexport const railNav = tv({\n slots: {\n shell: \"flex min-h-dvh w-full bg-surface-0 text-fg\",\n root:\n // Phone: a bottom tab bar, clear of the home indicator. Desktop: a sticky column that is only as wide as its icons.\n \"fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1 pb-[env(safe-area-inset-bottom)] \" +\n \"md:sticky md:overflow-x-clip md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 \" +\n \"md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56\",\n // The mark is the rail's on a desktop; hidden on a phone (the header carries it there).\n mark: \"hidden h-14 w-full shrink-0 items-center overflow-hidden justify-center md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-4\",\n group: \"flex min-w-0 flex-row items-stretch md:flex-col md:items-center md:gap-1 md:px-1.5 md:group-data-expanded/rail:items-stretch\",\n main: \"max-md:grow-(--rail-n) md:flex-1 md:py-2\",\n foot: \"max-md:grow-(--rail-n) md:border-t md:border-border-subtle md:py-2\",\n item:\n \"group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent \" +\n // The accent bar: on the top edge of a tab, on the left edge of a rail item.\n \"before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 \" +\n \"md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm \" +\n \"md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0\",\n icon: \"relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n label: \"max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only\",\n badge:\n \"absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-sm bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]\",\n toggle:\n \"hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5\",\n body: \"flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]\",\n },\n});\nconst s = railNav();\n\ninterface RailState {\n expanded: boolean;\n}\nconst RailContext = React.createContext<RailState | null>(null);\nconst useRail = () => {\n const ctx = React.useContext(RailContext);\n if (!ctx) throw new Error(\"RailNav parts must be inside <RailNav.Root>\");\n return ctx;\n};\n\n/** The frame of the page: the rail, then `RailNav.Body` (the header and the content). A row on a desktop. */\nexport function RailNavShell({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.shell({ className })} {...props} />;\n}\n\n/** The column beside the rail: the `AppHeader`, then the content. On a phone it keeps clear of the tab bar. */\nexport function RailNavBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type RailNavRootProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Orazaka`, `Studio`). */\n label: string;\n /** The product's mark on top of the rail, as a link home (`<Link href=\"/\"><ProductLogo id=\"orazaka\" /></Link>`); named by the app (its `aria-label`). Hidden on a phone: `AppHeader` shows it there. */\n mark?: React.ReactNode;\n /** The product's brand: scopes its colours (`brand-orazaka`…) over the rail, so the accent follows. Omit it inside a page that already wears the brand. */\n accent?: BrandId;\n /** The main destinations: `RailNav.Item`, the ones you work in. Five at most so that they fit a phone's tab bar. */\n children: React.ReactNode;\n /** At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. `RailNav.Item`s or a control with `data-rail-item`. */\n footer?: React.ReactNode;\n /** Adds a button that widens the rail to show the words (desktop only). Needs `expandLabels`. */\n expandable?: boolean;\n /** Controlled width (pair with `onExpandedChange` to keep the choice). */\n expanded?: boolean;\n /** The starting width when uncontrolled. */\n defaultExpanded?: boolean;\n /** Called when the toggle widens or narrows the rail. */\n onExpandedChange?: (expanded: boolean) => void;\n /** The toggle's words, `[expand, collapse]`. */\n expandLabels?: readonly [string, string];\n};\n\nconst count = (node: React.ReactNode) => React.Children.toArray(node).length;\n\n/** Moves the focus along the rail's items with the arrows (↑ ↓ on the rail, ← → on the tab bar; both always work), Home and End. */\nfunction moveFocus(event: React.KeyboardEvent<HTMLElement>) {\n const keys: Record<string, number> = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 };\n const step = keys[event.key];\n if (step === undefined && event.key !== \"Home\" && event.key !== \"End\") return;\n const items = [...event.currentTarget.querySelectorAll<HTMLElement>(\"[data-rail-item]\")];\n if (items.length === 0) return;\n const here = items.findIndex((el) => el === document.activeElement || el.contains(document.activeElement));\n let next: number;\n if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (here < 0) next = step > 0 ? 0 : items.length - 1;\n else next = (here + step + items.length) % items.length;\n event.preventDefault();\n items[next]?.focus();\n}\n\n/** The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone. */\nexport function RailNavRoot({\n label, mark, accent, children, footer, expandable, expanded: controlled, defaultExpanded = false, onExpandedChange, expandLabels, className, onKeyDown, ...props\n}: RailNavRootProps) {\n const [own, setOwn] = React.useState(defaultExpanded);\n const expanded = expandable ? (controlled ?? own) : false;\n const toggle = () => {\n if (controlled === undefined) setOwn(!expanded);\n onExpandedChange?.(!expanded);\n };\n const value = React.useMemo(() => ({ expanded }), [expanded]);\n return (\n <RailContext.Provider value={value}>\n <nav\n aria-label={label}\n data-expanded={expanded ? \"\" : undefined}\n className={cn(\"group/rail\", accent && \"brand-\" + accent, s.root({ className }))}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (!e.defaultPrevented) moveFocus(e);\n }}\n {...props}\n >\n {mark && (\n <div data-brand-mark className={s.mark()}>\n {mark}\n </div>\n )}\n <div className={s.group({ className: s.main() })} style={{ [\"--rail-n\" as string]: Math.max(count(children), 1) }}>\n {children}\n </div>\n {(footer || expandable) && (\n <div className={s.group({ className: s.foot() })} style={{ [\"--rail-n\" as string]: Math.max(count(footer), 1) }}>\n {footer}\n {expandable && expandLabels && (\n <button type=\"button\" data-rail-item className={s.toggle()} aria-expanded={expanded} onClick={toggle}>\n <ChevronGlyph direction={expanded ? \"left\" : \"right\"} className=\"h-4 w-4 shrink-0\" />\n <span className={expanded ? undefined : \"sr-only\"}>{expanded ? expandLabels[1] : expandLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </nav>\n </RailContext.Provider>\n );\n}\n\nexport type RailNavItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon of `@krizaka/icons`): all that shows on a desktop rail. */\n icon: React.ReactNode;\n /** Its words: the accessible name, the tooltip, the tab's caption on a phone, the row's text when the rail is expanded. */\n label: string;\n /** This is the section the user is in: `aria-current=\"page\"`, the accent bar and the accent colour. */\n current?: boolean;\n /** A count (unread, pending) on the icon. Say it in words with `badgeLabel`. */\n badge?: React.ReactNode;\n /** The count in words (« 3 unread »), appended to the accessible name. */\n badgeLabel?: string;\n /** Renders your router's link with the item's look: pass it as the only child. */\n asChild?: boolean;\n children?: React.ReactElement;\n};\n\n/** A destination of the rail. */\nexport function RailNavItem({ icon, label, current, badge, badgeLabel, asChild, children, className, ...props }: RailNavItemProps) {\n const { expanded } = useRail();\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n <span className={s.icon()}>\n {icon}\n {badge != null && (typeof badge === \"string\" || typeof badge === \"number\") ? (\n // Drawn by CSS, so the count is no text of the link: the visible text stays the label, which the name `Chat, 2 unread` contains.\n <span className={s.badge()} data-count={badge} aria-hidden />\n ) : (\n badge != null && <span className={s.badge()} aria-hidden>{badge}</span>\n )}\n </span>\n <span className={s.label()}>{label}</span>\n </>\n );\n const link = (\n <Comp data-rail-item aria-label={badgeLabel ? `${label}, ${badgeLabel}` : label} aria-current={current ? \"page\" : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n // Expanded, the words are on the row; collapsed, the tooltip says them (Escape dismisses it, the keyboard focus shows it).\n return expanded ? link : <Tooltip content={label} side=\"right\">{link}</Tooltip>;\n}\n\nexport const RailNav = {\n Shell: RailNavShell,\n Root: RailNavRoot,\n Item: RailNavItem,\n Body: RailNavBody,\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/tooltip/tooltip.tsx","../src/floating.ts","../src/rail-nav/rail-nav.tsx"],"sourcesContent":["// Client (a portal). A short label for a control, on hover after `delayDuration` and on keyboard focus at once;\n// Escape dismisses it. It names nothing: the control keeps its own accessible name (an IconButton's `label`).\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\n/** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\nexport type TooltipProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Content>, \"content\" | \"children\"> & {\n /** What the tooltip says — passed translated. */\n content: React.ReactNode;\n /** The trigger, rendered as is (`asChild`): a focusable element. */\n children: React.ReactNode;\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Hover delay in ms before it opens (300 by default). */\n delayDuration?: number;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function Tooltip({\n content,\n children,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration = 300,\n container,\n sideOffset = 6,\n collisionPadding = 8,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipPrimitive.Provider delayDuration={delayDuration}>\n <TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(floating, \"max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)\", className)}\n {...props}\n >\n {content}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\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 (the expand state, the arrow keys, the tooltip). The compact navigation of an application, read from Orazaka's\n// web client: a vertical rail of icons on a desktop — the product's mark on top, a tooltip on each icon, the current one\n// marked by an accent bar on its left edge, a footer for settings and the account — that becomes a bottom tab bar on a\n// phone. The same nodes in both: only the layout changes, so the items, their order and their words are written once.\n// The mark lives in the rail on a desktop; on a phone, where the rail has no room for it, `AppHeader` shows it (the rule\n// « one mark visible at every width »). Brand-aware through the tokens: `accent` scopes `.brand-<id>`.\nimport { Tooltip } from \"@krizaka/ui/tooltip\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph } from \"../glyphs\";\nimport type { BrandId } from \"../marks/ProductLogo\";\n\nexport const railNav = tv({\n slots: {\n shell: \"flex min-h-dvh w-full bg-surface-0 text-fg\",\n root:\n // Phone: a bottom tab bar, clear of the home indicator. Desktop: a sticky column that is only as wide as its icons.\n \"fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1 pb-[env(safe-area-inset-bottom)] \" +\n \"md:sticky md:overflow-x-clip md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 \" +\n \"md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56\",\n // The mark is the rail's on a desktop; hidden on a phone (the header carries it there).\n mark: \"hidden h-14 w-full shrink-0 items-center overflow-hidden justify-center md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-4\",\n group: \"flex min-w-0 flex-row items-stretch md:flex-col md:items-center md:gap-1 md:px-1.5 md:group-data-expanded/rail:items-stretch\",\n main: \"max-md:grow-(--rail-n) md:flex-1 md:py-2\",\n foot: \"max-md:grow-(--rail-n) md:border-t md:border-border-subtle md:py-2\",\n // The shortcuts: the product's quick ways in (a saved view, a client, « new invoice »), desktop only — a phone's tab bar\n // keeps its five destinations. Their heading shows once the rail is expanded; collapsed, it names the group.\n shortcuts: \"hidden md:flex md:border-t md:border-border-subtle md:py-2\",\n shortcutsHeading: \"sr-only md:group-data-expanded/rail:not-sr-only md:group-data-expanded/rail:px-3.5 md:group-data-expanded/rail:pb-1 md:group-data-expanded/rail:pt-1 text-[11px] font-semibold text-fg-secondary\",\n item:\n \"group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent \" +\n // The accent bar: on the top edge of a tab, on the left edge of a rail item.\n \"before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 \" +\n \"md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm \" +\n \"md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0\",\n icon: \"relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n label: \"max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only\",\n badge:\n \"absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-sm bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]\",\n toggle:\n \"hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5\",\n body: \"flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]\",\n },\n});\nconst s = railNav();\n\ninterface RailState {\n expanded: boolean;\n}\nconst RailContext = React.createContext<RailState | null>(null);\nconst useRail = () => {\n const ctx = React.useContext(RailContext);\n if (!ctx) throw new Error(\"RailNav parts must be inside <RailNav.Root>\");\n return ctx;\n};\n\n/** The frame of the page: the rail, then `RailNav.Body` (the header and the content). A row on a desktop. */\nexport function RailNavShell({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.shell({ className })} {...props} />;\n}\n\n/** The column beside the rail: the `AppHeader`, then the content. On a phone it keeps clear of the tab bar. */\nexport function RailNavBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type RailNavRootProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Orazaka`, `Studio`). */\n label: string;\n /** The product's mark on top of the rail, as a link home (`<Link href=\"/\"><ProductLogo id=\"orazaka\" /></Link>`); named by the app (its `aria-label`). Hidden on a phone: `AppHeader` shows it there. */\n mark?: React.ReactNode;\n /** The product's brand: scopes its colours (`brand-orazaka`…) over the rail, so the accent follows. Omit it inside a page that already wears the brand. */\n accent?: BrandId;\n /** The main destinations: `RailNav.Item`, the ones you work in. Five at most so that they fit a phone's tab bar. */\n children: React.ReactNode;\n /** At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. `RailNav.Item`s or a control with `data-rail-item`. */\n footer?: React.ReactNode;\n /** The product's shortcuts (`RailNav.Item`s: a saved view, a client, « New invoice »), a group above the footer and the expand toggle. Desktop only: a phone's tab bar keeps its destinations. */\n shortcuts?: React.ReactNode;\n /** The shortcuts' heading (« Raccourcis », « Shortcuts ») — passed translated: the group's name, shown once the rail is expanded. */\n shortcutsLabel?: string;\n /** Adds a button that widens the rail to show the words (desktop only). Needs `expandLabels`. */\n expandable?: boolean;\n /** Controlled width (pair with `onExpandedChange` to keep the choice). */\n expanded?: boolean;\n /** The starting width when uncontrolled. Unset: expanded from 1280 px (the words fit there), narrow below — until the person toggles it. */\n defaultExpanded?: boolean;\n /** Called when the toggle widens or narrows the rail. */\n onExpandedChange?: (expanded: boolean) => void;\n /** The toggle's words, `[expand, collapse]`. */\n expandLabels?: readonly [string, string];\n};\n\nconst count = (node: React.ReactNode) => React.Children.toArray(node).length;\n\n// The width from which an expandable rail shows its words by default — 80 rem (1280 px), Tailwind's `xl`.\nconst WIDE = \"(min-width: 80rem)\";\nconst subscribeWide = (onChange: () => void) => {\n if (typeof window === \"undefined\" || !window.matchMedia) return () => undefined;\n const query = window.matchMedia(WIDE);\n query.addEventListener(\"change\", onChange);\n return () => query.removeEventListener(\"change\", onChange);\n};\nconst isWide = () => typeof window !== \"undefined\" && Boolean(window.matchMedia?.(WIDE).matches);\n/** Whether the window is 1280 px wide or more; `false` on the server (the rail then widens before the first paint). */\nfunction useWide() {\n return React.useSyncExternalStore(subscribeWide, isWide, () => false);\n}\n\n/** Moves the focus along the rail's items with the arrows (↑ ↓ on the rail, ← → on the tab bar; both always work), Home and End. */\nfunction moveFocus(event: React.KeyboardEvent<HTMLElement>) {\n const keys: Record<string, number> = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 };\n const step = keys[event.key];\n if (step === undefined && event.key !== \"Home\" && event.key !== \"End\") return;\n const items = [...event.currentTarget.querySelectorAll<HTMLElement>(\"[data-rail-item]\")];\n if (items.length === 0) return;\n const here = items.findIndex((el) => el === document.activeElement || el.contains(document.activeElement));\n let next: number;\n if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (here < 0) next = step > 0 ? 0 : items.length - 1;\n else next = (here + step + items.length) % items.length;\n event.preventDefault();\n items[next]?.focus();\n}\n\n/** The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone. */\nexport function RailNavRoot({\n label, mark, accent, children, footer, shortcuts, shortcutsLabel, expandable, expanded: controlled, defaultExpanded, onExpandedChange, expandLabels, className, onKeyDown, ...props\n}: RailNavRootProps) {\n const [own, setOwn] = React.useState<boolean | undefined>(defaultExpanded);\n const wide = useWide();\n const headingId = React.useId();\n const expanded = expandable ? (controlled ?? own ?? wide) : false;\n const toggle = () => {\n if (controlled === undefined) setOwn(!expanded);\n onExpandedChange?.(!expanded);\n };\n const value = React.useMemo(() => ({ expanded }), [expanded]);\n return (\n <RailContext.Provider value={value}>\n <nav\n aria-label={label}\n data-expanded={expanded ? \"\" : undefined}\n className={cn(\"group/rail\", accent && \"brand-\" + accent, s.root({ className }))}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (!e.defaultPrevented) moveFocus(e);\n }}\n {...props}\n >\n {mark && (\n <div data-brand-mark className={s.mark()}>\n {mark}\n </div>\n )}\n <div className={s.group({ className: s.main() })} style={{ [\"--rail-n\" as string]: Math.max(count(children), 1) }}>\n {children}\n </div>\n {shortcuts && (\n <div role=\"group\" aria-labelledby={shortcutsLabel ? headingId : undefined} data-rail-shortcuts=\"\" className={s.group({ className: s.shortcuts() })}>\n {shortcutsLabel && (\n <p id={headingId} className={s.shortcutsHeading()}>\n {shortcutsLabel}\n </p>\n )}\n {shortcuts}\n </div>\n )}\n {(footer || expandable) && (\n <div className={s.group({ className: s.foot() })} style={{ [\"--rail-n\" as string]: Math.max(count(footer), 1) }}>\n {footer}\n {expandable && expandLabels && (\n <button type=\"button\" data-rail-item className={s.toggle()} aria-expanded={expanded} onClick={toggle}>\n <ChevronGlyph direction={expanded ? \"left\" : \"right\"} className=\"h-4 w-4 shrink-0\" />\n <span className={expanded ? undefined : \"sr-only\"}>{expanded ? expandLabels[1] : expandLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </nav>\n </RailContext.Provider>\n );\n}\n\nexport type RailNavItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon of `@krizaka/icons`): all that shows on a desktop rail. */\n icon: React.ReactNode;\n /** Its words: the accessible name, the tooltip, the tab's caption on a phone, the row's text when the rail is expanded. */\n label: string;\n /** This is the section the user is in: `aria-current=\"page\"`, the accent bar and the accent colour. */\n current?: boolean;\n /** A count (unread, pending) on the icon. Say it in words with `badgeLabel`. */\n badge?: React.ReactNode;\n /** The count in words (« 3 unread »), appended to the accessible name. */\n badgeLabel?: string;\n /** Renders your router's link with the item's look: pass it as the only child. */\n asChild?: boolean;\n children?: React.ReactElement;\n};\n\n/** A destination of the rail. */\nexport function RailNavItem({ icon, label, current, badge, badgeLabel, asChild, children, className, ...props }: RailNavItemProps) {\n const { expanded } = useRail();\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n <span className={s.icon()}>\n {icon}\n {badge != null && (typeof badge === \"string\" || typeof badge === \"number\") ? (\n // Drawn by CSS, so the count is no text of the link: the visible text stays the label, which the name `Chat, 2 unread` contains.\n <span className={s.badge()} data-count={badge} aria-hidden />\n ) : (\n badge != null && <span className={s.badge()} aria-hidden>{badge}</span>\n )}\n </span>\n <span className={s.label()}>{label}</span>\n </>\n );\n const link = (\n <Comp data-rail-item aria-label={badgeLabel ? `${label}, ${badgeLabel}` : label} aria-current={current ? \"page\" : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n // Expanded, the words are on the row; collapsed, the tooltip says them (Escape dismisses it, the keyboard focus shows it).\n return expanded ? link : <Tooltip content={label} side=\"right\">{link}</Tooltip>;\n}\n\nexport const RailNav = {\n Shell: RailNavShell,\n Root: RailNavRoot,\n Item: RailNavItem,\n Body: RailNavBody,\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { VideoPlayerProps } from './video-player.js';
|
|
3
|
+
import 'tailwind-variants';
|
|
4
|
+
|
|
5
|
+
/** A vertical video in a CSS-and-SVG television cabinet. */
|
|
6
|
+
interface RetroTvProps extends Omit<VideoPlayerProps, "aspectRatio" | "autoPlay" | "className" | "loop" | "muted" | "preload"> {
|
|
7
|
+
/** The cabinet style. */
|
|
8
|
+
variant?: "cabinet" | "portable";
|
|
9
|
+
/** A short channel label shown on the cabinet, for example `"CH 3 · Plateau"`. */
|
|
10
|
+
channel?: string;
|
|
11
|
+
/** Shows animated static instead of loading or playing the video. */
|
|
12
|
+
off?: boolean;
|
|
13
|
+
/** Starts muted and plays only while on screen; reduced motion waits for a gesture. Default `true`. */
|
|
14
|
+
autoPlay?: boolean;
|
|
15
|
+
/** Starts the player muted. Default `true`. */
|
|
16
|
+
muted?: boolean;
|
|
17
|
+
/** Plays the video again from the start when it ends. Default `true`. */
|
|
18
|
+
loop?: boolean;
|
|
19
|
+
/** How much to fetch before playback. Default `none` for lazy loading. */
|
|
20
|
+
preload?: VideoPlayerProps["preload"];
|
|
21
|
+
/** Additional classes on the television frame. */
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A vertical video presented in an old-school television; the existing player remains fully accessible.
|
|
26
|
+
* @deprecated Since 3.55 (ADR-006, krizaka-ui#674): no product uses it. Removed in 4.0.
|
|
27
|
+
*/
|
|
28
|
+
declare function RetroTv({ variant, channel, off, autoPlay, muted, loop, preload, className, ...playerProps }: RetroTvProps): React.JSX.Element;
|
|
29
|
+
|
|
30
|
+
export { RetroTv, type RetroTvProps };
|
package/dist/retro-tv.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
VideoPlayer
|
|
4
|
+
} from "./chunk-YCZ7N6Q6.js";
|
|
5
|
+
import "./chunk-ADRUEPYC.js";
|
|
6
|
+
import {
|
|
7
|
+
warnDeprecated
|
|
8
|
+
} from "./chunk-BDIU5LZB.js";
|
|
9
|
+
import "./chunk-HJFRHYCI.js";
|
|
10
|
+
import "./chunk-NSLXEDIS.js";
|
|
11
|
+
import {
|
|
12
|
+
useInView,
|
|
13
|
+
usePrefersReducedMotion
|
|
14
|
+
} from "./chunk-FZBWEDQI.js";
|
|
15
|
+
import "./chunk-CPA5CF35.js";
|
|
16
|
+
|
|
17
|
+
// src/retro-tv/retro-tv.tsx
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
var styles = `
|
|
21
|
+
.kz-rtv{position:relative;isolation:isolate;width:100%;aspect-ratio:4/5;max-width:100%;color:var(--kz-text-primary)}
|
|
22
|
+
.kz-rtv-cabinet{position:absolute;inset:0;overflow:hidden}
|
|
23
|
+
.kz-rtv-body{position:absolute;inset:4% 4% 16%;border:1px solid var(--kz-border-strong);border-radius:8% / 6%;background:linear-gradient(145deg,var(--kz-surface-sheen),transparent 35%),linear-gradient(145deg,color-mix(in srgb,var(--kz-warning) 18%,var(--kz-surface-3)),color-mix(in srgb,var(--kz-warning-text) 10%,var(--kz-surface-2)) 48%,var(--kz-surface-1));box-shadow:inset 0 1px 0 var(--kz-surface-sheen),inset 0 -3px 6px color-mix(in srgb,var(--kz-scrim-strong) 30%,transparent),0 1.2rem 2rem color-mix(in srgb,var(--kz-scrim-strong) 24%,transparent)}
|
|
24
|
+
.kz-rtv[data-variant=portable] .kz-rtv-body{border-radius:12% / 8%;background:linear-gradient(145deg,var(--kz-surface-1),var(--kz-surface-2) 55%,var(--kz-surface-3))}
|
|
25
|
+
.kz-rtv-body:after{position:absolute;inset:0;border-radius:inherit;background:repeating-linear-gradient(115deg,transparent 0 7px,color-mix(in srgb,var(--kz-border-subtle) 35%,transparent) 8px 9px);content:"";opacity:.4;pointer-events:none}
|
|
26
|
+
.kz-rtv-bezel{position:absolute;top:0;bottom:0;left:6%;width:61%;border:1px solid var(--kz-border-strong);border-radius:14% / 7%;background:linear-gradient(145deg,var(--kz-surface-1),var(--kz-surface-3));box-shadow:inset 0 2px 5px color-mix(in srgb,var(--kz-scrim-strong) 35%,transparent),0 1px 2px color-mix(in srgb,var(--kz-surface-sheen) 60%,transparent)}
|
|
27
|
+
.kz-rtv[data-variant=portable] .kz-rtv-bezel{border-radius:19% / 9%;background:linear-gradient(145deg,var(--kz-surface-0),var(--kz-surface-2))}
|
|
28
|
+
.kz-rtv-controls{position:absolute;top:16%;right:7%;display:flex;width:23%;flex-direction:column;align-items:center;gap:1.1rem}
|
|
29
|
+
.kz-rtv-knob{position:relative;display:block;width:2.3rem;max-width:70%;aspect-ratio:1;border:2px solid var(--kz-border-strong);border-radius:50%;background:radial-gradient(circle at 35% 28%,var(--kz-surface-sheen),transparent 30%),linear-gradient(145deg,var(--kz-surface-1),var(--kz-surface-3));box-shadow:inset 0 -2px 3px color-mix(in srgb,var(--kz-scrim-strong) 35%,transparent),0 2px 4px color-mix(in srgb,var(--kz-scrim-strong) 25%,transparent);color:var(--kz-accent)}
|
|
30
|
+
.kz-rtv-knob[data-hue=accent]{background:radial-gradient(circle at 35% 28%,var(--kz-surface-sheen),transparent 30%),linear-gradient(145deg,var(--kz-accent-text),var(--kz-accent))}
|
|
31
|
+
.kz-rtv-knob:after{position:absolute;top:14%;left:calc(50% - 1px);width:2px;height:27%;border-radius:2px;background:var(--kz-on-accent);content:""}
|
|
32
|
+
.kz-rtv[data-variant=portable] .kz-rtv-knob{width:1.9rem}
|
|
33
|
+
.kz-rtv-speaker{position:absolute;right:7%;bottom:9%;display:flex;width:23%;flex-direction:column;gap:3px}
|
|
34
|
+
.kz-rtv-speaker i{height:2px;border-radius:2px;background:var(--kz-border-strong);box-shadow:0 1px 0 var(--kz-surface-sheen)}
|
|
35
|
+
.kz-rtv[data-variant=portable] .kz-rtv-speaker{display:none}
|
|
36
|
+
.kz-rtv-stand{position:absolute;bottom:4%;left:36%;width:28%;height:12%;border-bottom:1px solid var(--kz-border-strong);border-radius:0 0 30% 30%;background:linear-gradient(180deg,var(--kz-surface-2),var(--kz-surface-3));clip-path:polygon(25% 0,75% 0,88% 78%,100% 100%,0 100%,12% 78%)}
|
|
37
|
+
.kz-rtv[data-variant=portable] .kz-rtv-stand{left:40%;width:20%;height:8%;border-radius:50%;clip-path:ellipse(50% 50% at 50% 50%)}
|
|
38
|
+
.kz-rtv-screen{position:absolute;top:4%;left:9.5%;width:56%;height:80%;overflow:hidden;border:2px solid color-mix(in srgb,var(--kz-border-strong) 72%,var(--kz-accent));border-radius:13% / 7%;background:var(--kz-scrim-strong);box-shadow:0 0 1.1rem color-mix(in srgb,var(--kz-accent) 30%,transparent),inset 0 0 1.2rem var(--kz-scrim-strong)}
|
|
39
|
+
.kz-rtv[data-variant=portable] .kz-rtv-screen{border-radius:18% / 9%}
|
|
40
|
+
.kz-rtv-screen .kz-rtv-player{height:100%;width:100%;border-radius:inherit}
|
|
41
|
+
.kz-rtv-player video,.kz-rtv-player img{object-fit:cover}
|
|
42
|
+
.kz-rtv-effects{position:absolute;z-index:5;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none}
|
|
43
|
+
.kz-rtv-effects:before{position:absolute;inset:0;background:repeating-linear-gradient(to bottom,transparent 0 3px,color-mix(in srgb,var(--kz-scrim-strong) 25%,transparent) 4px 5px);content:"";opacity:.46}
|
|
44
|
+
.kz-rtv-effects:after{position:absolute;inset:-1px;background:radial-gradient(ellipse at center,transparent 55%,var(--kz-scrim-strong) 100%);content:"";opacity:.52}
|
|
45
|
+
.kz-rtv-glow{position:absolute;inset:0;background:radial-gradient(ellipse at 50% 45%,color-mix(in srgb,var(--kz-accent) 14%,transparent),transparent 68%);opacity:.7}
|
|
46
|
+
.kz-rtv-noise{position:absolute;inset:0;height:100%;width:100%;opacity:.55;filter:contrast(1.3) brightness(.85)}
|
|
47
|
+
.kz-rtv-glass{position:absolute;inset:0;height:100%;width:100%;opacity:.28}
|
|
48
|
+
.kz-rtv-power{position:absolute;inset:0;background:var(--kz-text-on-media);opacity:0;transform:scaleY(.01);transform-origin:center;pointer-events:none}
|
|
49
|
+
.kz-rtv[data-powered=true] .kz-rtv-power{animation:kz-rtv-power .65s ease-out both}
|
|
50
|
+
.kz-rtv-channel{position:absolute;z-index:7;top:9%;right:5%;width:28%;overflow:hidden;color:var(--kz-text-primary);font:600 clamp(.42rem,1.2vw,.55rem)/1.2 var(--kz-font-mono,monospace);text-align:center;text-overflow:ellipsis;white-space:nowrap}
|
|
51
|
+
.kz-rtv[data-variant=portable] .kz-rtv-channel{top:7%}
|
|
52
|
+
.kz-rtv:focus-within .kz-rtv-screen{outline:2px solid var(--kz-ring);outline-offset:3px}
|
|
53
|
+
@keyframes kz-rtv-power{0%{opacity:1;transform:scaleY(.01)}45%{opacity:.9;transform:scaleY(1)}100%{opacity:0;transform:scaleY(1)}}
|
|
54
|
+
@keyframes kz-rtv-noise{0%,100%{opacity:.38}50%{opacity:.62}}
|
|
55
|
+
@media (prefers-reduced-motion:no-preference){.kz-rtv[data-off=true] .kz-rtv-noise{animation:kz-rtv-noise .18s steps(2,end) infinite}}
|
|
56
|
+
@media (prefers-reduced-motion:reduce){.kz-rtv-power{display:none!important}.kz-rtv-noise{animation:none!important}}
|
|
57
|
+
`;
|
|
58
|
+
function RetroTv({
|
|
59
|
+
variant = "cabinet",
|
|
60
|
+
channel,
|
|
61
|
+
off = false,
|
|
62
|
+
autoPlay = true,
|
|
63
|
+
muted = true,
|
|
64
|
+
loop = true,
|
|
65
|
+
preload = "none",
|
|
66
|
+
className,
|
|
67
|
+
...playerProps
|
|
68
|
+
}) {
|
|
69
|
+
warnDeprecated("retro-tv");
|
|
70
|
+
const root = React.useRef(null);
|
|
71
|
+
const [powered, setPowered] = React.useState(false);
|
|
72
|
+
const reducedMotion = usePrefersReducedMotion();
|
|
73
|
+
const uid = React.useId().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
74
|
+
const noiseId = `${uid}-noise`;
|
|
75
|
+
const glassId = `${uid}-glass`;
|
|
76
|
+
const shineId = `${uid}-shine`;
|
|
77
|
+
useInView(root, setPowered);
|
|
78
|
+
return /* @__PURE__ */ jsxs("div", { ref: root, className: ["kz-rtv", className].filter(Boolean).join(" "), "data-variant": variant, "data-powered": powered && !reducedMotion ? "true" : void 0, "data-off": off ? "true" : void 0, children: [
|
|
79
|
+
/* @__PURE__ */ jsx("style", { children: styles }),
|
|
80
|
+
/* @__PURE__ */ jsxs("div", { className: "kz-rtv-cabinet", "aria-hidden": "true", children: [
|
|
81
|
+
/* @__PURE__ */ jsxs("div", { className: "kz-rtv-body", children: [
|
|
82
|
+
/* @__PURE__ */ jsx("div", { className: "kz-rtv-bezel" }),
|
|
83
|
+
/* @__PURE__ */ jsxs("div", { className: "kz-rtv-controls", children: [
|
|
84
|
+
/* @__PURE__ */ jsx("span", { className: "kz-rtv-knob", "data-hue": "accent" }),
|
|
85
|
+
/* @__PURE__ */ jsx("span", { className: "kz-rtv-knob", "data-hue": "accent" })
|
|
86
|
+
] }),
|
|
87
|
+
/* @__PURE__ */ jsx("div", { className: "kz-rtv-speaker", children: Array.from({ length: 7 }, (_, index) => /* @__PURE__ */ jsx("i", {}, index)) })
|
|
88
|
+
] }),
|
|
89
|
+
/* @__PURE__ */ jsx("div", { className: "kz-rtv-stand" })
|
|
90
|
+
] }),
|
|
91
|
+
channel && /* @__PURE__ */ jsx("span", { className: "kz-rtv-channel", children: channel }),
|
|
92
|
+
/* @__PURE__ */ jsxs("div", { className: "kz-rtv-screen", children: [
|
|
93
|
+
off ? /* @__PURE__ */ jsxs("svg", { className: "kz-rtv-noise", viewBox: "0 0 100 100", preserveAspectRatio: "none", "aria-hidden": "true", children: [
|
|
94
|
+
/* @__PURE__ */ jsxs("filter", { id: noiseId, children: [
|
|
95
|
+
/* @__PURE__ */ jsx("feTurbulence", { type: "fractalNoise", baseFrequency: ".85", numOctaves: "2", stitchTiles: "stitch" }),
|
|
96
|
+
/* @__PURE__ */ jsx("feColorMatrix", { type: "saturate", values: "0" })
|
|
97
|
+
] }),
|
|
98
|
+
/* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", filter: `url(#${noiseId})` })
|
|
99
|
+
] }) : /* @__PURE__ */ jsx(VideoPlayer, { ...playerProps, className: "kz-rtv-player", aspectRatio: "9 / 16", autoPlay, muted, loop, preload }),
|
|
100
|
+
/* @__PURE__ */ jsxs("div", { className: "kz-rtv-effects", "aria-hidden": "true", children: [
|
|
101
|
+
/* @__PURE__ */ jsxs("svg", { className: "kz-rtv-glass", viewBox: "0 0 100 100", preserveAspectRatio: "none", children: [
|
|
102
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
103
|
+
/* @__PURE__ */ jsxs("radialGradient", { id: shineId, cx: "50%", cy: "42%", r: "68%", children: [
|
|
104
|
+
/* @__PURE__ */ jsx("stop", { offset: "0", stopColor: "var(--kz-surface-sheen)", stopOpacity: ".12" }),
|
|
105
|
+
/* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "var(--kz-scrim-strong)", stopOpacity: ".2" })
|
|
106
|
+
] }),
|
|
107
|
+
/* @__PURE__ */ jsxs("filter", { id: glassId, children: [
|
|
108
|
+
/* @__PURE__ */ jsx("feTurbulence", { baseFrequency: ".01 .04", numOctaves: "1", seed: "2", result: "curve" }),
|
|
109
|
+
/* @__PURE__ */ jsx("feDisplacementMap", { in: "SourceGraphic", in2: "curve", scale: "1.2", xChannelSelector: "R", yChannelSelector: "G" })
|
|
110
|
+
] })
|
|
111
|
+
] }),
|
|
112
|
+
/* @__PURE__ */ jsx("rect", { width: "100", height: "100", fill: `url(#${shineId})`, filter: `url(#${glassId})` })
|
|
113
|
+
] }),
|
|
114
|
+
/* @__PURE__ */ jsx("span", { className: "kz-rtv-glow" }),
|
|
115
|
+
/* @__PURE__ */ jsx("span", { className: "kz-rtv-power" })
|
|
116
|
+
] })
|
|
117
|
+
] }),
|
|
118
|
+
off && /* @__PURE__ */ jsx("span", { className: "sr-only", children: playerProps.title })
|
|
119
|
+
] });
|
|
120
|
+
}
|
|
121
|
+
export {
|
|
122
|
+
RetroTv
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=retro-tv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/retro-tv/retro-tv.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nimport { warnDeprecated } from \"../deprecated\";\nimport { useInView, usePrefersReducedMotion } from \"../media\";\nimport { VideoPlayer, type VideoPlayerProps } from \"../video-player/video-player\";\n\nconst styles = `\n.kz-rtv{position:relative;isolation:isolate;width:100%;aspect-ratio:4/5;max-width:100%;color:var(--kz-text-primary)}\n.kz-rtv-cabinet{position:absolute;inset:0;overflow:hidden}\n.kz-rtv-body{position:absolute;inset:4% 4% 16%;border:1px solid var(--kz-border-strong);border-radius:8% / 6%;background:linear-gradient(145deg,var(--kz-surface-sheen),transparent 35%),linear-gradient(145deg,color-mix(in srgb,var(--kz-warning) 18%,var(--kz-surface-3)),color-mix(in srgb,var(--kz-warning-text) 10%,var(--kz-surface-2)) 48%,var(--kz-surface-1));box-shadow:inset 0 1px 0 var(--kz-surface-sheen),inset 0 -3px 6px color-mix(in srgb,var(--kz-scrim-strong) 30%,transparent),0 1.2rem 2rem color-mix(in srgb,var(--kz-scrim-strong) 24%,transparent)}\n.kz-rtv[data-variant=portable] .kz-rtv-body{border-radius:12% / 8%;background:linear-gradient(145deg,var(--kz-surface-1),var(--kz-surface-2) 55%,var(--kz-surface-3))}\n.kz-rtv-body:after{position:absolute;inset:0;border-radius:inherit;background:repeating-linear-gradient(115deg,transparent 0 7px,color-mix(in srgb,var(--kz-border-subtle) 35%,transparent) 8px 9px);content:\"\";opacity:.4;pointer-events:none}\n.kz-rtv-bezel{position:absolute;top:0;bottom:0;left:6%;width:61%;border:1px solid var(--kz-border-strong);border-radius:14% / 7%;background:linear-gradient(145deg,var(--kz-surface-1),var(--kz-surface-3));box-shadow:inset 0 2px 5px color-mix(in srgb,var(--kz-scrim-strong) 35%,transparent),0 1px 2px color-mix(in srgb,var(--kz-surface-sheen) 60%,transparent)}\n.kz-rtv[data-variant=portable] .kz-rtv-bezel{border-radius:19% / 9%;background:linear-gradient(145deg,var(--kz-surface-0),var(--kz-surface-2))}\n.kz-rtv-controls{position:absolute;top:16%;right:7%;display:flex;width:23%;flex-direction:column;align-items:center;gap:1.1rem}\n.kz-rtv-knob{position:relative;display:block;width:2.3rem;max-width:70%;aspect-ratio:1;border:2px solid var(--kz-border-strong);border-radius:50%;background:radial-gradient(circle at 35% 28%,var(--kz-surface-sheen),transparent 30%),linear-gradient(145deg,var(--kz-surface-1),var(--kz-surface-3));box-shadow:inset 0 -2px 3px color-mix(in srgb,var(--kz-scrim-strong) 35%,transparent),0 2px 4px color-mix(in srgb,var(--kz-scrim-strong) 25%,transparent);color:var(--kz-accent)}\n.kz-rtv-knob[data-hue=accent]{background:radial-gradient(circle at 35% 28%,var(--kz-surface-sheen),transparent 30%),linear-gradient(145deg,var(--kz-accent-text),var(--kz-accent))}\n.kz-rtv-knob:after{position:absolute;top:14%;left:calc(50% - 1px);width:2px;height:27%;border-radius:2px;background:var(--kz-on-accent);content:\"\"}\n.kz-rtv[data-variant=portable] .kz-rtv-knob{width:1.9rem}\n.kz-rtv-speaker{position:absolute;right:7%;bottom:9%;display:flex;width:23%;flex-direction:column;gap:3px}\n.kz-rtv-speaker i{height:2px;border-radius:2px;background:var(--kz-border-strong);box-shadow:0 1px 0 var(--kz-surface-sheen)}\n.kz-rtv[data-variant=portable] .kz-rtv-speaker{display:none}\n.kz-rtv-stand{position:absolute;bottom:4%;left:36%;width:28%;height:12%;border-bottom:1px solid var(--kz-border-strong);border-radius:0 0 30% 30%;background:linear-gradient(180deg,var(--kz-surface-2),var(--kz-surface-3));clip-path:polygon(25% 0,75% 0,88% 78%,100% 100%,0 100%,12% 78%)}\n.kz-rtv[data-variant=portable] .kz-rtv-stand{left:40%;width:20%;height:8%;border-radius:50%;clip-path:ellipse(50% 50% at 50% 50%)}\n.kz-rtv-screen{position:absolute;top:4%;left:9.5%;width:56%;height:80%;overflow:hidden;border:2px solid color-mix(in srgb,var(--kz-border-strong) 72%,var(--kz-accent));border-radius:13% / 7%;background:var(--kz-scrim-strong);box-shadow:0 0 1.1rem color-mix(in srgb,var(--kz-accent) 30%,transparent),inset 0 0 1.2rem var(--kz-scrim-strong)}\n.kz-rtv[data-variant=portable] .kz-rtv-screen{border-radius:18% / 9%}\n.kz-rtv-screen .kz-rtv-player{height:100%;width:100%;border-radius:inherit}\n.kz-rtv-player video,.kz-rtv-player img{object-fit:cover}\n.kz-rtv-effects{position:absolute;z-index:5;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none}\n.kz-rtv-effects:before{position:absolute;inset:0;background:repeating-linear-gradient(to bottom,transparent 0 3px,color-mix(in srgb,var(--kz-scrim-strong) 25%,transparent) 4px 5px);content:\"\";opacity:.46}\n.kz-rtv-effects:after{position:absolute;inset:-1px;background:radial-gradient(ellipse at center,transparent 55%,var(--kz-scrim-strong) 100%);content:\"\";opacity:.52}\n.kz-rtv-glow{position:absolute;inset:0;background:radial-gradient(ellipse at 50% 45%,color-mix(in srgb,var(--kz-accent) 14%,transparent),transparent 68%);opacity:.7}\n.kz-rtv-noise{position:absolute;inset:0;height:100%;width:100%;opacity:.55;filter:contrast(1.3) brightness(.85)}\n.kz-rtv-glass{position:absolute;inset:0;height:100%;width:100%;opacity:.28}\n.kz-rtv-power{position:absolute;inset:0;background:var(--kz-text-on-media);opacity:0;transform:scaleY(.01);transform-origin:center;pointer-events:none}\n.kz-rtv[data-powered=true] .kz-rtv-power{animation:kz-rtv-power .65s ease-out both}\n.kz-rtv-channel{position:absolute;z-index:7;top:9%;right:5%;width:28%;overflow:hidden;color:var(--kz-text-primary);font:600 clamp(.42rem,1.2vw,.55rem)/1.2 var(--kz-font-mono,monospace);text-align:center;text-overflow:ellipsis;white-space:nowrap}\n.kz-rtv[data-variant=portable] .kz-rtv-channel{top:7%}\n.kz-rtv:focus-within .kz-rtv-screen{outline:2px solid var(--kz-ring);outline-offset:3px}\n@keyframes kz-rtv-power{0%{opacity:1;transform:scaleY(.01)}45%{opacity:.9;transform:scaleY(1)}100%{opacity:0;transform:scaleY(1)}}\n@keyframes kz-rtv-noise{0%,100%{opacity:.38}50%{opacity:.62}}\n@media (prefers-reduced-motion:no-preference){.kz-rtv[data-off=true] .kz-rtv-noise{animation:kz-rtv-noise .18s steps(2,end) infinite}}\n@media (prefers-reduced-motion:reduce){.kz-rtv-power{display:none!important}.kz-rtv-noise{animation:none!important}}\n`;\n\n/** A vertical video in a CSS-and-SVG television cabinet. */\nexport interface RetroTvProps extends Omit<VideoPlayerProps, \"aspectRatio\" | \"autoPlay\" | \"className\" | \"loop\" | \"muted\" | \"preload\"> {\n /** The cabinet style. */\n variant?: \"cabinet\" | \"portable\";\n /** A short channel label shown on the cabinet, for example `\"CH 3 · Plateau\"`. */\n channel?: string;\n /** Shows animated static instead of loading or playing the video. */\n off?: boolean;\n /** Starts muted and plays only while on screen; reduced motion waits for a gesture. Default `true`. */\n autoPlay?: boolean;\n /** Starts the player muted. Default `true`. */\n muted?: boolean;\n /** Plays the video again from the start when it ends. Default `true`. */\n loop?: boolean;\n /** How much to fetch before playback. Default `none` for lazy loading. */\n preload?: VideoPlayerProps[\"preload\"];\n /** Additional classes on the television frame. */\n className?: string;\n}\n\n/**\n * A vertical video presented in an old-school television; the existing player remains fully accessible.\n * @deprecated Since 3.55 (ADR-006, krizaka-ui#674): no product uses it. Removed in 4.0.\n */\nexport function RetroTv({\n variant = \"cabinet\",\n channel,\n off = false,\n autoPlay = true,\n muted = true,\n loop = true,\n preload = \"none\",\n className,\n ...playerProps\n}: RetroTvProps) {\n warnDeprecated(\"retro-tv\");\n const root = React.useRef<HTMLDivElement>(null);\n const [powered, setPowered] = React.useState(false);\n const reducedMotion = usePrefersReducedMotion();\n const uid = React.useId().replace(/[^a-zA-Z0-9_-]/g, \"\");\n const noiseId = `${uid}-noise`;\n const glassId = `${uid}-glass`;\n const shineId = `${uid}-shine`;\n\n useInView(root, setPowered);\n\n return (\n <div ref={root} className={[\"kz-rtv\", className].filter(Boolean).join(\" \")} data-variant={variant} data-powered={powered && !reducedMotion ? \"true\" : undefined} data-off={off ? \"true\" : undefined}>\n <style>{styles}</style>\n <div className=\"kz-rtv-cabinet\" aria-hidden=\"true\">\n <div className=\"kz-rtv-body\">\n <div className=\"kz-rtv-bezel\" />\n <div className=\"kz-rtv-controls\">\n <span className=\"kz-rtv-knob\" data-hue=\"accent\" />\n <span className=\"kz-rtv-knob\" data-hue=\"accent\" />\n </div>\n <div className=\"kz-rtv-speaker\">{Array.from({ length: 7 }, (_, index) => <i key={index} />)}</div>\n </div>\n <div className=\"kz-rtv-stand\" />\n </div>\n {channel && <span className=\"kz-rtv-channel\">{channel}</span>}\n <div className=\"kz-rtv-screen\">\n {off ? (\n <svg className=\"kz-rtv-noise\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\n <filter id={noiseId}><feTurbulence type=\"fractalNoise\" baseFrequency=\".85\" numOctaves=\"2\" stitchTiles=\"stitch\" /><feColorMatrix type=\"saturate\" values=\"0\" /></filter>\n <rect width=\"100%\" height=\"100%\" filter={`url(#${noiseId})`} />\n </svg>\n ) : (\n <VideoPlayer {...playerProps} className=\"kz-rtv-player\" aspectRatio=\"9 / 16\" autoPlay={autoPlay} muted={muted} loop={loop} preload={preload} />\n )}\n <div className=\"kz-rtv-effects\" aria-hidden=\"true\">\n <svg className=\"kz-rtv-glass\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\">\n <defs>\n <radialGradient id={shineId} cx=\"50%\" cy=\"42%\" r=\"68%\">\n <stop offset=\"0\" stopColor=\"var(--kz-surface-sheen)\" stopOpacity=\".12\" />\n <stop offset=\"1\" stopColor=\"var(--kz-scrim-strong)\" stopOpacity=\".2\" />\n </radialGradient>\n <filter id={glassId}>\n <feTurbulence baseFrequency=\".01 .04\" numOctaves=\"1\" seed=\"2\" result=\"curve\" />\n <feDisplacementMap in=\"SourceGraphic\" in2=\"curve\" scale=\"1.2\" xChannelSelector=\"R\" yChannelSelector=\"G\" />\n </filter>\n </defs>\n <rect width=\"100\" height=\"100\" fill={`url(#${shineId})`} filter={`url(#${glassId})`} />\n </svg>\n <span className=\"kz-rtv-glow\" />\n <span className=\"kz-rtv-power\" />\n </div>\n </div>\n {off && <span className=\"sr-only\">{playerProps.title}</span>}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/router.d.ts
CHANGED
|
@@ -39,6 +39,17 @@ declare function writeRouteValue(search: string, key: string, value: string, fal
|
|
|
39
39
|
* `key` undefined makes the hook inert (it returns the default) so a component can call it unconditionally.
|
|
40
40
|
*/
|
|
41
41
|
declare function useRouteState<V extends string>(key: string | undefined, { values, default: fallback, history }: RouteStateOptions<V>): readonly [V, (next: V) => void];
|
|
42
|
+
/**
|
|
43
|
+
* The query string and a way to change several parameters in one navigation (a sort and the page it resets). Writes made
|
|
44
|
+
* in the same tick build on each other — across every hook of the same router — so a router that applies them later never
|
|
45
|
+
* loses one.
|
|
46
|
+
*/
|
|
47
|
+
declare function useRouteSearch(): {
|
|
48
|
+
search: string;
|
|
49
|
+
write: (update: (search: string) => string, options?: {
|
|
50
|
+
replace?: boolean;
|
|
51
|
+
}) => void;
|
|
52
|
+
};
|
|
42
53
|
/** What a selection component spreads on its root: `value` and `onValueChange` bound to the URL when `routeKey` is set. */
|
|
43
54
|
interface RouteBindable {
|
|
44
55
|
value?: string | null;
|
|
@@ -48,4 +59,4 @@ interface RouteBindable {
|
|
|
48
59
|
/** The props of a selection component bound to the URL (`routeKey`), or its own, unchanged, when there is no `routeKey`. */
|
|
49
60
|
declare function useRouteBinding<P extends RouteBindable>(routeKey: string | undefined, routeValues: readonly string[] | undefined, props: P): P;
|
|
50
61
|
|
|
51
|
-
export { type RouteAdapter, type RouteBindable, type RouteStateOptions, RouteStateProvider, type RouteStateProviderProps, browserAdapter, readRouteValue, useRouteBinding, useRouteState, writeRouteValue };
|
|
62
|
+
export { type RouteAdapter, type RouteBindable, type RouteStateOptions, RouteStateProvider, type RouteStateProviderProps, browserAdapter, readRouteValue, useRouteBinding, useRouteSearch, useRouteState, writeRouteValue };
|