@krizaka/ui 2.2.0 → 2.4.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 +33 -8
- package/dist/audio-player.d.ts +113 -0
- package/dist/audio-player.js +207 -0
- package/dist/audio-player.js.map +1 -0
- package/dist/{button-Cgfkg_3y.d.ts → button-BMAO7dKF.d.ts} +29 -2
- package/dist/button.d.ts +32 -5
- package/dist/button.js +62 -9
- package/dist/button.js.map +1 -1
- package/dist/chip-link.d.ts +53 -0
- package/dist/chip-link.js +32 -0
- package/dist/chip-link.js.map +1 -0
- package/dist/chunk-2USC2YT6.js +17 -0
- package/dist/chunk-2USC2YT6.js.map +1 -0
- package/dist/chunk-43PTCDTL.js +31 -0
- package/dist/chunk-43PTCDTL.js.map +1 -0
- package/dist/chunk-6ISW63JI.js +11 -0
- package/dist/chunk-6ISW63JI.js.map +1 -0
- package/dist/chunk-EUPTXKH7.js +95 -0
- package/dist/chunk-EUPTXKH7.js.map +1 -0
- package/dist/chunk-HAQWKORZ.js +117 -0
- package/dist/chunk-HAQWKORZ.js.map +1 -0
- package/dist/{chunk-FHYZSO2S.js → chunk-R6SDS7JM.js} +5 -3
- package/dist/chunk-R6SDS7JM.js.map +1 -0
- package/dist/chunk-RUPNPMP3.js +103 -0
- package/dist/chunk-RUPNPMP3.js.map +1 -0
- package/dist/chunk-RUPRYJ45.js +82 -0
- package/dist/chunk-RUPRYJ45.js.map +1 -0
- package/dist/chunk-VDR2EP6K.js +49 -0
- package/dist/chunk-VDR2EP6K.js.map +1 -0
- package/dist/chunk-WEVYKZIF.js +33 -0
- package/dist/chunk-WEVYKZIF.js.map +1 -0
- package/dist/chunk-XUMJA5ZI.js +283 -0
- package/dist/chunk-XUMJA5ZI.js.map +1 -0
- package/dist/chunk-YH4LMWRU.js +92 -0
- package/dist/chunk-YH4LMWRU.js.map +1 -0
- package/dist/chunk-YX6CNVJA.js +94 -0
- package/dist/chunk-YX6CNVJA.js.map +1 -0
- package/dist/chunk-ZIXB33X7.js +95 -0
- package/dist/chunk-ZIXB33X7.js.map +1 -0
- package/dist/combobox.d.ts +188 -0
- package/dist/combobox.js +16 -0
- package/dist/combobox.js.map +1 -0
- package/dist/command.d.ts +7 -7
- package/dist/command.js +3 -2
- package/dist/command.js.map +1 -1
- package/dist/confirm-button.d.ts +1 -1
- package/dist/confirm-button.js +2 -1
- package/dist/confirm-button.js.map +1 -1
- package/dist/data-table.d.ts +246 -0
- package/dist/data-table.js +290 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-picker.d.ts +288 -0
- package/dist/date-picker.js +364 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/{dialog-GQ4Nvuyf.d.ts → dialog-D42QwYb_.d.ts} +11 -1
- package/dist/dialog.d.ts +1 -1
- package/dist/dialog.js +3 -2
- package/dist/dialog.js.map +1 -1
- package/dist/file-upload.d.ts +238 -0
- package/dist/file-upload.js +437 -0
- package/dist/file-upload.js.map +1 -0
- package/dist/filter-bar.d.ts +139 -0
- package/dist/filter-bar.js +155 -0
- package/dist/filter-bar.js.map +1 -0
- package/dist/glow-card.d.ts +20 -0
- package/dist/glow-card.js +30 -0
- package/dist/glow-card.js.map +1 -0
- package/dist/image-cropper.d.ts +115 -0
- package/dist/image-cropper.js +166 -0
- package/dist/image-cropper.js.map +1 -0
- package/dist/index.d.ts +2 -20
- package/dist/index.js +7 -64
- package/dist/index.js.map +1 -1
- package/dist/iso.d.ts +400 -0
- package/dist/iso.js +363 -0
- package/dist/iso.js.map +1 -0
- package/dist/loader.d.ts +206 -0
- package/dist/loader.js +138 -0
- package/dist/loader.js.map +1 -0
- package/dist/marquee.d.ts +33 -0
- package/dist/marquee.js +52 -0
- package/dist/marquee.js.map +1 -0
- package/dist/media-capture.d.ts +155 -0
- package/dist/media-capture.js +242 -0
- package/dist/media-capture.js.map +1 -0
- package/dist/meter.d.ts +146 -0
- package/dist/meter.js +107 -0
- package/dist/meter.js.map +1 -0
- package/dist/motion.css +394 -3
- package/dist/motion.d.ts +46 -0
- package/dist/motion.js +10 -0
- package/dist/motion.js.map +1 -0
- package/dist/native/media-capture.d.ts +49 -0
- package/dist/native/media-capture.js +113 -0
- package/dist/native/media-capture.js.map +1 -0
- package/dist/native/video-player.d.ts +50 -0
- package/dist/native/video-player.js +69 -0
- package/dist/native/video-player.js.map +1 -0
- package/dist/native.d.ts +66 -2
- package/dist/native.js +166 -68
- package/dist/native.js.map +1 -1
- package/dist/nav-bar.d.ts +178 -0
- package/dist/nav-bar.js +157 -0
- package/dist/nav-bar.js.map +1 -0
- package/dist/number-ticker.d.ts +32 -0
- package/dist/number-ticker.js +61 -0
- package/dist/number-ticker.js.map +1 -0
- package/dist/pagination.d.ts +141 -0
- package/dist/pagination.js +165 -0
- package/dist/pagination.js.map +1 -0
- package/dist/progress.d.ts +56 -1
- package/dist/progress.js +72 -25
- package/dist/progress.js.map +1 -1
- package/dist/search-field.d.ts +100 -0
- package/dist/search-field.js +167 -0
- package/dist/search-field.js.map +1 -0
- package/dist/skeleton.d.ts +18 -3
- package/dist/skeleton.js +9 -1
- package/dist/skeleton.js.map +1 -1
- package/dist/spinner.d.ts +21 -5
- package/dist/spinner.js +13 -12
- package/dist/spinner.js.map +1 -1
- package/dist/stepper.d.ts +112 -0
- package/dist/stepper.js +67 -0
- package/dist/stepper.js.map +1 -0
- package/dist/tabs.d.ts +1 -1
- package/dist/tabs.js +14 -8
- package/dist/tabs.js.map +1 -1
- package/dist/tag-input.d.ts +44 -0
- package/dist/tag-input.js +67 -0
- package/dist/tag-input.js.map +1 -0
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +2 -1
- package/dist/theme.js.map +1 -1
- package/dist/toast.d.ts +39 -4
- package/dist/toast.js +81 -7
- package/dist/toast.js.map +1 -1
- package/dist/video-player.d.ts +204 -0
- package/dist/video-player.js +371 -0
- package/dist/video-player.js.map +1 -0
- package/dist/video-trimmer.d.ts +142 -0
- package/dist/video-trimmer.js +193 -0
- package/dist/video-trimmer.js.map +1 -0
- package/package.json +375 -7
- package/registry/alert.json +1 -1
- package/registry/audio-player.json +282 -0
- package/registry/avatar.json +1 -1
- package/registry/badge.json +1 -1
- package/registry/button.json +232 -26
- package/registry/card.json +1 -1
- package/registry/checkbox.json +1 -1
- package/registry/chip-link.json +158 -0
- package/registry/chip.json +1 -1
- package/registry/combobox.json +475 -0
- package/registry/command.json +1 -1
- package/registry/confirm-button.json +91 -7
- package/registry/countdown.json +1 -1
- package/registry/data-table.json +500 -0
- package/registry/date-picker.json +978 -0
- package/registry/dialog.json +15 -7
- package/registry/dropdown-menu.json +1 -1
- package/registry/empty-state.json +1 -1
- package/registry/examples/audio-player/podcast.js +22 -0
- package/registry/examples/audio-player/podcast.tsx +19 -0
- package/registry/examples/audio-player/voice-note.d.ts +4 -0
- package/registry/examples/audio-player/voice-note.js +12 -0
- package/registry/examples/audio-player/voice-note.tsx +12 -0
- package/registry/examples/button/error.d.ts +4 -0
- package/registry/examples/button/error.js +11 -0
- package/registry/examples/button/error.tsx +10 -0
- package/registry/examples/button/loading.tsx +1 -1
- package/registry/examples/button/save-flow.d.ts +4 -0
- package/registry/examples/button/save-flow.js +28 -0
- package/registry/examples/button/save-flow.tsx +24 -0
- package/registry/examples/button/signature.d.ts +4 -0
- package/registry/examples/button/signature.js +17 -0
- package/registry/examples/button/signature.tsx +19 -0
- package/registry/examples/button/upload-progress.d.ts +4 -0
- package/registry/examples/button/upload-progress.js +23 -0
- package/registry/examples/button/upload-progress.tsx +26 -0
- package/registry/examples/chip-link/filters.d.ts +4 -0
- package/registry/examples/chip-link/filters.js +12 -0
- package/registry/examples/chip-link/filters.tsx +17 -0
- package/registry/examples/combobox/async.d.ts +4 -0
- package/registry/examples/combobox/async.js +23 -0
- package/registry/examples/combobox/async.tsx +22 -0
- package/registry/examples/combobox/creatable.d.ts +4 -0
- package/registry/examples/combobox/creatable.js +32 -0
- package/registry/examples/combobox/creatable.tsx +28 -0
- package/registry/examples/combobox/invalid.d.ts +4 -0
- package/registry/examples/combobox/invalid.js +23 -0
- package/registry/examples/combobox/invalid.tsx +17 -0
- package/registry/examples/combobox/multiple.d.ts +4 -0
- package/registry/examples/combobox/multiple.js +29 -0
- package/registry/examples/combobox/multiple.tsx +26 -0
- package/registry/examples/data-table/cards.d.ts +4 -0
- package/registry/examples/data-table/cards.js +21 -0
- package/registry/examples/data-table/cards.tsx +20 -0
- package/registry/examples/data-table/empty.d.ts +4 -0
- package/registry/examples/data-table/empty.js +26 -0
- package/registry/examples/data-table/empty.tsx +21 -0
- package/registry/examples/data-table/error.d.ts +4 -0
- package/registry/examples/data-table/error.js +28 -0
- package/registry/examples/data-table/error.tsx +29 -0
- package/registry/examples/data-table/jobs.d.ts +4 -0
- package/registry/examples/data-table/jobs.js +37 -0
- package/registry/examples/data-table/jobs.tsx +36 -0
- package/registry/examples/data-table/loading.d.ts +4 -0
- package/registry/examples/data-table/loading.js +16 -0
- package/registry/examples/data-table/loading.tsx +12 -0
- package/registry/examples/data-table/virtualized.d.ts +4 -0
- package/registry/examples/data-table/virtualized.js +21 -0
- package/registry/examples/data-table/virtualized.tsx +20 -0
- package/registry/examples/date-picker/calendar.d.ts +4 -0
- package/registry/examples/date-picker/calendar.js +14 -0
- package/registry/examples/date-picker/calendar.tsx +16 -0
- package/registry/examples/date-picker/french.d.ts +4 -0
- package/registry/examples/date-picker/french.js +20 -0
- package/registry/examples/date-picker/french.tsx +14 -0
- package/registry/examples/date-picker/open.d.ts +4 -0
- package/registry/examples/date-picker/open.js +11 -0
- package/registry/examples/date-picker/open.tsx +8 -0
- package/registry/examples/date-picker/range.d.ts +4 -0
- package/registry/examples/date-picker/range.js +29 -0
- package/registry/examples/date-picker/range.tsx +25 -0
- package/registry/examples/date-picker/schedule.d.ts +4 -0
- package/registry/examples/date-picker/schedule.js +26 -0
- package/registry/examples/date-picker/schedule.tsx +22 -0
- package/registry/examples/dialog/left.d.ts +4 -0
- package/registry/examples/dialog/left.js +22 -0
- package/registry/examples/dialog/left.tsx +32 -0
- package/registry/examples/file-upload/images.d.ts +4 -0
- package/registry/examples/file-upload/images.js +32 -0
- package/registry/examples/file-upload/images.tsx +25 -0
- package/registry/examples/file-upload/states.d.ts +4 -0
- package/registry/examples/file-upload/states.js +28 -0
- package/registry/examples/file-upload/states.tsx +23 -0
- package/registry/examples/file-upload/tus.d.ts +4 -0
- package/registry/examples/file-upload/tus.js +23 -0
- package/registry/examples/file-upload/tus.tsx +26 -0
- package/registry/examples/file-upload/video.d.ts +4 -0
- package/registry/examples/file-upload/video.js +39 -0
- package/registry/examples/file-upload/video.tsx +36 -0
- package/registry/examples/filter-bar/address.d.ts +4 -0
- package/registry/examples/filter-bar/address.js +29 -0
- package/registry/examples/filter-bar/address.tsx +27 -0
- package/registry/examples/filter-bar/jobs.d.ts +4 -0
- package/registry/examples/filter-bar/jobs.js +37 -0
- package/registry/examples/filter-bar/jobs.tsx +37 -0
- package/registry/examples/filter-bar/menu.d.ts +4 -0
- package/registry/examples/filter-bar/menu.js +27 -0
- package/registry/examples/filter-bar/menu.tsx +23 -0
- package/registry/examples/glow-card/link-card.d.ts +4 -0
- package/registry/examples/glow-card/link-card.js +14 -0
- package/registry/examples/glow-card/link-card.tsx +13 -0
- package/registry/examples/glow-card/plans.d.ts +4 -0
- package/registry/examples/glow-card/plans.js +25 -0
- package/registry/examples/glow-card/plans.tsx +26 -0
- package/registry/examples/glow-card/spotlight.d.ts +4 -0
- package/registry/examples/glow-card/spotlight.js +14 -0
- package/registry/examples/glow-card/spotlight.tsx +15 -0
- package/registry/examples/image-cropper/avatar.d.ts +4 -0
- package/registry/examples/image-cropper/avatar.js +13 -0
- package/registry/examples/image-cropper/avatar.tsx +14 -0
- package/registry/examples/image-cropper/banner.d.ts +4 -0
- package/registry/examples/image-cropper/banner.js +11 -0
- package/registry/examples/image-cropper/banner.tsx +10 -0
- package/registry/examples/image-cropper/vertical-video.d.ts +4 -0
- package/registry/examples/image-cropper/vertical-video.js +12 -0
- package/registry/examples/image-cropper/vertical-video.tsx +16 -0
- package/registry/examples/iso/compose.d.ts +4 -0
- package/registry/examples/iso/compose.js +22 -0
- package/registry/examples/iso/compose.tsx +19 -0
- package/registry/examples/iso/orazaka-hero.d.ts +4 -0
- package/registry/examples/iso/orazaka-hero.js +26 -0
- package/registry/examples/iso/orazaka-hero.tsx +21 -0
- package/registry/examples/iso/orochia-hero.d.ts +4 -0
- package/registry/examples/iso/orochia-hero.js +29 -0
- package/registry/examples/iso/orochia-hero.tsx +23 -0
- package/registry/examples/iso/still.d.ts +4 -0
- package/registry/examples/iso/still.js +21 -0
- package/registry/examples/iso/still.tsx +15 -0
- package/registry/examples/loader/endings.d.ts +4 -0
- package/registry/examples/loader/endings.js +14 -0
- package/registry/examples/loader/endings.tsx +11 -0
- package/registry/examples/loader/fetch-flow.d.ts +4 -0
- package/registry/examples/loader/fetch-flow.js +24 -0
- package/registry/examples/loader/fetch-flow.tsx +24 -0
- package/registry/examples/loader/minimal.d.ts +4 -0
- package/registry/examples/loader/minimal.js +11 -0
- package/registry/examples/loader/minimal.tsx +6 -0
- package/registry/examples/loader/overlay.d.ts +4 -0
- package/registry/examples/loader/overlay.js +16 -0
- package/registry/examples/loader/overlay.tsx +13 -0
- package/registry/examples/loader/region-handover.d.ts +4 -0
- package/registry/examples/loader/region-handover.js +42 -0
- package/registry/examples/loader/region-handover.tsx +29 -0
- package/registry/examples/loader/upload-eta.d.ts +4 -0
- package/registry/examples/loader/upload-eta.js +11 -0
- package/registry/examples/loader/upload-eta.tsx +10 -0
- package/registry/examples/marquee/cards.d.ts +4 -0
- package/registry/examples/marquee/cards.js +23 -0
- package/registry/examples/marquee/cards.tsx +21 -0
- package/registry/examples/marquee/logos.d.ts +4 -0
- package/registry/examples/marquee/logos.js +12 -0
- package/registry/examples/marquee/logos.tsx +17 -0
- package/registry/examples/media-capture/clip.d.ts +4 -0
- package/registry/examples/media-capture/clip.js +20 -0
- package/registry/examples/media-capture/clip.tsx +18 -0
- package/registry/examples/media-capture/native/photo.d.ts +4 -0
- package/registry/examples/media-capture/native/photo.dark.png +0 -0
- package/registry/examples/media-capture/native/photo.js +27 -0
- package/registry/examples/media-capture/native/photo.light.png +0 -0
- package/registry/examples/media-capture/native/photo.tsx +20 -0
- package/registry/examples/media-capture/profile-photo.d.ts +4 -0
- package/registry/examples/media-capture/profile-photo.js +24 -0
- package/registry/examples/media-capture/profile-photo.tsx +20 -0
- package/registry/examples/meter/balance.d.ts +4 -0
- package/registry/examples/meter/balance.js +14 -0
- package/registry/examples/meter/balance.tsx +15 -0
- package/registry/examples/meter/quota.d.ts +4 -0
- package/registry/examples/meter/quota.js +15 -0
- package/registry/examples/meter/quota.tsx +12 -0
- package/registry/examples/meter/split.d.ts +4 -0
- package/registry/examples/meter/split.js +18 -0
- package/registry/examples/meter/split.tsx +18 -0
- package/registry/examples/nav-bar/app-bar.d.ts +4 -0
- package/registry/examples/nav-bar/app-bar.js +22 -0
- package/registry/examples/nav-bar/app-bar.tsx +21 -0
- package/registry/examples/nav-bar/menu-open.d.ts +4 -0
- package/registry/examples/nav-bar/menu-open.js +26 -0
- package/registry/examples/nav-bar/menu-open.tsx +26 -0
- package/registry/examples/nav-bar/site.d.ts +4 -0
- package/registry/examples/nav-bar/site.js +31 -0
- package/registry/examples/nav-bar/site.tsx +36 -0
- package/registry/examples/number-ticker/gradient.d.ts +4 -0
- package/registry/examples/number-ticker/gradient.js +11 -0
- package/registry/examples/number-ticker/gradient.tsx +10 -0
- package/registry/examples/number-ticker/live-total.d.ts +4 -0
- package/registry/examples/number-ticker/live-total.js +17 -0
- package/registry/examples/number-ticker/live-total.tsx +21 -0
- package/registry/examples/number-ticker/stats.d.ts +4 -0
- package/registry/examples/number-ticker/stats.js +19 -0
- package/registry/examples/number-ticker/stats.tsx +23 -0
- package/registry/examples/pagination/cursor.d.ts +4 -0
- package/registry/examples/pagination/cursor.js +24 -0
- package/registry/examples/pagination/cursor.tsx +20 -0
- package/registry/examples/pagination/links.d.ts +4 -0
- package/registry/examples/pagination/links.js +11 -0
- package/registry/examples/pagination/links.tsx +6 -0
- package/registry/examples/pagination/native/cursor.d.ts +4 -0
- package/registry/examples/pagination/native/cursor.dark.png +0 -0
- package/registry/examples/pagination/native/cursor.js +19 -0
- package/registry/examples/pagination/native/cursor.light.png +0 -0
- package/registry/examples/pagination/native/cursor.tsx +13 -0
- package/registry/examples/pagination/native/pages.d.ts +4 -0
- package/registry/examples/pagination/native/pages.dark.png +0 -0
- package/registry/examples/pagination/native/pages.js +21 -0
- package/registry/examples/pagination/native/pages.light.png +0 -0
- package/registry/examples/pagination/native/pages.tsx +14 -0
- package/registry/examples/pagination/results.d.ts +4 -0
- package/registry/examples/pagination/results.js +23 -0
- package/registry/examples/pagination/results.tsx +19 -0
- package/registry/examples/pagination/table-footer.d.ts +4 -0
- package/registry/examples/pagination/table-footer.js +31 -0
- package/registry/examples/pagination/table-footer.tsx +27 -0
- package/registry/examples/progress/buffer.d.ts +4 -0
- package/registry/examples/progress/buffer.js +11 -0
- package/registry/examples/progress/buffer.tsx +10 -0
- package/registry/examples/progress/statuses.d.ts +4 -0
- package/registry/examples/progress/statuses.js +14 -0
- package/registry/examples/progress/statuses.tsx +11 -0
- package/registry/examples/progress/steps.d.ts +4 -0
- package/registry/examples/progress/steps.js +14 -0
- package/registry/examples/progress/steps.tsx +13 -0
- package/registry/examples/progress/upload.d.ts +4 -0
- package/registry/examples/progress/upload.js +11 -0
- package/registry/examples/progress/upload.tsx +10 -0
- package/registry/examples/search-field/global.d.ts +4 -0
- package/registry/examples/search-field/global.js +19 -0
- package/registry/examples/search-field/global.tsx +15 -0
- package/registry/examples/search-field/native/default.d.ts +4 -0
- package/registry/examples/search-field/native/default.dark.png +0 -0
- package/registry/examples/search-field/native/default.js +13 -0
- package/registry/examples/search-field/native/default.light.png +0 -0
- package/registry/examples/search-field/native/default.tsx +7 -0
- package/registry/examples/search-field/suggestions.d.ts +4 -0
- package/registry/examples/search-field/suggestions.js +30 -0
- package/registry/examples/search-field/suggestions.tsx +27 -0
- package/registry/examples/search-field/toolbar.d.ts +4 -0
- package/registry/examples/search-field/toolbar.js +17 -0
- package/registry/examples/search-field/toolbar.tsx +21 -0
- package/registry/examples/skeleton/paragraph.d.ts +4 -0
- package/registry/examples/skeleton/paragraph.js +14 -0
- package/registry/examples/skeleton/paragraph.tsx +12 -0
- package/registry/examples/skeleton/shape-of-content.d.ts +4 -0
- package/registry/examples/skeleton/shape-of-content.js +23 -0
- package/registry/examples/skeleton/shape-of-content.tsx +26 -0
- package/registry/examples/spinner/default.js +5 -2
- package/registry/examples/spinner/default.tsx +7 -1
- package/registry/examples/spinner/sizes.js +2 -1
- package/registry/examples/spinner/sizes.tsx +2 -0
- package/registry/examples/spinner/value.d.ts +4 -0
- package/registry/examples/spinner/value.js +11 -0
- package/registry/examples/spinner/value.tsx +12 -0
- package/registry/examples/stepper/checkout.d.ts +4 -0
- package/registry/examples/stepper/checkout.js +22 -0
- package/registry/examples/stepper/checkout.tsx +17 -0
- package/registry/examples/stepper/failed.d.ts +4 -0
- package/registry/examples/stepper/failed.js +26 -0
- package/registry/examples/stepper/failed.tsx +21 -0
- package/registry/examples/stepper/job.d.ts +4 -0
- package/registry/examples/stepper/job.js +32 -0
- package/registry/examples/stepper/job.tsx +28 -0
- package/registry/examples/tag-input/recipients.d.ts +4 -0
- package/registry/examples/tag-input/recipients.js +23 -0
- package/registry/examples/tag-input/recipients.tsx +20 -0
- package/registry/examples/tag-input/video-tags.d.ts +4 -0
- package/registry/examples/tag-input/video-tags.js +26 -0
- package/registry/examples/tag-input/video-tags.tsx +22 -0
- package/registry/examples/toast/grouped.d.ts +4 -0
- package/registry/examples/toast/grouped.js +21 -0
- package/registry/examples/toast/grouped.tsx +23 -0
- package/registry/examples/toast/undo.d.ts +4 -0
- package/registry/examples/toast/undo.js +29 -0
- package/registry/examples/toast/undo.tsx +30 -0
- package/registry/examples/toast/upload-progress.d.ts +4 -0
- package/registry/examples/toast/upload-progress.js +29 -0
- package/registry/examples/toast/upload-progress.tsx +31 -0
- package/registry/examples/video-player/default.d.ts +4 -0
- package/registry/examples/video-player/default.js +12 -0
- package/registry/examples/video-player/default.tsx +8 -0
- package/registry/examples/video-player/gated.d.ts +4 -0
- package/registry/examples/video-player/gated.js +26 -0
- package/registry/examples/video-player/gated.tsx +23 -0
- package/registry/examples/video-player/native/default.d.ts +4 -0
- package/registry/examples/video-player/native/default.dark.png +0 -0
- package/registry/examples/video-player/native/default.js +18 -0
- package/registry/examples/video-player/native/default.light.png +0 -0
- package/registry/examples/video-player/native/default.tsx +12 -0
- package/registry/examples/video-player/signed-source.d.ts +4 -0
- package/registry/examples/video-player/signed-source.js +16 -0
- package/registry/examples/video-player/signed-source.tsx +15 -0
- package/registry/examples/video-player/vertical.d.ts +4 -0
- package/registry/examples/video-player/vertical.js +12 -0
- package/registry/examples/video-player/vertical.tsx +12 -0
- package/registry/examples/video-trimmer/custom.d.ts +4 -0
- package/registry/examples/video-trimmer/custom.js +24 -0
- package/registry/examples/video-trimmer/custom.tsx +26 -0
- package/registry/examples/video-trimmer/filmstrip.d.ts +4 -0
- package/registry/examples/video-trimmer/filmstrip.js +15 -0
- package/registry/examples/video-trimmer/filmstrip.tsx +13 -0
- package/registry/examples/video-trimmer/playhead.d.ts +4 -0
- package/registry/examples/video-trimmer/playhead.js +15 -0
- package/registry/examples/video-trimmer/playhead.tsx +13 -0
- package/registry/field.json +1 -1
- package/registry/file-upload.json +471 -0
- package/registry/filter-bar.json +347 -0
- package/registry/glow-card.json +162 -0
- package/registry/image-cropper.json +313 -0
- package/registry/index.json +445 -20
- package/registry/iso.json +1355 -0
- package/registry/kbd.json +1 -1
- package/registry/loader.json +399 -0
- package/registry/marquee.json +225 -0
- package/registry/mascots.json +3 -3
- package/registry/media-capture.json +347 -0
- package/registry/meter.json +324 -0
- package/registry/nav-bar.json +480 -0
- package/registry/number-ticker.json +219 -0
- package/registry/page-header.json +1 -1
- package/registry/pagination.json +475 -0
- package/registry/popover.json +1 -1
- package/registry/progress.json +114 -9
- package/registry/radio-group.json +1 -1
- package/registry/search-field.json +436 -0
- package/registry/section-backdrop.json +1 -1
- package/registry/separator.json +1 -1
- package/registry/skeleton.json +69 -13
- package/registry/slider.json +1 -1
- package/registry/slot.json +1 -1
- package/registry/spinner.json +91 -27
- package/registry/stat.json +1 -1
- package/registry/stepper.json +174 -0
- package/registry/switch.json +1 -1
- package/registry/tabs.json +11 -7
- package/registry/tag-input.json +363 -0
- package/registry/theme.json +3 -3
- package/registry/toast.json +41 -13
- package/registry/tooltip.json +1 -1
- package/registry/video-player.json +598 -0
- package/registry/video-trimmer.json +385 -0
- package/dist/chunk-FHYZSO2S.js.map +0 -1
- package/dist/chunk-PESA2R4U.js +0 -51
- package/dist/chunk-PESA2R4U.js.map +0 -1
- package/registry/examples/spinner/muted.js +0 -11
- package/registry/examples/spinner/muted.tsx +0 -6
- /package/registry/examples/{spinner/muted.d.ts → audio-player/podcast.d.ts} +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "audio-player",
|
|
3
|
+
"type": "primitive",
|
|
4
|
+
"title": "Audio player",
|
|
5
|
+
"summary": "A sound with a waveform you seek on — the peaks given by the server or computed once with Web Audio — play, time and speed, paused when it leaves the screen.",
|
|
6
|
+
"description": "A sound with a waveform you seek on — the peaks given by the server or computed once with Web Audio — play, time and speed, paused when it leaves the screen.",
|
|
7
|
+
"status": "beta",
|
|
8
|
+
"category": "media",
|
|
9
|
+
"platforms": "web",
|
|
10
|
+
"whenToUse": [
|
|
11
|
+
"For a voice note, a podcast extract, a generated voice, a music preview.",
|
|
12
|
+
"When the shape of the sound helps to find a moment (speech and silences)."
|
|
13
|
+
],
|
|
14
|
+
"whenNotToUse": [
|
|
15
|
+
{
|
|
16
|
+
"when": "For a sound with a picture: the video player.",
|
|
17
|
+
"use": "video-player"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"when": "To show a value along a bar without a sound: a progress bar.",
|
|
21
|
+
"use": "progress"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"bestPractices": [
|
|
25
|
+
"Compute the peaks on the server once (`peaks`); `computePeaks` downloads and decodes the whole file in the browser.",
|
|
26
|
+
"Give `duration` when you know it: the time shows before the metadata arrives.",
|
|
27
|
+
"Name the player by its content (“Voice note from Eric, 0:42”)."
|
|
28
|
+
],
|
|
29
|
+
"accessibility": {
|
|
30
|
+
"keyboard": [
|
|
31
|
+
{
|
|
32
|
+
"keys": "Arrow keys",
|
|
33
|
+
"action": "Back or forward 5 seconds on the waveform."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"keys": "Page Up / Page Down",
|
|
37
|
+
"action": "Back or forward 30 seconds."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"keys": "Home / End",
|
|
41
|
+
"action": "The start or the end."
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"notes": [
|
|
45
|
+
"A `group` named by `title`; the waveform is a `slider` whose value is read as a time (“0:42 of 3:10”).",
|
|
46
|
+
"The play button says its state (“Pause” while playing); the speed button its speed.",
|
|
47
|
+
"The bars are decorative; only the colour of the played part changes, nothing moves."
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"related": [
|
|
51
|
+
"video-player",
|
|
52
|
+
"slider",
|
|
53
|
+
"progress"
|
|
54
|
+
],
|
|
55
|
+
"web": {
|
|
56
|
+
"entry": "@krizaka/ui/audio-player",
|
|
57
|
+
"import": "import { AudioPlayer, resamplePeaks, computeAudioPeaks } from \"@krizaka/ui/audio-player\";",
|
|
58
|
+
"props": [
|
|
59
|
+
{
|
|
60
|
+
"component": "AudioPlayer",
|
|
61
|
+
"description": "A sound with a seekable waveform: play / pause, time, speed — a voice note, a podcast clip, a track.",
|
|
62
|
+
"props": [
|
|
63
|
+
{
|
|
64
|
+
"name": "src",
|
|
65
|
+
"type": "string",
|
|
66
|
+
"default": null,
|
|
67
|
+
"description": "The address of the sound.",
|
|
68
|
+
"required": true
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "title",
|
|
72
|
+
"type": "string",
|
|
73
|
+
"default": null,
|
|
74
|
+
"description": "What it is (\"Voice note — Eric, 0:42\"): shown, and the accessible name of the player.",
|
|
75
|
+
"required": true
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "bars",
|
|
79
|
+
"type": "number",
|
|
80
|
+
"default": "48",
|
|
81
|
+
"description": "How many bars. Default 48.",
|
|
82
|
+
"required": false
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "className",
|
|
86
|
+
"type": "string",
|
|
87
|
+
"default": null,
|
|
88
|
+
"description": "Classes merged on the root.",
|
|
89
|
+
"required": false
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "computePeaks",
|
|
93
|
+
"type": "boolean",
|
|
94
|
+
"default": null,
|
|
95
|
+
"description": "Without `peaks`: fetches the file and computes them with Web Audio at the first play (same-origin or CORS).",
|
|
96
|
+
"required": false
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "duration",
|
|
100
|
+
"type": "number",
|
|
101
|
+
"default": "0",
|
|
102
|
+
"description": "The length, in seconds, before the metadata is loaded (from the server).",
|
|
103
|
+
"required": false
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "labels",
|
|
107
|
+
"type": "Partial<AudioPlayerLabels>",
|
|
108
|
+
"default": null,
|
|
109
|
+
"description": "The words, passed translated; English by default.",
|
|
110
|
+
"required": false
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "onPlayingChange",
|
|
114
|
+
"type": "((playing: boolean) => void)",
|
|
115
|
+
"default": null,
|
|
116
|
+
"description": "Called when playback starts, pauses, ends.",
|
|
117
|
+
"required": false
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "pauseWhenHidden",
|
|
121
|
+
"type": "boolean",
|
|
122
|
+
"default": "true",
|
|
123
|
+
"description": "Pauses when it leaves the screen. Default `true`.",
|
|
124
|
+
"required": false
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "peaks",
|
|
128
|
+
"type": "readonly number[]",
|
|
129
|
+
"default": null,
|
|
130
|
+
"description": "The peaks, between 0 and 1, as many as you like (they are resampled to `bars`).",
|
|
131
|
+
"required": false
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "playbackRates",
|
|
135
|
+
"type": "readonly number[]",
|
|
136
|
+
"default": "[1, 1.5, 2]",
|
|
137
|
+
"description": "The speeds of the speed button. Default `[1, 1.5, 2]`; `[]` hides it.",
|
|
138
|
+
"required": false
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
"examples": [
|
|
144
|
+
{
|
|
145
|
+
"name": "voice-note",
|
|
146
|
+
"title": "Voice note",
|
|
147
|
+
"description": "Peaks from the server, a short note.",
|
|
148
|
+
"path": "examples/audio-player/voice-note.tsx",
|
|
149
|
+
"module": "@krizaka/ui/registry/examples/audio-player/voice-note",
|
|
150
|
+
"code": "import { AudioPlayer } from \"@krizaka/ui/audio-player\";\n\n// Peaks computed once on the server: 64 values between 0 and 1.\nconst PEAKS = Array.from({ length: 64 }, (_, i) => 0.2 + Math.abs(Math.sin(i * 0.45) * Math.cos(i * 0.13)) * 0.8);\n\nexport default function AudioPlayerVoiceNote() {\n return (\n <div className=\"w-full max-w-md\">\n <AudioPlayer title=\"Voice note from Eric\" src=\"https://www.krizaka.com/assets/orochia/tour/elena-live.mp4\" peaks={PEAKS} duration={42} />\n </div>\n );\n}\n"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "podcast",
|
|
154
|
+
"title": "Podcast extract",
|
|
155
|
+
"description": "More bars and four speeds.",
|
|
156
|
+
"path": "examples/audio-player/podcast.tsx",
|
|
157
|
+
"module": "@krizaka/ui/registry/examples/audio-player/podcast",
|
|
158
|
+
"code": "import { AudioPlayer } from \"@krizaka/ui/audio-player\";\n\nconst PEAKS = Array.from({ length: 200 }, (_, i) => (i % 37 < 3 ? 0.05 : 0.3 + Math.abs(Math.sin(i * 0.31)) * 0.7));\n\n// A longer extract: more bars, four speeds, the time before the metadata arrives.\nexport default function AudioPlayerPodcast() {\n return (\n <div className=\"w-full max-w-lg\">\n <AudioPlayer\n title=\"Creators' hour — episode 12, extract\"\n src=\"https://www.krizaka.com/assets/orochia/tour/alex-discover.mp4\"\n peaks={PEAKS}\n bars={72}\n duration={190}\n playbackRates={[1, 1.25, 1.5, 2]}\n />\n </div>\n );\n}\n"
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
"native": null,
|
|
163
|
+
"files": [
|
|
164
|
+
{
|
|
165
|
+
"path": "audio-player/audio-player.tsx",
|
|
166
|
+
"content": "// Client. An `<audio>` with a waveform you can seek on: the bars are the sound's peaks (given by the server, or\n// computed here from the file with Web Audio when `computePeaks` — once, on demand), the played part in the accent.\n// The waveform is a `slider` (arrows ± 5 s, Page keys ± 30 s, Home / End) whose value is read as a time; the play\n// button and the speed are named by props. No animation but the played part's colour, and it pauses off screen.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { PauseGlyph, PlayGlyph } from \"../glyphs\";\nimport { clamp, formatClock, playSafely, useInView } from \"../media\";\n\nexport const audioPlayer = tv({\n slots: {\n root: \"flex w-full items-center gap-3 rounded-xl border border-border-default bg-surface-1 p-3\",\n play:\n \"inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-accent text-on-accent transition-colors hover:bg-accent-hover \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-1\",\n body: \"flex min-w-0 flex-1 flex-col gap-1\",\n title: \"truncate text-sm font-semibold text-fg\",\n wave:\n \"relative flex h-10 w-full cursor-pointer touch-none items-center gap-[2px] rounded-md \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n bar: \"min-w-[2px] flex-1 rounded-full bg-border-strong data-[played]:bg-accent\",\n meta: \"flex items-center justify-between font-mono text-[11px] tabular-nums text-fg-secondary\",\n speed:\n \"shrink-0 rounded-md px-2 py-1 text-xs font-semibold tabular-nums text-fg-secondary hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n});\n\nexport type AudioPlayerLabels = {\n play: string;\n pause: string;\n /** The waveform slider (\"Seek\"). */\n seek: string;\n /** The speed button: `(rate) => \"Speed \" + rate + \"×\"`. */\n speed: (rate: number) => string;\n /** The slider's value: `(time, duration) => \"0:42 of 3:10\"`. */\n time: (time: string, duration: string) => string;\n};\n\nexport const audioPlayerLabels: AudioPlayerLabels = {\n play: \"Play\",\n pause: \"Pause\",\n seek: \"Seek\",\n speed: (rate) => `Speed ${rate}×`,\n time: (time, duration) => `${time} of ${duration}`,\n};\n\nexport type AudioPlayerProps = {\n /** The address of the sound. */\n src: string;\n /** What it is (\"Voice note — Eric, 0:42\"): shown, and the accessible name of the player. */\n title: string;\n /** The peaks, between 0 and 1, as many as you like (they are resampled to `bars`). */\n peaks?: readonly number[];\n /** Without `peaks`: fetches the file and computes them with Web Audio at the first play (same-origin or CORS). */\n computePeaks?: boolean;\n /** How many bars. Default 48. */\n bars?: number;\n /** The speeds of the speed button. Default `[1, 1.5, 2]`; `[]` hides it. */\n playbackRates?: readonly number[];\n /** Pauses when it leaves the screen. Default `true`. */\n pauseWhenHidden?: boolean;\n /** The length, in seconds, before the metadata is loaded (from the server). */\n duration?: number;\n /** Called when playback starts, pauses, ends. */\n onPlayingChange?: (playing: boolean) => void;\n /** The words, passed translated; English by default. */\n labels?: Partial<AudioPlayerLabels>;\n /** Classes merged on the root. */\n className?: string;\n};\n\n/** Resamples peaks to `count` bars (the maximum of each slice), normalised to the loudest. */\nexport function resamplePeaks(peaks: readonly number[], count: number): number[] {\n if (peaks.length === 0) return Array.from({ length: count }, () => 0.15);\n const out = Array.from({ length: count }, (_, i) => {\n const from = Math.floor((i / count) * peaks.length);\n const to = Math.max(from + 1, Math.floor(((i + 1) / count) * peaks.length));\n return Math.max(...peaks.slice(from, to).map(Math.abs));\n });\n const loudest = Math.max(...out, 0.0001);\n return out.map((v) => Math.max(0.08, v / loudest));\n}\n\n/** The peaks of a sound file, computed with Web Audio (`count` of them). */\nexport async function computeAudioPeaks(src: string, count = 200, signal?: AbortSignal): Promise<number[]> {\n const response = await fetch(src, { signal });\n const data = await response.arrayBuffer();\n const Context = window.AudioContext ?? (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext;\n const context = new Context();\n try {\n const buffer = await context.decodeAudioData(data);\n const channel = buffer.getChannelData(0);\n const size = Math.max(1, Math.floor(channel.length / count));\n return Array.from({ length: count }, (_, i) => {\n let peak = 0;\n for (let j = i * size; j < Math.min(channel.length, (i + 1) * size); j += 1) peak = Math.max(peak, Math.abs(channel[j]!));\n return peak;\n });\n } finally {\n void context.close();\n }\n}\n\n/** A sound with a seekable waveform: play / pause, time, speed — a voice note, a podcast clip, a track. */\nexport function AudioPlayer({\n src,\n title,\n peaks: given,\n computePeaks,\n bars = 48,\n playbackRates = [1, 1.5, 2],\n pauseWhenHidden = true,\n duration: knownDuration = 0,\n onPlayingChange,\n labels: words,\n className,\n}: AudioPlayerProps) {\n const labels = { ...audioPlayerLabels, ...words };\n const s = audioPlayer();\n const audio = React.useRef<HTMLAudioElement>(null);\n const root = React.useRef<HTMLDivElement>(null);\n const wave = React.useRef<HTMLDivElement>(null);\n const dragging = React.useRef(false);\n const [playing, setPlaying] = React.useState(false);\n const [time, setTime] = React.useState(0);\n const [duration, setDuration] = React.useState(knownDuration);\n const [rate, setRate] = React.useState(playbackRates[0] ?? 1);\n const [computed, setComputed] = React.useState<number[] | null>(null);\n const [wantPeaks, setWantPeaks] = React.useState(false);\n\n React.useEffect(() => {\n if (given || !computePeaks || !wantPeaks) return;\n const controller = new AbortController();\n computeAudioPeaks(src, 200, controller.signal).then(setComputed, () => undefined);\n return () => controller.abort();\n }, [given, computePeaks, wantPeaks, src]);\n\n useInView(root, (visible) => !visible && audio.current && !audio.current.paused && audio.current.pause(), pauseWhenHidden);\n\n const shape = React.useMemo(() => resamplePeaks(given ?? computed ?? [], bars), [given, computed, bars]);\n const progress = duration > 0 ? time / duration : 0;\n\n const seek = (to: number) => {\n if (!audio.current) return;\n const next = clamp(to, 0, duration || audio.current.duration || 0);\n audio.current.currentTime = next;\n setTime(next);\n };\n const at = (clientX: number) => {\n const box = wave.current?.getBoundingClientRect();\n return box && box.width ? ((clientX - box.left) / box.width) * duration : 0;\n };\n const toggle = () => {\n setWantPeaks(true);\n if (!audio.current) return;\n if (audio.current.paused) playSafely(audio.current);\n else audio.current.pause();\n };\n\n return (\n <div ref={root} role=\"group\" aria-label={title} className={s.root({ className })}>\n <audio\n ref={audio}\n src={src}\n preload=\"metadata\"\n onPlay={() => {\n setPlaying(true);\n onPlayingChange?.(true);\n }}\n onPause={() => {\n setPlaying(false);\n onPlayingChange?.(false);\n }}\n onTimeUpdate={(event) => setTime(event.currentTarget.currentTime)}\n onDurationChange={(event) => Number.isFinite(event.currentTarget.duration) && setDuration(event.currentTarget.duration)}\n />\n <button type=\"button\" className={s.play()} aria-label={playing ? labels.pause : labels.play} onClick={toggle}>\n {playing ? <PauseGlyph className=\"h-5 w-5\" /> : <PlayGlyph className=\"ml-0.5 h-5 w-5\" />}\n </button>\n <div className={s.body()}>\n <p className={s.title()} aria-hidden>\n {title}\n </p>\n <div\n ref={wave}\n role=\"slider\"\n tabIndex={0}\n aria-label={labels.seek}\n aria-valuemin={0}\n aria-valuemax={Math.round(duration)}\n aria-valuenow={Math.round(time)}\n aria-valuetext={labels.time(formatClock(time), formatClock(duration))}\n className={s.wave()}\n onPointerDown={(event) => {\n dragging.current = true;\n wave.current?.setPointerCapture?.(event.pointerId);\n seek(at(event.clientX));\n }}\n onPointerMove={(event) => dragging.current && seek(at(event.clientX))}\n onPointerUp={() => {\n dragging.current = false;\n }}\n onKeyDown={(event) => {\n const moves: Record<string, number> = {\n ArrowLeft: time - 5,\n ArrowDown: time - 5,\n ArrowRight: time + 5,\n ArrowUp: time + 5,\n PageDown: time - 30,\n PageUp: time + 30,\n Home: 0,\n End: duration,\n };\n const to = moves[event.key];\n if (to === undefined) return;\n event.preventDefault();\n seek(to);\n }}\n >\n {shape.map((peak, i) => (\n <span key={i} aria-hidden data-played={(i + 0.5) / bars <= progress ? \"\" : undefined} className={s.bar()} style={{ height: `${Math.round(peak * 100)}%` }} />\n ))}\n </div>\n <div className={s.meta()} aria-hidden>\n <span>{formatClock(time)}</span>\n <span>{formatClock(duration)}</span>\n </div>\n </div>\n {playbackRates.length > 1 && (\n <button\n type=\"button\"\n className={s.speed()}\n aria-label={labels.speed(rate)}\n onClick={() => {\n const next = playbackRates[(playbackRates.indexOf(rate) + 1) % playbackRates.length] ?? 1;\n if (audio.current) audio.current.playbackRate = next;\n setRate(next);\n }}\n >\n {rate}×\n </button>\n )}\n </div>\n );\n}\n"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"path": "audio-player/index.ts",
|
|
170
|
+
"content": "/** @krizaka/ui/audio-player — `AudioPlayer` (a seekable waveform, speed, pause off screen), `resamplePeaks`, `computeAudioPeaks`, `audioPlayer` (the slots). Client (\"use client\"). */\nexport { AudioPlayer, audioPlayer, type AudioPlayerLabels, audioPlayerLabels, type AudioPlayerProps, computeAudioPeaks, resamplePeaks } from \"./audio-player\";\n"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"path": "audio-player/meta.ts",
|
|
174
|
+
"content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Audio player\",\n summary: \"A sound with a waveform you seek on — the peaks given by the server or computed once with Web Audio — play, time and speed, paused when it leaves the screen.\",\n status: \"beta\",\n category: \"media\",\n platforms: \"web\",\n whenToUse: [\n \"For a voice note, a podcast extract, a generated voice, a music preview.\",\n \"When the shape of the sound helps to find a moment (speech and silences).\",\n ],\n whenNotToUse: [\n { when: \"For a sound with a picture: the video player.\", use: \"video-player\" },\n { when: \"To show a value along a bar without a sound: a progress bar.\", use: \"progress\" },\n ],\n bestPractices: [\n \"Compute the peaks on the server once (`peaks`); `computePeaks` downloads and decodes the whole file in the browser.\",\n \"Give `duration` when you know it: the time shows before the metadata arrives.\",\n \"Name the player by its content (“Voice note from Eric, 0:42”).\",\n ],\n accessibility: {\n keyboard: [\n { keys: \"Arrow keys\", action: \"Back or forward 5 seconds on the waveform.\" },\n { keys: \"Page Up / Page Down\", action: \"Back or forward 30 seconds.\" },\n { keys: \"Home / End\", action: \"The start or the end.\" },\n ],\n notes: [\n \"A `group` named by `title`; the waveform is a `slider` whose value is read as a time (“0:42 of 3:10”).\",\n \"The play button says its state (“Pause” while playing); the speed button its speed.\",\n \"The bars are decorative; only the colour of the played part changes, nothing moves.\",\n ],\n },\n related: [\"video-player\", \"slider\", \"progress\"],\n web: {\n imports: [\"AudioPlayer\", \"resamplePeaks\", \"computeAudioPeaks\"],\n examples: [\n { name: \"voice-note\", title: \"Voice note\", description: \"Peaks from the server, a short note.\" },\n { name: \"podcast\", title: \"Podcast extract\", description: \"More bars and four speeds.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"path": "glyphs.tsx",
|
|
178
|
+
"content": "// The small line glyphs the data and media primitives draw (play, volume, search, chevrons…): decorative, 24-unit\n// box, `currentColor`, sized by the caller's class. Shared by the entries that need them; never exported on its own —\n// a product draws its own icons with @krizaka/icons.\nimport type * as React from \"react\";\n\ntype GlyphProps = { className?: string };\n\nfunction Glyph({ className = \"h-4 w-4\", fill, children }: GlyphProps & { fill?: boolean; children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n className={className}\n fill={fill ? \"currentColor\" : \"none\"}\n stroke={fill ? \"none\" : \"currentColor\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n focusable=\"false\"\n >\n {children}\n </svg>\n );\n}\n\nexport const PlayGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <path d=\"M8 5.5v13a1 1 0 0 0 1.5.86l10.4-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5Z\" />\n </Glyph>\n);\nexport const PauseGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n </Glyph>\n);\nexport const VolumeGlyph = ({ muted, ...p }: GlyphProps & { muted?: boolean }) => (\n <Glyph {...p}>\n <path d=\"M11 5 6 9H3v6h3l5 4V5Z\" />\n {muted ? <path d=\"m22 9-6 6m0-6 6 6\" /> : <path d=\"M15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13\" />}\n </Glyph>\n);\nexport const FullscreenGlyph = ({ exit, ...p }: GlyphProps & { exit?: boolean }) => (\n <Glyph {...p}>\n {exit ? <path d=\"M9 4v5H4m11-5v5h5M9 20v-5H4m11 5v-5h5\" /> : <path d=\"M4 9V4h5m6 0h5v5M4 15v5h5m11-5v5h-5\" />}\n </Glyph>\n);\nexport const CaptionsGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"M10 10.5a2 2 0 1 0 0 3M17 10.5a2 2 0 1 0 0 3\" />\n </Glyph>\n);\nexport const PipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <rect x=\"12\" y=\"12\" width=\"6\" height=\"4\" rx=\"1\" />\n </Glyph>\n);\nexport const SearchGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <path d=\"m20 20-3.5-3.5\" />\n </Glyph>\n);\nexport const CloseGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Glyph>\n);\nexport const ChevronGlyph = ({ direction = \"down\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" | \"up\" | \"down\" }) => (\n <Glyph {...p}>\n <path d={{ left: \"m15 6-6 6 6 6\", right: \"m9 6 6 6-6 6\", up: \"m6 15 6-6 6 6\", down: \"m6 9 6 6 6-6\" }[direction]} />\n </Glyph>\n);\nexport const CheckGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Glyph>\n);\nexport const PlusGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 5v14M5 12h14\" />\n </Glyph>\n);\nexport const CalendarGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\" />\n <path d=\"M3 10h18M8 3v4M16 3v4\" />\n </Glyph>\n);\nexport const UploadGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 16V4m0 0L7 9m5-5 5 5\" />\n <path d=\"M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\" />\n </Glyph>\n);\nexport const FileGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z\" />\n <path d=\"M14 3v5h5\" />\n </Glyph>\n);\nexport const CameraGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 8h3l2-3h6l2 3h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z\" />\n <circle cx=\"12\" cy=\"13.5\" r=\"3.5\" />\n </Glyph>\n);\nexport const FlipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 0 1 14-5.3M20 12a8 8 0 0 1-14 5.3\" />\n <path d=\"M18 3v4h-4M6 21v-4h4\" />\n </Glyph>\n);\nexport const RetryGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 1 0 2.3-5.7L4 8.5\" />\n <path d=\"M4 4v4.5h4.5\" />\n </Glyph>\n);\nexport const SortGlyph = ({ direction, ...p }: GlyphProps & { direction?: \"ascending\" | \"descending\" }) => (\n <Glyph {...p}>\n {direction === \"ascending\" ? <path d=\"m7 14 5-5 5 5\" /> : direction === \"descending\" ? <path d=\"m7 10 5 5 5-5\" /> : <path d=\"m8 9 4-4 4 4M8 15l4 4 4-4\" />}\n </Glyph>\n);\n"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"path": "media.ts",
|
|
182
|
+
"content": "// Shared by the data and media primitives (client): the clock format, the reduced-motion preference, the\n// in-view observer, a debounced callback. Never an entry of its own.\nimport * as React from \"react\";\n\n/** Seconds as a clock: `75` → `1:15`, `3725` → `1:02:05`. Negative or unknown values read `0:00`. */\nexport function formatClock(seconds: number): string {\n const s = Number.isFinite(seconds) && seconds > 0 ? Math.floor(seconds) : 0;\n const h = Math.floor(s / 3600);\n const m = Math.floor((s % 3600) / 60);\n const rest = String(s % 60).padStart(2, \"0\");\n return h > 0 ? `${h}:${String(m).padStart(2, \"0\")}:${rest}` : `${m}:${rest}`;\n}\n\n/** Clamps `value` between `min` and `max`. */\nexport const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nconst REDUCE = \"(prefers-reduced-motion: reduce)\";\nconst subscribeReduce = (notify: () => void) => {\n if (typeof window === \"undefined\" || !window.matchMedia) return () => undefined;\n const query = window.matchMedia(REDUCE);\n query.addEventListener?.(\"change\", notify);\n return () => query.removeEventListener?.(\"change\", notify);\n};\n\n/** `true` when the person asked for less motion (`prefers-reduced-motion: reduce`); follows a change of the setting. */\nexport function usePrefersReducedMotion(): boolean {\n return React.useSyncExternalStore(\n subscribeReduce,\n () => (typeof window !== \"undefined\" && window.matchMedia ? window.matchMedia(REDUCE).matches : false),\n () => false,\n );\n}\n\n/** The latest value of a callback, for an effect or an event that must not re-subscribe when it changes. */\nexport function useLatest<T>(value: T) {\n const ref = React.useRef(value);\n React.useLayoutEffect(() => {\n ref.current = value;\n });\n return ref;\n}\n\n/** Calls `onChange(visible)` when at least `threshold` of the element enters or leaves the viewport. */\nexport function useInView(ref: React.RefObject<Element | null>, onChange: (visible: boolean) => void, enabled = true, threshold = 0.25) {\n const latest = useLatest(onChange);\n React.useEffect(() => {\n const element = ref.current;\n if (!enabled || !element || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => entry && latest.current(entry.isIntersecting), { threshold });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref, enabled, threshold, latest]);\n}\n\n/** A stable function that runs `callback` once `delay` ms have passed without a new call; `cancel()` drops the pending one. */\nexport function useDebouncedCallback<A extends unknown[]>(callback: (...args: A) => void, delay: number) {\n const latest = useLatest(callback);\n const [debounced] = React.useState(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let wait = delay;\n const run = (...args: A) => {\n clearTimeout(timer);\n if (wait <= 0) latest.current(...args);\n else timer = setTimeout(() => latest.current(...args), wait);\n };\n return Object.assign(run, {\n cancel: () => clearTimeout(timer),\n setDelay: (next: number) => {\n wait = next;\n },\n });\n });\n React.useEffect(() => debounced.setDelay(delay), [debounced, delay]);\n React.useEffect(() => () => debounced.cancel(), [debounced]);\n return debounced;\n}\n\n/** A value controlled by a prop when it is given, held inside otherwise; `set` calls `onChange` either way. */\nexport function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (next: T) => void) {\n const [inner, setInner] = React.useState(defaultValue);\n const controlled = value !== undefined;\n const current = controlled ? value : inner;\n const set = React.useCallback(\n (next: T) => {\n if (!controlled) setInner(next);\n onChange?.(next);\n },\n [controlled, onChange],\n );\n return [current, set] as const;\n}\n\n/** Starts a media element without an unhandled rejection (autoplay refused, the source replaced meanwhile). */\nexport function playSafely(media: HTMLMediaElement | null | undefined) {\n try {\n const started = media?.play() as Promise<void> | undefined;\n started?.catch?.(() => undefined);\n } catch {\n // Not playable here (no media support): the controls stay as they are.\n }\n}\n"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"path": "meta.ts",
|
|
186
|
+
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"data-table\"\n | \"date-picker\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"pagination\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. `media`: video, sound, camera, files, cropping. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
"dependencies": [
|
|
190
|
+
"tailwind-variants@^3.3.1"
|
|
191
|
+
],
|
|
192
|
+
"registryDependencies": [],
|
|
193
|
+
"demo": {
|
|
194
|
+
"path": "examples/audio-player/voice-note.tsx",
|
|
195
|
+
"content": "import { AudioPlayer } from \"@krizaka/ui/audio-player\";\n\n// Peaks computed once on the server: 64 values between 0 and 1.\nconst PEAKS = Array.from({ length: 64 }, (_, i) => 0.2 + Math.abs(Math.sin(i * 0.45) * Math.cos(i * 0.13)) * 0.8);\n\nexport default function AudioPlayerVoiceNote() {\n return (\n <div className=\"w-full max-w-md\">\n <AudioPlayer title=\"Voice note from Eric\" src=\"https://www.krizaka.com/assets/orochia/tour/elena-live.mp4\" peaks={PEAKS} duration={42} />\n </div>\n );\n}\n"
|
|
196
|
+
},
|
|
197
|
+
"props": [
|
|
198
|
+
{
|
|
199
|
+
"component": "AudioPlayer",
|
|
200
|
+
"description": "A sound with a seekable waveform: play / pause, time, speed — a voice note, a podcast clip, a track.",
|
|
201
|
+
"props": [
|
|
202
|
+
{
|
|
203
|
+
"name": "src",
|
|
204
|
+
"type": "string",
|
|
205
|
+
"default": null,
|
|
206
|
+
"description": "The address of the sound.",
|
|
207
|
+
"required": true
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"name": "title",
|
|
211
|
+
"type": "string",
|
|
212
|
+
"default": null,
|
|
213
|
+
"description": "What it is (\"Voice note — Eric, 0:42\"): shown, and the accessible name of the player.",
|
|
214
|
+
"required": true
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"name": "bars",
|
|
218
|
+
"type": "number",
|
|
219
|
+
"default": "48",
|
|
220
|
+
"description": "How many bars. Default 48.",
|
|
221
|
+
"required": false
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"name": "className",
|
|
225
|
+
"type": "string",
|
|
226
|
+
"default": null,
|
|
227
|
+
"description": "Classes merged on the root.",
|
|
228
|
+
"required": false
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "computePeaks",
|
|
232
|
+
"type": "boolean",
|
|
233
|
+
"default": null,
|
|
234
|
+
"description": "Without `peaks`: fetches the file and computes them with Web Audio at the first play (same-origin or CORS).",
|
|
235
|
+
"required": false
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"name": "duration",
|
|
239
|
+
"type": "number",
|
|
240
|
+
"default": "0",
|
|
241
|
+
"description": "The length, in seconds, before the metadata is loaded (from the server).",
|
|
242
|
+
"required": false
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"name": "labels",
|
|
246
|
+
"type": "Partial<AudioPlayerLabels>",
|
|
247
|
+
"default": null,
|
|
248
|
+
"description": "The words, passed translated; English by default.",
|
|
249
|
+
"required": false
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"name": "onPlayingChange",
|
|
253
|
+
"type": "((playing: boolean) => void)",
|
|
254
|
+
"default": null,
|
|
255
|
+
"description": "Called when playback starts, pauses, ends.",
|
|
256
|
+
"required": false
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"name": "pauseWhenHidden",
|
|
260
|
+
"type": "boolean",
|
|
261
|
+
"default": "true",
|
|
262
|
+
"description": "Pauses when it leaves the screen. Default `true`.",
|
|
263
|
+
"required": false
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"name": "peaks",
|
|
267
|
+
"type": "readonly number[]",
|
|
268
|
+
"default": null,
|
|
269
|
+
"description": "The peaks, between 0 and 1, as many as you like (they are resampled to `bars`).",
|
|
270
|
+
"required": false
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"name": "playbackRates",
|
|
274
|
+
"type": "readonly number[]",
|
|
275
|
+
"default": "[1, 1.5, 2]",
|
|
276
|
+
"description": "The speeds of the speed button. Default `[1, 1.5, 2]`; `[]` hides it.",
|
|
277
|
+
"required": false
|
|
278
|
+
}
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
}
|
package/registry/avatar.json
CHANGED
|
@@ -320,7 +320,7 @@
|
|
|
320
320
|
},
|
|
321
321
|
{
|
|
322
322
|
"path": "meta.ts",
|
|
323
|
-
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"cn\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"kbd\"\n | \"mascots\"\n | \"page-header\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"switch\"\n | \"tabs\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
323
|
+
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"data-table\"\n | \"date-picker\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"pagination\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. `media`: video, sound, camera, files, cropping. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
324
324
|
}
|
|
325
325
|
],
|
|
326
326
|
"dependencies": [
|
package/registry/badge.json
CHANGED
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
},
|
|
240
240
|
{
|
|
241
241
|
"path": "meta.ts",
|
|
242
|
-
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"cn\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"kbd\"\n | \"mascots\"\n | \"page-header\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"switch\"\n | \"tabs\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
242
|
+
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"data-table\"\n | \"date-picker\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"pagination\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. `media`: video, sound, camera, files, cropping. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
243
243
|
}
|
|
244
244
|
],
|
|
245
245
|
"dependencies": [
|