@sableui/react 0.6.2 → 0.7.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/AGENTS.md +2 -2
- package/CHANGELOG.md +273 -0
- package/CONTRIBUTING.md +16 -10
- package/DESIGN.md +3 -3
- package/README.md +3 -3
- package/bin/sable-lint.mjs +18 -0
- package/bin/sable.mjs +470 -62
- package/dist/blocks/api-keys-block.js +44 -0
- package/dist/blocks/api-keys-block.meta.js +21 -0
- package/dist/blocks/chat-thread-block.js +17 -0
- package/dist/blocks/chat-thread-block.meta.js +20 -0
- package/dist/blocks/command-palette-block.js +24 -0
- package/dist/blocks/command-palette-block.meta.js +21 -0
- package/dist/blocks/cta-band-block.js +27 -0
- package/dist/blocks/cta-band-block.meta.js +20 -0
- package/dist/blocks/danger-zone-block.js +39 -0
- package/dist/blocks/danger-zone-block.meta.js +21 -0
- package/dist/blocks/device-comparison-block.js +69 -0
- package/dist/blocks/device-comparison-block.meta.js +21 -0
- package/dist/blocks/event-card-block.js +40 -0
- package/dist/blocks/event-card-block.meta.js +21 -0
- package/dist/blocks/faq-block.js +38 -0
- package/dist/blocks/faq-block.meta.js +20 -0
- package/dist/blocks/feature-grid-block.js +38 -0
- package/dist/blocks/feature-grid-block.meta.js +21 -0
- package/dist/blocks/feedback-form-block.js +30 -0
- package/dist/blocks/feedback-form-block.meta.js +21 -0
- package/dist/blocks/goal-progress-block.js +24 -0
- package/dist/blocks/goal-progress-block.meta.js +21 -0
- package/dist/blocks/hero-block.js +33 -0
- package/dist/blocks/hero-block.meta.js +21 -0
- package/dist/blocks/index.js +162 -1964
- package/dist/blocks/invite-team-block.js +36 -0
- package/dist/blocks/invite-team-block.meta.js +20 -0
- package/dist/blocks/invoice-history-block.js +41 -0
- package/dist/blocks/invoice-history-block.meta.js +21 -0
- package/dist/blocks/kpi-sparkline-block.js +29 -0
- package/dist/blocks/kpi-sparkline-block.meta.js +20 -0
- package/dist/blocks/media-player-block.js +68 -0
- package/dist/blocks/media-player-block.meta.js +21 -0
- package/dist/blocks/newsletter-block.js +35 -0
- package/dist/blocks/newsletter-block.meta.js +21 -0
- package/dist/blocks/not-found-block.js +27 -0
- package/dist/blocks/not-found-block.meta.js +20 -0
- package/dist/blocks/notification-list-block.js +32 -0
- package/dist/blocks/notification-list-block.meta.js +21 -0
- package/dist/blocks/notification-settings-block.js +25 -0
- package/dist/blocks/notification-settings-block.meta.js +20 -0
- package/dist/blocks/order-tracking-block.js +26 -0
- package/dist/blocks/order-tracking-block.meta.js +20 -0
- package/dist/blocks/pricing-card-block.js +46 -0
- package/dist/blocks/pricing-card-block.meta.js +21 -0
- package/dist/blocks/pricing-table-block.js +88 -0
- package/dist/blocks/pricing-table-block.meta.js +20 -0
- package/dist/blocks/product-card-block.js +26 -0
- package/dist/blocks/product-card-block.meta.js +21 -0
- package/dist/blocks/profile-card-block.js +58 -0
- package/dist/blocks/profile-card-block.meta.js +21 -0
- package/dist/blocks/profile-form-block.js +70 -0
- package/dist/blocks/profile-form-block.meta.js +21 -0
- package/dist/blocks/revenue-breakdown-block.js +38 -0
- package/dist/blocks/revenue-breakdown-block.meta.js +21 -0
- package/dist/blocks/sign-in-block.js +38 -0
- package/dist/blocks/sign-in-block.meta.js +21 -0
- package/dist/blocks/sign-up-block.js +48 -0
- package/dist/blocks/sign-up-block.meta.js +21 -0
- package/dist/blocks/site-footer-block.js +54 -0
- package/dist/blocks/site-footer-block.meta.js +20 -0
- package/dist/blocks/stat-row-block.js +28 -0
- package/dist/blocks/stat-row-block.meta.js +21 -0
- package/dist/blocks/steps-block.js +37 -0
- package/dist/blocks/steps-block.meta.js +20 -0
- package/dist/blocks/task-list-block.js +52 -0
- package/dist/blocks/task-list-block.meta.js +21 -0
- package/dist/blocks/team-members-block.js +49 -0
- package/dist/blocks/team-members-block.meta.js +21 -0
- package/dist/blocks/testimonial-block.js +49 -0
- package/dist/blocks/testimonial-block.meta.js +20 -0
- package/dist/blocks/traffic-sources-block.js +39 -0
- package/dist/blocks/traffic-sources-block.meta.js +21 -0
- package/dist/blocks/traffic-trend-block.js +61 -0
- package/dist/blocks/traffic-trend-block.meta.js +21 -0
- package/dist/blocks/upload-list-block.js +39 -0
- package/dist/blocks/upload-list-block.meta.js +21 -0
- package/dist/blocks/verify-code-block.js +28 -0
- package/dist/blocks/verify-code-block.meta.js +21 -0
- package/dist/blocks/wallet-block.js +48 -0
- package/dist/blocks/wallet-block.meta.js +21 -0
- package/dist/components/accordion/accordion.js +63 -0
- package/dist/components/accordion/accordion.meta.js +155 -0
- package/dist/components/accordion/index.js +15 -0
- package/dist/components/app-header/app-header.js +30 -0
- package/dist/components/app-header/app-header.meta.js +88 -0
- package/dist/components/app-header/index.js +7 -0
- package/dist/components/app-shell/app-shell-dock.js +37 -0
- package/dist/components/app-shell/app-shell.js +67 -0
- package/dist/components/app-shell/app-shell.meta.js +176 -0
- package/dist/components/app-shell/index.js +7 -0
- package/dist/components/area-chart/area-chart.js +10 -0
- package/dist/components/area-chart/area-chart.meta.js +218 -0
- package/dist/components/area-chart/index.js +7 -0
- package/dist/components/attachment/attachment.js +176 -0
- package/dist/components/attachment/attachment.meta.js +179 -0
- package/dist/components/attachment/attachment.variants.js +47 -0
- package/dist/components/attachment/index.js +7 -0
- package/dist/components/avatar/avatar.js +192 -0
- package/dist/components/avatar/avatar.meta.js +233 -0
- package/dist/components/avatar/avatar.variants.js +44 -0
- package/dist/components/avatar/index.js +22 -0
- package/dist/components/badge/badge.js +26 -0
- package/dist/components/badge/badge.meta.js +171 -0
- package/dist/components/badge/badge.variants.js +103 -0
- package/dist/components/badge/index.js +11 -0
- package/dist/components/banner/banner.js +76 -0
- package/dist/components/banner/banner.meta.js +172 -0
- package/dist/components/banner/banner.variants.js +44 -0
- package/dist/components/banner/index.js +9 -0
- package/dist/components/bar-chart/bar-chart.js +10 -0
- package/dist/components/bar-chart/bar-chart.meta.js +245 -0
- package/dist/components/bar-chart/index.js +7 -0
- package/dist/components/bottom-nav/bottom-nav.js +63 -0
- package/dist/components/bottom-nav/bottom-nav.meta.js +95 -0
- package/dist/components/bottom-nav/index.js +11 -0
- package/dist/components/breadcrumbs/breadcrumbs.js +90 -0
- package/dist/components/breadcrumbs/breadcrumbs.meta.js +111 -0
- package/dist/components/breadcrumbs/index.js +17 -0
- package/dist/components/browser/browser.js +39 -0
- package/dist/components/browser/browser.meta.js +80 -0
- package/dist/components/browser/index.js +7 -0
- package/dist/components/bubble/bubble.js +110 -0
- package/dist/components/bubble/bubble.meta.js +158 -0
- package/dist/components/bubble/bubble.variants.js +90 -0
- package/dist/components/bubble/index.js +13 -0
- package/dist/components/button/button.js +87 -0
- package/dist/components/button/button.meta.js +302 -0
- package/dist/components/button/button.variants.js +137 -0
- package/dist/components/button/index.js +9 -0
- package/dist/components/calendar/calendar.js +89 -0
- package/dist/components/calendar/calendar.meta.js +136 -0
- package/dist/components/calendar/index.js +7 -0
- package/dist/components/card/card.js +200 -0
- package/dist/components/card/card.meta.js +212 -0
- package/dist/components/card/index.js +23 -0
- package/dist/components/carousel/carousel.js +428 -0
- package/dist/components/carousel/carousel.meta.js +100 -0
- package/dist/components/carousel/index.js +7 -0
- package/dist/components/chat-composer/chat-composer.js +174 -0
- package/dist/components/chat-composer/chat-composer.meta.js +241 -0
- package/dist/components/chat-composer/chat-composer.variants.js +17 -0
- package/dist/components/chat-composer/index.js +7 -0
- package/dist/components/checkbox/checkbox-mark.js +28 -0
- package/dist/components/checkbox/checkbox.js +30 -0
- package/dist/components/checkbox/checkbox.meta.js +127 -0
- package/dist/components/checkbox/index.js +7 -0
- package/dist/components/checkbox-card/checkbox-card.js +94 -0
- package/dist/components/checkbox-card/checkbox-card.meta.js +154 -0
- package/dist/components/checkbox-card/checkbox-card.variants.js +43 -0
- package/dist/components/checkbox-card/index.js +11 -0
- package/dist/components/code/code.js +19 -0
- package/dist/components/code/code.meta.js +71 -0
- package/dist/components/code/index.js +7 -0
- package/dist/components/code-block/code-block.js +84 -0
- package/dist/components/code-block/code-block.meta.js +103 -0
- package/dist/components/code-block/index.js +8 -0
- package/dist/components/collapsible/collapsible.js +38 -0
- package/dist/components/collapsible/collapsible.meta.js +117 -0
- package/dist/components/collapsible/index.js +15 -0
- package/dist/components/color-field/color-field.js +293 -0
- package/dist/components/color-field/color-field.meta.js +142 -0
- package/dist/components/color-field/color.js +69 -0
- package/dist/components/color-field/index.js +15 -0
- package/dist/components/combobox/combobox.js +486 -0
- package/dist/components/combobox/combobox.meta.js +217 -0
- package/dist/components/combobox/index.js +37 -0
- package/dist/components/command-menu/command-menu-trigger.js +122 -0
- package/dist/components/command-menu/command-menu.js +433 -0
- package/dist/components/command-menu/command-menu.meta.js +279 -0
- package/dist/components/command-menu/index.js +21 -0
- package/dist/components/context-card/context-card.js +62 -0
- package/dist/components/context-card/context-card.meta.js +106 -0
- package/dist/components/context-card/index.js +17 -0
- package/dist/components/context-menu/context-menu.js +92 -0
- package/dist/components/context-menu/context-menu.meta.js +138 -0
- package/dist/components/context-menu/index.js +23 -0
- package/dist/components/data-table/data-table.js +142 -0
- package/dist/components/data-table/data-table.meta.js +146 -0
- package/dist/components/data-table/index.js +9 -0
- package/dist/components/date-picker/date-picker.js +196 -0
- package/dist/components/date-picker/date-picker.meta.js +164 -0
- package/dist/components/date-picker/index.js +7 -0
- package/dist/components/date-tile/date-tile.js +29 -0
- package/dist/components/date-tile/date-tile.meta.js +72 -0
- package/dist/components/date-tile/index.js +7 -0
- package/dist/components/destructive-action-modal/destructive-action-modal.js +130 -0
- package/dist/components/destructive-action-modal/destructive-action-modal.meta.js +136 -0
- package/dist/components/destructive-action-modal/index.js +9 -0
- package/dist/components/dialog/dialog.js +207 -0
- package/dist/components/dialog/dialog.meta.js +239 -0
- package/dist/components/dialog/index.js +45 -0
- package/dist/components/disclosure-picker/disclosure-picker.js +417 -0
- package/dist/components/disclosure-picker/disclosure-picker.meta.js +213 -0
- package/dist/components/disclosure-picker/index.js +21 -0
- package/dist/components/empty-state/empty-state.js +52 -0
- package/dist/components/empty-state/empty-state.meta.js +158 -0
- package/dist/components/empty-state/index.js +7 -0
- package/dist/components/entity/entity.js +70 -0
- package/dist/components/entity/entity.meta.js +108 -0
- package/dist/components/entity/entity.variants.js +16 -0
- package/dist/components/entity/index.js +7 -0
- package/dist/components/feedback/feedback.js +93 -0
- package/dist/components/feedback/feedback.meta.js +109 -0
- package/dist/components/feedback/index.js +7 -0
- package/dist/components/fieldset/fieldset.js +80 -0
- package/dist/components/fieldset/fieldset.meta.js +160 -0
- package/dist/components/fieldset/index.js +17 -0
- package/dist/components/file-dropzone/file-dropzone.js +193 -0
- package/dist/components/file-dropzone/file-dropzone.meta.js +210 -0
- package/dist/components/file-dropzone/file-dropzone.variants.js +26 -0
- package/dist/components/file-dropzone/index.js +13 -0
- package/dist/components/font-picker/font-picker.js +77 -0
- package/dist/components/font-picker/font-picker.meta.js +119 -0
- package/dist/components/font-picker/index.js +7 -0
- package/dist/components/form/form.js +145 -0
- package/dist/components/form/form.meta.js +142 -0
- package/dist/components/form/index.js +11 -0
- package/dist/components/gliding-highlight/gliding-highlight.js +50 -0
- package/dist/components/gliding-highlight/gliding-highlight.meta.js +135 -0
- package/dist/components/gliding-highlight/index.js +9 -0
- package/dist/components/gradient-art/gradient-art.js +168 -0
- package/dist/components/gradient-art/gradient-art.meta.js +81 -0
- package/dist/components/gradient-art/index.js +7 -0
- package/dist/components/gradient-art/renderer.js +336 -0
- package/dist/components/inline-status/index.js +7 -0
- package/dist/components/inline-status/inline-status.js +33 -0
- package/dist/components/inline-status/inline-status.meta.js +83 -0
- package/dist/components/inline-status/inline-status.variants.js +18 -0
- package/dist/components/input/index.js +7 -0
- package/dist/components/input/input.js +33 -0
- package/dist/components/input/input.meta.js +155 -0
- package/dist/components/kbd/index.js +8 -0
- package/dist/components/kbd/kbd.js +54 -0
- package/dist/components/kbd/kbd.meta.js +95 -0
- package/dist/components/label/index.js +7 -0
- package/dist/components/label/label.js +51 -0
- package/dist/components/label/label.meta.js +98 -0
- package/dist/components/line-chart/index.js +7 -0
- package/dist/components/line-chart/line-chart.js +10 -0
- package/dist/components/line-chart/line-chart.meta.js +222 -0
- package/dist/components/marker/index.js +7 -0
- package/dist/components/marker/marker.js +39 -0
- package/dist/components/marker/marker.meta.js +132 -0
- package/dist/components/marker/marker.variants.js +25 -0
- package/dist/components/marquee/index.js +7 -0
- package/dist/components/marquee/marquee.js +146 -0
- package/dist/components/marquee/marquee.meta.js +106 -0
- package/dist/components/media-image/index.js +7 -0
- package/dist/components/media-image/media-image.js +56 -0
- package/dist/components/media-image/media-image.meta.js +92 -0
- package/dist/components/media-tile/index.js +7 -0
- package/dist/components/media-tile/media-tile.js +135 -0
- package/dist/components/media-tile/media-tile.meta.js +133 -0
- package/dist/components/media-tile/media-tile.variants.js +48 -0
- package/dist/components/menu/index.js +33 -0
- package/dist/components/menu/menu.js +168 -0
- package/dist/components/menu/menu.meta.js +176 -0
- package/dist/components/message/index.js +7 -0
- package/dist/components/message/message.js +83 -0
- package/dist/components/message/message.meta.js +150 -0
- package/dist/components/message/message.variants.js +41 -0
- package/dist/components/message-scroller/index.js +9 -0
- package/dist/components/message-scroller/message-scroller.js +300 -0
- package/dist/components/message-scroller/message-scroller.meta.js +172 -0
- package/dist/components/meter/index.js +20 -0
- package/dist/components/meter/meter.js +112 -0
- package/dist/components/meter/meter.meta.js +227 -0
- package/dist/components/meter/meter.variants.js +61 -0
- package/dist/components/middle-truncate/index.js +7 -0
- package/dist/components/middle-truncate/middle-truncate.js +28 -0
- package/dist/components/middle-truncate/middle-truncate.meta.js +77 -0
- package/dist/components/note/index.js +9 -0
- package/dist/components/note/note.js +73 -0
- package/dist/components/note/note.meta.js +112 -0
- package/dist/components/note/note.variants.js +22 -0
- package/dist/components/notification-badge/index.js +15 -0
- package/dist/components/notification-badge/notification-badge.js +48 -0
- package/dist/components/notification-badge/notification-badge.meta.js +107 -0
- package/dist/components/notification-badge/notification-badge.variants.js +57 -0
- package/dist/components/number-field/index.js +7 -0
- package/dist/components/number-field/number-field.js +70 -0
- package/dist/components/number-field/number-field.meta.js +109 -0
- package/dist/components/otp-field/index.js +7 -0
- package/dist/components/otp-field/otp-field.js +70 -0
- package/dist/components/otp-field/otp-field.meta.js +197 -0
- package/dist/components/overflow-menu/index.js +7 -0
- package/dist/components/overflow-menu/overflow-menu.js +26 -0
- package/dist/components/overflow-menu/overflow-menu.meta.js +100 -0
- package/dist/components/page-header/index.js +7 -0
- package/dist/components/page-header/page-header.js +34 -0
- package/dist/components/page-header/page-header.meta.js +104 -0
- package/dist/components/page-loader/index.js +7 -0
- package/dist/components/page-loader/page-loader.js +37 -0
- package/dist/components/page-loader/page-loader.meta.js +85 -0
- package/dist/components/pagination/index.js +7 -0
- package/dist/components/pagination/pagination.js +105 -0
- package/dist/components/pagination/pagination.meta.js +141 -0
- package/dist/components/panel-group/index.js +10 -0
- package/dist/components/panel-group/panel-group.js +168 -0
- package/dist/components/panel-group/panel-group.meta.js +153 -0
- package/dist/components/panel-section/index.js +9 -0
- package/dist/components/panel-section/panel-section.js +115 -0
- package/dist/components/panel-section/panel-section.meta.js +156 -0
- package/dist/components/phone/index.js +7 -0
- package/dist/components/phone/phone.js +50 -0
- package/dist/{chunk-KFZ43RKU.js → components/phone/phone.meta.js} +3 -50
- package/dist/{chunk-NEQNXI2G.js → components/phone/status-icons.js} +4 -4
- package/dist/components/pie-chart/index.js +7 -0
- package/dist/components/pie-chart/pie-chart.js +191 -0
- package/dist/components/pie-chart/pie-chart.meta.js +210 -0
- package/dist/components/pill/index.js +9 -0
- package/dist/components/pill/pill.js +24 -0
- package/dist/components/pill/pill.meta.js +108 -0
- package/dist/components/pill/pill.variants.js +65 -0
- package/dist/components/popover/index.js +23 -0
- package/dist/components/popover/popover.js +100 -0
- package/dist/components/popover/popover.meta.js +136 -0
- package/dist/components/progress/index.js +19 -0
- package/dist/components/progress/progress.js +70 -0
- package/dist/components/progress/progress.meta.js +171 -0
- package/dist/components/progress/progress.variants.js +17 -0
- package/dist/components/radar-chart/index.js +7 -0
- package/dist/components/radar-chart/radar-chart.js +161 -0
- package/dist/components/radar-chart/radar-chart.meta.js +204 -0
- package/dist/components/radial-chart/index.js +7 -0
- package/dist/components/radial-chart/radial-chart.js +175 -0
- package/dist/components/radial-chart/radial-chart.meta.js +216 -0
- package/dist/components/radio/index.js +8 -0
- package/dist/components/radio/radio.js +39 -0
- package/dist/components/radio/radio.meta.js +104 -0
- package/dist/components/radio-card/index.js +7 -0
- package/dist/components/radio-card/radio-card.js +81 -0
- package/dist/components/radio-card/radio-card.meta.js +144 -0
- package/dist/components/radio-card/radio-card.variants.js +43 -0
- package/dist/components/relative-time/index.js +7 -0
- package/dist/components/relative-time/relative-time.js +47 -0
- package/dist/components/relative-time/relative-time.meta.js +77 -0
- package/dist/components/scroller/index.js +7 -0
- package/dist/components/scroller/scroller.js +111 -0
- package/dist/components/scroller/scroller.meta.js +118 -0
- package/dist/components/scrub-field/index.js +7 -0
- package/dist/components/scrub-field/scrub-field.js +124 -0
- package/dist/components/scrub-field/scrub-field.meta.js +139 -0
- package/dist/components/search-input/index.js +7 -0
- package/dist/components/search-input/search-input.js +91 -0
- package/dist/components/search-input/search-input.meta.js +129 -0
- package/dist/components/section-header/index.js +7 -0
- package/dist/components/section-header/section-header.js +39 -0
- package/dist/components/section-header/section-header.meta.js +174 -0
- package/dist/components/segmented-bar/index.js +14 -0
- package/dist/components/segmented-bar/segmented-bar.js +26 -0
- package/dist/components/segmented-bar/segmented-bar.meta.js +108 -0
- package/dist/components/segmented-bar/segmented-bar.variants.js +39 -0
- package/dist/components/select/index.js +25 -0
- package/dist/components/select/select.js +191 -0
- package/dist/components/select/select.meta.js +189 -0
- package/dist/components/separator/index.js +7 -0
- package/dist/components/separator/separator.js +42 -0
- package/dist/components/separator/separator.meta.js +84 -0
- package/dist/components/settings-menu/index.js +11 -0
- package/dist/components/settings-menu/settings-menu.js +101 -0
- package/dist/components/settings-menu/settings-menu.meta.js +177 -0
- package/dist/components/settings-menu/settings-menu.variants.js +15 -0
- package/dist/components/sheet/index.js +29 -0
- package/dist/components/sheet/sheet.js +121 -0
- package/dist/components/sheet/sheet.meta.js +167 -0
- package/dist/components/sheet/sheet.variants.js +21 -0
- package/dist/components/show-more/index.js +7 -0
- package/dist/components/show-more/show-more.js +87 -0
- package/dist/components/show-more/show-more.meta.js +79 -0
- package/dist/components/side-nav/index.js +13 -0
- package/dist/components/side-nav/side-nav.js +75 -0
- package/dist/components/side-nav/side-nav.meta.js +139 -0
- package/dist/components/side-nav/side-nav.variants.js +33 -0
- package/dist/components/sidebar/index.js +21 -0
- package/dist/components/sidebar/sidebar.js +196 -0
- package/dist/components/sidebar/sidebar.meta.js +118 -0
- package/dist/components/skeleton/index.js +7 -0
- package/dist/components/skeleton/skeleton.js +16 -0
- package/dist/components/skeleton/skeleton.meta.js +90 -0
- package/dist/components/slider/index.js +21 -0
- package/dist/components/slider/slider.js +115 -0
- package/dist/components/slider/slider.meta.js +214 -0
- package/dist/components/sparkline/index.js +7 -0
- package/dist/components/sparkline/sparkline.js +84 -0
- package/dist/components/sparkline/sparkline.meta.js +147 -0
- package/dist/components/spinner/index.js +7 -0
- package/dist/components/spinner/spinner.js +59 -0
- package/dist/components/spinner/spinner.meta.js +118 -0
- package/dist/components/status-bar/index.js +9 -0
- package/dist/components/status-bar/status-bar.js +40 -0
- package/dist/components/status-bar/status-bar.meta.js +117 -0
- package/dist/components/status-dot/index.js +9 -0
- package/dist/components/status-dot/status-dot.js +40 -0
- package/dist/components/status-dot/status-dot.meta.js +113 -0
- package/dist/components/status-dot/status-dot.variants.js +28 -0
- package/dist/components/stepper/index.js +17 -0
- package/dist/components/stepper/stepper.js +161 -0
- package/dist/components/stepper/stepper.meta.js +190 -0
- package/dist/components/stepper/stepper.variants.js +72 -0
- package/dist/components/streaming-text/index.js +7 -0
- package/dist/components/streaming-text/streaming-text.js +55 -0
- package/dist/components/streaming-text/streaming-text.meta.js +147 -0
- package/dist/components/switch/index.js +7 -0
- package/dist/components/switch/switch.js +26 -0
- package/dist/components/switch/switch.meta.js +133 -0
- package/dist/components/table/index.js +23 -0
- package/dist/components/table/table.js +117 -0
- package/dist/components/table/table.meta.js +143 -0
- package/dist/components/tabs/index.js +17 -0
- package/dist/components/tabs/tabs.js +58 -0
- package/dist/components/tabs/tabs.meta.js +120 -0
- package/dist/components/textarea/index.js +7 -0
- package/dist/components/textarea/textarea.js +38 -0
- package/dist/components/textarea/textarea.meta.js +117 -0
- package/dist/components/theme-selector/index.js +11 -0
- package/dist/components/theme-selector/theme-selector.js +145 -0
- package/dist/components/theme-selector/theme-selector.meta.js +181 -0
- package/dist/components/theme-switcher/index.js +7 -0
- package/dist/components/theme-switcher/theme-switcher.js +106 -0
- package/dist/components/theme-switcher/theme-switcher.meta.js +99 -0
- package/dist/components/thinking-orb/index.js +9 -0
- package/dist/components/thinking-orb/thinking-orb.js +126 -0
- package/dist/components/thinking-orb/thinking-orb.meta.js +142 -0
- package/dist/components/thinking-orb/thinking-orb.render.js +252 -0
- package/dist/components/toast/index.js +29 -0
- package/dist/components/toast/toast.js +254 -0
- package/dist/components/toast/toast.meta.js +261 -0
- package/dist/components/toggle/index.js +13 -0
- package/dist/components/toggle/toggle.js +51 -0
- package/dist/components/toggle/toggle.meta.js +129 -0
- package/dist/components/toolbar/index.js +27 -0
- package/dist/components/toolbar/toolbar.js +80 -0
- package/dist/components/toolbar/toolbar.meta.js +272 -0
- package/dist/components/toolbar/toolbar.variants.js +16 -0
- package/dist/components/tooltip/index.js +21 -0
- package/dist/components/tooltip/tooltip.js +74 -0
- package/dist/components/tooltip/tooltip.meta.js +156 -0
- package/dist/components/tree/index.js +12 -0
- package/dist/components/tree/tree.js +364 -0
- package/dist/components/tree/tree.meta.js +334 -0
- package/dist/components/video/index.js +7 -0
- package/dist/components/video/video.js +59 -0
- package/dist/components/video/video.meta.js +81 -0
- package/dist/components/workspace/index.js +9 -0
- package/dist/components/workspace/workspace.js +79 -0
- package/dist/components/workspace/workspace.meta.js +183 -0
- package/dist/foundations/accessibility.js +107 -0
- package/dist/foundations/index.js +25 -792
- package/dist/foundations/motion.js +135 -0
- package/dist/foundations/scrolling.js +62 -0
- package/dist/foundations/shape.js +113 -0
- package/dist/foundations/spacing.js +121 -0
- package/dist/foundations/surfaces.js +107 -0
- package/dist/foundations/types.js +0 -0
- package/dist/foundations/typography.js +152 -0
- package/dist/icon/Icon.js +30 -0
- package/dist/icon/IconProvider.js +27 -0
- package/dist/icon/compose.js +13 -0
- package/dist/icon/index.d.ts +13 -5
- package/dist/icon/index.js +13 -2
- package/dist/icon/registry.js +0 -0
- package/dist/icon-sets/brands.generated.js +123 -0
- package/dist/icon-sets/brands.js +10 -123
- package/dist/icon-sets/reicon.d.ts +3 -1
- package/dist/icon-sets/reicon.js +209 -1
- package/dist/index.d.ts +611 -33
- package/dist/index.js +211 -11351
- package/dist/ios/chrome.js +36 -0
- package/dist/ios/index.js +19 -315
- package/dist/ios/liquid-glass.js +103 -0
- package/dist/ios/native-app.js +46 -0
- package/dist/ios/navigation.js +63 -0
- package/dist/ios/phone-frame.js +64 -0
- package/dist/ios/preview-theme.js +83 -0
- package/dist/ios/preview.js +10 -137
- package/dist/ios/sheet.js +85 -0
- package/dist/ios/theme.js +19 -0
- package/dist/layout/AspectBox.js +27 -0
- package/dist/layout/Bleed.js +15 -0
- package/dist/layout/Center.js +21 -0
- package/dist/layout/Columns.js +70 -0
- package/dist/layout/Grid.js +50 -0
- package/dist/layout/GridOverlay.js +41 -0
- package/dist/layout/Page.js +11 -0
- package/dist/layout/Region.js +39 -0
- package/dist/layout/Row.js +45 -0
- package/dist/layout/SafeArea.js +26 -0
- package/dist/layout/Spacer.js +9 -0
- package/dist/layout/SplitPane.js +55 -0
- package/dist/layout/Stack.js +42 -0
- package/dist/layout/_responsive.js +16 -0
- package/dist/layout/_safeArea.js +18 -0
- package/dist/layout/index.d.ts +25 -6
- package/dist/layout/index.js +14 -2
- package/dist/lib/anchored-scroll.js +7 -0
- package/dist/lib/bleed.js +7 -0
- package/dist/lib/chart/cartesian.js +365 -0
- package/dist/lib/chart/chart-frame.js +163 -0
- package/dist/lib/chart/chart-legend.js +13 -0
- package/dist/lib/chart/chart-tooltip.js +38 -0
- package/dist/lib/chart/format.js +19 -0
- package/dist/lib/chart/geometry.js +114 -0
- package/dist/lib/chart/motion.js +34 -0
- package/dist/lib/chart/scale.js +72 -0
- package/dist/lib/chart/types.js +45 -0
- package/dist/lib/chart/use-arrival.js +41 -0
- package/dist/{chunk-SRQWQUTW.js → lib/cn.js} +5 -5
- package/dist/lib/component-guidance.js +210 -0
- package/dist/lib/density.js +54 -0
- package/dist/lib/field-shell.js +11 -0
- package/dist/lib/glyphs.js +9 -0
- package/dist/lib/heading-row.js +36 -0
- package/dist/lib/highlight-glide.js +84 -0
- package/dist/lib/hit-target.js +5 -0
- package/dist/lib/meta.js +0 -0
- package/dist/lib/portal-theme-scope.js +74 -0
- package/dist/{chunk-FKZXAFIY.js → lib/presentation.js} +8 -3
- package/dist/lib/refs.js +14 -0
- package/dist/lib/scrub-gesture.js +50 -0
- package/dist/lib/segmented.js +13 -0
- package/dist/lib/selection-card.js +41 -0
- package/dist/lib/status-tone.js +13 -0
- package/dist/lib/taxonomy.js +214 -0
- package/dist/lib/trim-label.js +20 -0
- package/dist/lib/use-copy.js +27 -0
- package/dist/lib/use-edge-fade.js +32 -0
- package/dist/lib/use-isomorphic-layout-effect.js +8 -0
- package/dist/lib/use-resize-observer.js +18 -0
- package/dist/lib/use-scroll-activity.js +52 -0
- package/dist/lib/use-wheel-to-horizontal.js +65 -0
- package/dist/motion/MotionProvider.js +75 -0
- package/dist/motion/Presence.js +112 -0
- package/dist/motion/Reveal.js +42 -0
- package/dist/motion/TextReveal.js +61 -0
- package/dist/motion/index.js +24 -0
- package/dist/motion/useInView.js +36 -0
- package/dist/motion/useReducedMotion.js +25 -0
- package/dist/motion/viewTransition.js +47 -0
- package/dist/patterns/auth-page.js +90 -0
- package/dist/patterns/auth-page.meta.js +27 -0
- package/dist/patterns/brand-landing-page.js +341 -0
- package/dist/patterns/brand-landing-page.meta.js +28 -0
- package/dist/patterns/chat-panel.js +185 -0
- package/dist/patterns/chat-panel.meta.js +31 -0
- package/dist/patterns/dashboard-page.js +332 -0
- package/dist/patterns/dashboard-page.meta.js +29 -0
- package/dist/patterns/feed-page.js +205 -0
- package/dist/patterns/feed-page.meta.js +25 -0
- package/dist/patterns/index.js +34 -2140
- package/dist/patterns/landing-page.js +356 -0
- package/dist/patterns/landing-page.meta.js +26 -0
- package/dist/patterns/list-detail-page.js +373 -0
- package/dist/patterns/list-detail-page.meta.js +24 -0
- package/dist/patterns/settings-page.js +268 -0
- package/dist/patterns/settings-page.meta.js +27 -0
- package/dist/presets/index.js +43 -185
- package/dist/styles.css +118 -3
- package/dist/{theme-provider-kQszHYji.d.ts → theme-provider-S0NVJs2Y.d.ts} +6 -1
- package/dist/{chunk-NETUFI34.js → themes/_contract.js} +14 -2
- package/dist/themes/atelier/index.js +17 -1
- package/dist/themes/contrast.js +288 -0
- package/dist/themes/ember/ember.css +6 -6
- package/dist/themes/ember/index.js +16 -1
- package/dist/themes/index.d.ts +1 -1
- package/dist/themes/index.js +3 -8
- package/dist/themes/meridian/index.js +16 -1
- package/dist/themes/poppy/index.js +17 -1
- package/dist/themes/prism/index.js +17 -1
- package/dist/themes/prism/prism.css +2 -2
- package/dist/themes/registry.js +59 -0
- package/dist/themes/sable/index.js +16 -1
- package/dist/{chunk-EFLC4NA3.js → themes/theme-provider.js} +38 -54
- package/dist/themes/verdant/index.js +17 -1
- package/llms/blocks/media-player-block.md +20 -7
- package/llms/blocks/product-card-block.md +6 -4
- package/llms/blocks/task-list-block.md +1 -1
- package/llms/blocks/verify-code-block.md +1 -1
- package/llms/components/app-shell.md +5 -2
- package/llms/components/avatar.md +25 -3
- package/llms/components/button.md +20 -1
- package/llms/components/card.md +1 -1
- package/llms/components/disclosure-picker.md +168 -0
- package/llms/components/font-picker.md +104 -0
- package/llms/components/media-image.md +98 -0
- package/llms/components/media-tile.md +143 -0
- package/llms/components/page-header.md +6 -5
- package/llms/components/section-header.md +144 -0
- package/llms/components/sheet.md +10 -0
- package/llms/components/sidebar.md +4 -3
- package/llms/components/slider.md +14 -2
- package/llms/components/theme-selector.md +44 -4
- package/llms/components/tree.md +3 -3
- package/llms/layout/grid.md +24 -3
- package/llms/patterns/dashboard-page.md +3 -6
- package/llms/patterns/feed-page.md +4 -4
- package/llms/patterns/list-detail-page.md +1 -0
- package/llms/patterns/settings-page.md +2 -5
- package/llms/reference/utilities.md +84 -4
- package/llms/tasks/converting-an-app.md +14 -4
- package/llms/tasks/reviewing-a-design.md +15 -0
- package/llms-full.txt +980 -64
- package/llms.txt +26 -9
- package/package.json +1 -1
- package/registry.json +2324 -171
- package/scripts/agent-setup.mjs +90 -0
- package/scripts/design-presets.mjs +46 -4
- package/scripts/grade.mjs +195 -29
- package/scripts/lint-rules.mjs +486 -10
- package/scripts/review-evidence.mjs +28 -1
- package/skills/sable/SKILL.md +56 -22
- package/targets/ios.json +45 -0
- package/dist/chunk-3IWZYBGH.js +0 -398
- package/dist/chunk-7MG4SHYX.js +0 -15
- package/dist/chunk-7QSDYBXO.js +0 -7421
- package/dist/chunk-ADLLDWLW.js +0 -15
- package/dist/chunk-C4Z3CF54.js +0 -15
- package/dist/chunk-EDXLM7YL.js +0 -5078
- package/dist/chunk-EHH4MHO6.js +0 -14
- package/dist/chunk-K7RUHUGC.js +0 -14
- package/dist/chunk-KO3NAEBF.js +0 -15
- package/dist/chunk-L4IEIQQA.js +0 -14
- package/dist/chunk-QJ6FWTUG.js +0 -40
- package/dist/chunk-VVW4UCDI.js +0 -4908
- package/dist/chunk-XAZGMY73.js +0 -187
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/components/relative-time/relative-time.tsx
|
|
2
|
+
import { format, formatDistanceToNow } from "date-fns";
|
|
3
|
+
import { cn } from "../../lib/cn.js";
|
|
4
|
+
import {
|
|
5
|
+
Tooltip,
|
|
6
|
+
TooltipContent,
|
|
7
|
+
TooltipTrigger
|
|
8
|
+
} from "../tooltip/index.js";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
function toDate(date) {
|
|
11
|
+
return date instanceof Date ? date : new Date(date);
|
|
12
|
+
}
|
|
13
|
+
function RelativeTime({ date, className, ...props }) {
|
|
14
|
+
const parsed = toDate(date);
|
|
15
|
+
const relative = formatDistanceToNow(parsed, { addSuffix: true });
|
|
16
|
+
const absolute = format(parsed, "PPpp");
|
|
17
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
18
|
+
/* @__PURE__ */ jsx(
|
|
19
|
+
TooltipTrigger,
|
|
20
|
+
{
|
|
21
|
+
render: (
|
|
22
|
+
// design-lint-disable-next-line static-interactive -- the only hover change is text-decoration, which motion-interactive does not list and CSS cannot tween: text-decoration-line is discrete, so the underline lands in one frame either way. Adding the recipe would declare a transition that animates nothing and imply the snap had been handled.
|
|
23
|
+
/* @__PURE__ */ jsx(
|
|
24
|
+
"time",
|
|
25
|
+
{
|
|
26
|
+
dateTime: parsed.toISOString(),
|
|
27
|
+
tabIndex: 0,
|
|
28
|
+
className: cn(
|
|
29
|
+
// No type size of its own: it inherits the line it sits in (a
|
|
30
|
+
// feed meta row, a message header), so it never jumps a tier.
|
|
31
|
+
"rounded-xs underline-offset-2 decoration-dotted hover:underline focus-visible:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
32
|
+
className
|
|
33
|
+
),
|
|
34
|
+
...props
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
),
|
|
38
|
+
children: relative
|
|
39
|
+
}
|
|
40
|
+
),
|
|
41
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: absolute })
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
RelativeTime.displayName = "RelativeTime";
|
|
45
|
+
export {
|
|
46
|
+
RelativeTime
|
|
47
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// src/components/relative-time/relative-time.meta.ts
|
|
2
|
+
var relativeTimeMeta = {
|
|
3
|
+
name: "RelativeTime",
|
|
4
|
+
summary: `A human relative timestamp (e.g. "3 minutes ago") that reveals the full absolute date/time on hover or focus. Renders a native <time> element wrapped in our Tooltip; the absolute time is formatted with date-fns format(date, 'PPpp') (e.g. "Apr 29, 2025, 4:05:12 PM").`,
|
|
5
|
+
status: "stable",
|
|
6
|
+
keywords: [
|
|
7
|
+
"relative time",
|
|
8
|
+
"timestamp",
|
|
9
|
+
"time ago",
|
|
10
|
+
"date"
|
|
11
|
+
],
|
|
12
|
+
usage: {
|
|
13
|
+
description: "Use RelativeTime to show recent activity or timestamps in conversational relative language.",
|
|
14
|
+
bestPractices: [
|
|
15
|
+
{
|
|
16
|
+
guidance: "do",
|
|
17
|
+
description: "Use it for feeds, audit summaries, comments, and activity streams."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
guidance: "do",
|
|
21
|
+
description: "Expose the exact timestamp when precision matters."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
guidance: "dont",
|
|
25
|
+
description: "Do not use RelativeTime as the only date format for legal, billing, or audit-critical records."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
guidance: "dont",
|
|
29
|
+
description: `Do not render it during SSR without a stable absolute fallback. "2 minutes ago" computed on the server differs from the client's value, which is a hydration mismatch \u2014 and it silently drifts as the page sits open.`
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
related: {
|
|
34
|
+
components: [
|
|
35
|
+
"InlineStatus",
|
|
36
|
+
"Table"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
props: [
|
|
40
|
+
{
|
|
41
|
+
name: "date",
|
|
42
|
+
type: "Date | string | number",
|
|
43
|
+
description: "The instant to render. Accepts a Date, an ISO/parseable string, or an epoch number (ms). Coerced to a Date for date-fns."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "className",
|
|
47
|
+
type: "string",
|
|
48
|
+
description: "Merged onto the <time> trigger element (the visible relative label)."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "...time props",
|
|
52
|
+
type: 'Omit<ComponentPropsWithRef<"time">, "dateTime" | "children">',
|
|
53
|
+
description: "Remaining native <time> attributes pass through to the trigger. dateTime is set automatically from the parsed ISO value."
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
tokensUsed: ["popover", "popover-foreground", "border", "ring"],
|
|
57
|
+
a11y: [
|
|
58
|
+
"Renders a semantic <time> element with a machine-readable dateTime (ISO) attribute.",
|
|
59
|
+
"The <time> carries tabIndex=0 (it is not focusable natively), so the absolute time \u2014 exposed via Base UI's Tooltip, which opens on keyboard focus as well as hover and wires aria-describedby \u2014 is reachable from the keyboard.",
|
|
60
|
+
"It inherits the type size of the surrounding text rather than setting its own, so it sits inside a meta row or message header without changing tier.",
|
|
61
|
+
"Wrap the page or a group in <TooltipProvider> to share open/close delays.",
|
|
62
|
+
"Relative phrasing is supplementary; the dateTime attribute remains the canonical machine value."
|
|
63
|
+
],
|
|
64
|
+
examples: [
|
|
65
|
+
{
|
|
66
|
+
label: "Basic",
|
|
67
|
+
code: "<TooltipProvider><RelativeTime date={new Date()} /></TooltipProvider>"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
label: "From an ISO string",
|
|
71
|
+
code: '<TooltipProvider><RelativeTime date="2025-04-29T16:05:12Z" /></TooltipProvider>'
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
};
|
|
75
|
+
export {
|
|
76
|
+
relativeTimeMeta
|
|
77
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/scroller/scroller.tsx
|
|
4
|
+
import { useCallback, useRef } from "react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
import { setRef } from "../../lib/refs.js";
|
|
7
|
+
import { useEdgeFade } from "../../lib/use-edge-fade.js";
|
|
8
|
+
import { useScrollActivity } from "../../lib/use-scroll-activity.js";
|
|
9
|
+
import {
|
|
10
|
+
scrollRegionKeyDown,
|
|
11
|
+
useWheelToHorizontal
|
|
12
|
+
} from "../../lib/use-wheel-to-horizontal.js";
|
|
13
|
+
import { jsx } from "react/jsx-runtime";
|
|
14
|
+
function Scroller({
|
|
15
|
+
orientation = "vertical",
|
|
16
|
+
wheelScroll = true,
|
|
17
|
+
label,
|
|
18
|
+
className,
|
|
19
|
+
viewportClassName,
|
|
20
|
+
children,
|
|
21
|
+
ref,
|
|
22
|
+
style,
|
|
23
|
+
onScroll,
|
|
24
|
+
onKeyDown,
|
|
25
|
+
...props
|
|
26
|
+
}) {
|
|
27
|
+
const regionRef = useRef(null);
|
|
28
|
+
const isHorizontal = orientation === "horizontal";
|
|
29
|
+
const trackActivity = useScrollActivity();
|
|
30
|
+
const trackWheel = useWheelToHorizontal(isHorizontal && wheelScroll);
|
|
31
|
+
const setRegion = useCallback(
|
|
32
|
+
(node) => {
|
|
33
|
+
setRef(ref, node);
|
|
34
|
+
trackActivity(node);
|
|
35
|
+
trackWheel(node);
|
|
36
|
+
regionRef.current = node;
|
|
37
|
+
},
|
|
38
|
+
[ref, trackActivity, trackWheel]
|
|
39
|
+
);
|
|
40
|
+
const handleKeyDown = useCallback(
|
|
41
|
+
(event) => {
|
|
42
|
+
onKeyDown?.(event);
|
|
43
|
+
if (event.defaultPrevented) return;
|
|
44
|
+
scrollRegionKeyDown(event, orientation);
|
|
45
|
+
},
|
|
46
|
+
[onKeyDown, orientation]
|
|
47
|
+
);
|
|
48
|
+
const { sync: syncFade, style: fadeStyle } = useEdgeFade(regionRef, orientation);
|
|
49
|
+
const handleScroll = useCallback(
|
|
50
|
+
(event) => {
|
|
51
|
+
syncFade();
|
|
52
|
+
onScroll?.(event);
|
|
53
|
+
},
|
|
54
|
+
[syncFade, onScroll]
|
|
55
|
+
);
|
|
56
|
+
const isVertical = orientation === "vertical";
|
|
57
|
+
return (
|
|
58
|
+
// The chrome box. Carries the consumer's border/background/radius and the
|
|
59
|
+
// sizing, and is NOT masked — which is the entire point of the split. A
|
|
60
|
+
// flex column so the scroller below can be `flex-1 min-h-0`, which bounds
|
|
61
|
+
// off `h-*`, `max-h-*` and `flex-1` alike with no percentage to resolve.
|
|
62
|
+
/* @__PURE__ */ jsx("div", { style, className: cn("flex flex-col", className), children: /* @__PURE__ */ jsx(
|
|
63
|
+
"div",
|
|
64
|
+
{
|
|
65
|
+
ref: setRegion,
|
|
66
|
+
onScroll: handleScroll,
|
|
67
|
+
onKeyDown: handleKeyDown,
|
|
68
|
+
tabIndex: 0,
|
|
69
|
+
role: "group",
|
|
70
|
+
"aria-label": label,
|
|
71
|
+
"data-orientation": orientation,
|
|
72
|
+
style: fadeStyle,
|
|
73
|
+
className: cn(
|
|
74
|
+
// Fill the chrome box without a percentage height. `min-h-0` /
|
|
75
|
+
// `min-w-0` because a flex item's default `min-size: auto` refuses to
|
|
76
|
+
// shrink below its content — which is exactly how a scroll region
|
|
77
|
+
// silently stops scrolling.
|
|
78
|
+
"min-h-0 min-w-0 flex-1",
|
|
79
|
+
// Inherit the wrapper's radius so content clips to the same curve the
|
|
80
|
+
// border draws; a scroll container already clips to its own padding
|
|
81
|
+
// box, so this needs no `overflow-hidden` fighting the scroll axis.
|
|
82
|
+
"rounded-[inherit]",
|
|
83
|
+
"motion-interactive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
84
|
+
// Contained overscroll: a Scroller is almost always a bounded region
|
|
85
|
+
// inside a page or a popup, and a wheel gesture that reaches its end
|
|
86
|
+
// should stop rather than start scrolling whatever is behind it.
|
|
87
|
+
"overscroll-contain",
|
|
88
|
+
isVertical ? (
|
|
89
|
+
// Vertical: a thin bar, revealed while scrolling. The fade says
|
|
90
|
+
// "more below"; the bar says how much and where you are — a long
|
|
91
|
+
// list needs both.
|
|
92
|
+
"scrollbar-quiet overflow-y-auto overflow-x-hidden"
|
|
93
|
+
) : (
|
|
94
|
+
// Horizontal: no bar at all. The edge fades this component already
|
|
95
|
+
// draws ARE the affordance, and they say the same thing better —
|
|
96
|
+
// which is the carousel read a media strip or chip row wants. A
|
|
97
|
+
// 4px rail under a row of tiles adds chrome and no information.
|
|
98
|
+
"scrollbar-hidden overflow-x-auto overflow-y-hidden"
|
|
99
|
+
),
|
|
100
|
+
viewportClassName
|
|
101
|
+
),
|
|
102
|
+
...props,
|
|
103
|
+
children
|
|
104
|
+
}
|
|
105
|
+
) })
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
Scroller.displayName = "Scroller";
|
|
109
|
+
export {
|
|
110
|
+
Scroller
|
|
111
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// src/components/scroller/scroller.meta.ts
|
|
2
|
+
var scrollerMeta = {
|
|
3
|
+
name: "Scroller",
|
|
4
|
+
summary: "Scroll container that fades its leading/trailing edges when content overflows. Tracks scroll position to toggle the fades.",
|
|
5
|
+
status: "stable",
|
|
6
|
+
keywords: [
|
|
7
|
+
"scroller",
|
|
8
|
+
"overflow",
|
|
9
|
+
"horizontal scroll",
|
|
10
|
+
"carousel"
|
|
11
|
+
],
|
|
12
|
+
usage: {
|
|
13
|
+
description: "Use Scroller to create a contained overflow region for content that naturally extends beyond the viewport.",
|
|
14
|
+
bestPractices: [
|
|
15
|
+
{
|
|
16
|
+
guidance: "do",
|
|
17
|
+
description: "Use it for chip rows, media strips, or comparison sets where horizontal browsing is expected."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
guidance: "do",
|
|
21
|
+
description: "Keep scroll affordances visible enough that overflow is discoverable."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
guidance: "do",
|
|
25
|
+
description: "Put everything on `className` \u2014 sizing (`max-h-80`, `h-64`, `flex-1 min-h-0`) and chrome (`rounded-lg border`, `bg-card`) alike. It styles the Scroller's outer box, and the scrolling element inside it is `flex-1 min-h-0`, so a cap on the Scroller is still a cap on what scrolls."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
guidance: "do",
|
|
29
|
+
description: 'Pass `label` on any Scroller with real content. It is a focusable region, and an unnamed one announces as a bare group \u2014 "Tags" or "Recent covers" costs a word and is the difference between navigable and not.'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
guidance: "dont",
|
|
33
|
+
description: "Do not use Scroller to hide primary page layout or required controls."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
guidance: "dont",
|
|
37
|
+
description: "Do not add your own wheel handler to make a horizontal strip mouse-scrollable \u2014 it already is. A second handler double-scrolls and usually loses the end-release, which traps the page."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
guidance: "dont",
|
|
41
|
+
description: "Do not reach past it with a child selector (`[&>div]:snap-x`). The scrolling element is addressable by name: `viewportClassName`."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
guidance: "dont",
|
|
45
|
+
description: "Do not use it to hide overflow you should have laid out. It exists to make an intentionally scrolling strip legible, not to contain content that overflowed by accident."
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
related: {
|
|
50
|
+
components: [
|
|
51
|
+
"Carousel",
|
|
52
|
+
"Marquee"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
props: [
|
|
56
|
+
{
|
|
57
|
+
name: "orientation",
|
|
58
|
+
type: '"vertical" | "horizontal"',
|
|
59
|
+
default: '"vertical"',
|
|
60
|
+
description: '"vertical" scrolls and fades top/bottom; "horizontal" scrolls and fades left/right.'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "wheelScroll",
|
|
64
|
+
type: "boolean",
|
|
65
|
+
default: "true",
|
|
66
|
+
description: "On a horizontal Scroller, let a vertical mouse wheel scroll it sideways. Ignored when vertical. Turn it off only if the region is inside something that owns the wheel itself (a map, a canvas)."
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "label",
|
|
70
|
+
type: "string",
|
|
71
|
+
description: "Accessible name for the scroll region. The region takes focus, so it should say what it contains; without one a screen reader announces an unnamed group."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "viewportClassName",
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "Classes for the inner element that actually scrolls. Narrow on purpose \u2014 `className` is what you want almost always. This is for the few utilities that only mean something on the scrolling box: `snap-x`, `scroll-smooth`, `scroll-p-*`."
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "...div props",
|
|
80
|
+
type: "ComponentPropsWithRef<'div'>",
|
|
81
|
+
description: "Everything except `className`/`style` spreads onto the SCROLLING element \u2014 `role`, `id`, `aria-*`, `data-*` and event handlers all describe the thing that scrolls, and CommandMenu relies on it to make this component its listbox. `ref` and `onScroll` likewise address the scroller, and compose with the component's own."
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
variants: {
|
|
85
|
+
orientation: ["vertical", "horizontal"],
|
|
86
|
+
wheelScroll: ["true", "false"]
|
|
87
|
+
},
|
|
88
|
+
tokensUsed: ["ring"],
|
|
89
|
+
a11y: [
|
|
90
|
+
"The edge fades are a CSS mask-image on the scrolling element, not overlay elements \u2014 there is nothing in the DOM to intercept a pointer or be read by assistive tech, and the content under a fade stays fully interactive.",
|
|
91
|
+
'Two boxes: a chrome box carrying `className` (border, background, radius, sizing) and, inside it, the element that actually scrolls and carries the fade mask. They are split because a `mask-image` applies to its element\'s own border \u2014 so with both on one box, a bordered Scroller watched its frame dissolve at the scrolling edge. The axis is published as `data-orientation`, not `aria-orientation`, which is invalid on `role="group"`.',
|
|
92
|
+
"The scroll region uses native overflow and contains overscroll, so a gesture that runs out of content does not scroll the page behind it.",
|
|
93
|
+
'It is focusable (`tabIndex=0`, `role="group"`) and handles arrows, Home/End and PageUp/PageDown along its own axis. Chrome 128+ and Firefox make scrollable regions focusable on their own; Safari does not, so a strip with a hidden scrollbar and no focusable children is unreachable there. Declaring it makes the behaviour a property of the component, not of the reader\'s browser. Pass `label` to name it \u2014 an unnamed focusable region announces as a bare group.',
|
|
94
|
+
"On a horizontal Scroller, a vertical mouse wheel scrolls it sideways, because most mice have no horizontal wheel and the content past the fold is otherwise unreachable on them. The strip releases the wheel at both ends so it never traps the page, and leaves trackpad `deltaX` gestures and `shift+wheel` to the browser.",
|
|
95
|
+
"Cross-axis arrow keys are deliberately not captured, and a consumer can take the arrows entirely by calling `preventDefault()` in their own `onKeyDown` \u2014 a strip of interactive chips usually wants them for roving focus."
|
|
96
|
+
],
|
|
97
|
+
examples: [
|
|
98
|
+
{
|
|
99
|
+
label: "Vertical with overflow",
|
|
100
|
+
code: '<Scroller label="Editions" className="h-64"><ul className="space-y-2 p-4">{items.map((item) => (<li key={item.id} className="text-body-sm">{item.title}</li>))}</ul></Scroller>'
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
label: "Capped, scrolls past the cap",
|
|
104
|
+
code: '<Scroller label="Versions" className="max-h-80 rounded-md border border-border"><ul className="divide-y divide-border">{versions.map((v) => (<li key={v.id} className="px-3 py-2 text-body-sm">{v.label}</li>))}</ul></Scroller>'
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
label: "Horizontal",
|
|
108
|
+
code: '<Scroller orientation="horizontal" label="Recent covers" className="w-full"><div className="flex gap-3 p-4">{covers.map((src) => (<img key={src} src={src} alt="" className="h-32 w-32 rounded-lg object-cover" />))}</div></Scroller>'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
label: "Snap points on the scrolling box",
|
|
112
|
+
code: '<Scroller orientation="horizontal" label="Covers" className="w-full rounded-lg border border-border" viewportClassName="snap-x snap-mandatory scroll-smooth"><div className="flex gap-3 p-4">{covers.map((src) => (<img key={src} src={src} alt="" className="h-32 w-32 snap-start rounded-lg object-cover" />))}</div></Scroller>'
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
};
|
|
116
|
+
export {
|
|
117
|
+
scrollerMeta
|
|
118
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/scrub-field/scrub-field.tsx
|
|
4
|
+
import { useRef, useState } from "react";
|
|
5
|
+
import { Icon } from "../../icon/index.js";
|
|
6
|
+
import { cn } from "../../lib/cn.js";
|
|
7
|
+
import { FIELD_SHELL_XS } from "../../lib/field-shell.js";
|
|
8
|
+
import { beginScrub } from "../../lib/scrub-gesture.js";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
function ScrubField({
|
|
11
|
+
value,
|
|
12
|
+
onValueChange,
|
|
13
|
+
min,
|
|
14
|
+
max,
|
|
15
|
+
step = 1,
|
|
16
|
+
label,
|
|
17
|
+
icon,
|
|
18
|
+
prefix,
|
|
19
|
+
suffix,
|
|
20
|
+
onGestureStart,
|
|
21
|
+
onGestureEnd,
|
|
22
|
+
disabled,
|
|
23
|
+
id,
|
|
24
|
+
className
|
|
25
|
+
}) {
|
|
26
|
+
const [draft, setDraft] = useState(null);
|
|
27
|
+
const inputRef = useRef(null);
|
|
28
|
+
const decimals = step < 1 ? String(step).split(".")[1]?.length ?? 0 : 0;
|
|
29
|
+
function clamp(n) {
|
|
30
|
+
let out = n;
|
|
31
|
+
if (min !== void 0) out = Math.max(min, out);
|
|
32
|
+
if (max !== void 0) out = Math.min(max, out);
|
|
33
|
+
return Number(out.toFixed(decimals));
|
|
34
|
+
}
|
|
35
|
+
const display = draft ?? value.toFixed(decimals);
|
|
36
|
+
function commitDraft() {
|
|
37
|
+
if (draft === null) return;
|
|
38
|
+
const parsed = Number.parseFloat(draft);
|
|
39
|
+
if (Number.isFinite(parsed)) onValueChange?.(clamp(parsed));
|
|
40
|
+
setDraft(null);
|
|
41
|
+
}
|
|
42
|
+
function onKeyDown(e) {
|
|
43
|
+
if (e.key === "Enter") {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
commitDraft();
|
|
46
|
+
inputRef.current?.blur();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (e.key === "Escape") {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
setDraft(null);
|
|
52
|
+
inputRef.current?.blur();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
const magnitude = step * (e.shiftKey ? 10 : 1);
|
|
58
|
+
const base = draft !== null ? Number.parseFloat(draft) : value;
|
|
59
|
+
if (!Number.isFinite(base)) return;
|
|
60
|
+
onValueChange?.(clamp(base + (e.key === "ArrowUp" ? magnitude : -magnitude)));
|
|
61
|
+
setDraft(null);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function onScrubDown(e) {
|
|
65
|
+
beginScrub(e, {
|
|
66
|
+
value,
|
|
67
|
+
step,
|
|
68
|
+
clamp,
|
|
69
|
+
onValueChange,
|
|
70
|
+
onGestureStart,
|
|
71
|
+
onGestureEnd,
|
|
72
|
+
disabled
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const hasHandle = Boolean(icon || prefix);
|
|
76
|
+
return /* @__PURE__ */ jsxs(
|
|
77
|
+
"div",
|
|
78
|
+
{
|
|
79
|
+
className: cn(
|
|
80
|
+
"group flex h-(--control-xs) items-center gap-1 px-1.5 motion-interactive",
|
|
81
|
+
FIELD_SHELL_XS,
|
|
82
|
+
"focus-within:ring-2 focus-within:ring-ring",
|
|
83
|
+
disabled && "pointer-events-none opacity-50",
|
|
84
|
+
className ?? "w-full"
|
|
85
|
+
),
|
|
86
|
+
children: [
|
|
87
|
+
hasHandle ? /* @__PURE__ */ jsx(
|
|
88
|
+
"span",
|
|
89
|
+
{
|
|
90
|
+
"aria-hidden": true,
|
|
91
|
+
title: `Drag to change ${label}`,
|
|
92
|
+
onPointerDown: onScrubDown,
|
|
93
|
+
className: "flex shrink-0 cursor-ew-resize select-none items-center text-muted-foreground motion-interactive group-hover:text-foreground",
|
|
94
|
+
children: icon ? /* @__PURE__ */ jsx(Icon, { name: icon, className: "text-xs" }) : /* @__PURE__ */ jsx("span", { className: "text-ui-num", children: prefix })
|
|
95
|
+
}
|
|
96
|
+
) : null,
|
|
97
|
+
/* @__PURE__ */ jsx(
|
|
98
|
+
"input",
|
|
99
|
+
{
|
|
100
|
+
ref: inputRef,
|
|
101
|
+
id,
|
|
102
|
+
type: "text",
|
|
103
|
+
inputMode: "decimal",
|
|
104
|
+
"aria-label": label,
|
|
105
|
+
disabled,
|
|
106
|
+
value: display,
|
|
107
|
+
onChange: (e) => setDraft(e.target.value),
|
|
108
|
+
onBlur: commitDraft,
|
|
109
|
+
onKeyDown,
|
|
110
|
+
onFocus: (e) => e.currentTarget.select(),
|
|
111
|
+
style: { width: `${Math.max(display.length, 2) + 0.5}ch` },
|
|
112
|
+
className: "min-w-0 shrink-0 bg-transparent text-ui-num text-foreground outline-none"
|
|
113
|
+
}
|
|
114
|
+
),
|
|
115
|
+
suffix ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-ui-num text-muted-foreground", children: suffix }) : null,
|
|
116
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "min-w-0 flex-1" })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
ScrubField.displayName = "ScrubField";
|
|
122
|
+
export {
|
|
123
|
+
ScrubField
|
|
124
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// src/components/scrub-field/scrub-field.meta.ts
|
|
2
|
+
var scrubFieldMeta = {
|
|
3
|
+
name: "ScrubField",
|
|
4
|
+
summary: "The compact numeric field a property grid is built from: a leading glyph inside the field that doubles as a drag-to-scrub handle, the value, and an optional unit.",
|
|
5
|
+
keywords: [
|
|
6
|
+
"scrub",
|
|
7
|
+
"numeric",
|
|
8
|
+
"number",
|
|
9
|
+
"field",
|
|
10
|
+
"property",
|
|
11
|
+
"inspector",
|
|
12
|
+
"drag",
|
|
13
|
+
"workspace",
|
|
14
|
+
"tool",
|
|
15
|
+
"unit"
|
|
16
|
+
],
|
|
17
|
+
usage: {
|
|
18
|
+
description: "Use ScrubField for numeric properties in tool chrome \u2014 an inspector, a property grid, a panel. The leading icon or letter says what the number is and is also the thing you drag, which is why a value like opacity needs no slider. Reach for NumberField instead in page-register forms: it has steppers and locale formatting, and it renders at page-register height. Those two steppers put a ~112px floor on a control that needs to be about 44px in a property grid, which is why ScrubField exists rather than a NumberField size variant. The input is sized in ch, so each field is as wide as its longest value and a grid of them lines up without per-field tuning.",
|
|
19
|
+
bestPractices: [
|
|
20
|
+
{
|
|
21
|
+
guidance: "do",
|
|
22
|
+
description: "Give the field an icon or prefix when it stands alone, so the row has a drag affordance and the value has an identity."
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
guidance: "do",
|
|
26
|
+
description: "Pass the unit as `suffix` rather than baking it into the label \u2014 it renders against the number the way reference tools show 100%."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
guidance: "do",
|
|
30
|
+
description: "Bracket undo with onGestureStart/onGestureEnd. A scrub fires per frame, so without it one undo rewinds a single pixel of the drag."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
guidance: "do",
|
|
34
|
+
description: "Set `step` to the real precision (0.01 for a normalised threshold). Display precision follows it, so a seed shows 1234 and never 1,234."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
guidance: "dont",
|
|
38
|
+
description: "Add a separate drag gripper beside the glyph. The icon or prefix already is the scrub handle; a second one is the same affordance twice and costs width a 240px panel does not have."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
guidance: "dont",
|
|
42
|
+
description: "Pair it with a Slider AND give it a glyph. The slider is already the drag affordance; two on one row is the same gesture twice. Omit icon/prefix when there's a slider."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
guidance: "dont",
|
|
46
|
+
description: "Use it in a page form. It is chrome-sized and has no label, description, or error slots \u2014 that's Field plus Input or NumberField."
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
related: {
|
|
51
|
+
components: ["NumberField", "Slider", "PanelSection", "Workspace", "Input"]
|
|
52
|
+
},
|
|
53
|
+
status: "stable",
|
|
54
|
+
props: [
|
|
55
|
+
{ name: "value", type: "number", description: "The current value (controlled)." },
|
|
56
|
+
{
|
|
57
|
+
name: "onValueChange",
|
|
58
|
+
type: "(next: number) => void",
|
|
59
|
+
description: "Fires on commit, arrow-key step, and every frame of a scrub."
|
|
60
|
+
},
|
|
61
|
+
{ name: "min", type: "number", description: "Lower clamp, applied to typing and scrubbing." },
|
|
62
|
+
{ name: "max", type: "number", description: "Upper clamp, applied to typing and scrubbing." },
|
|
63
|
+
{
|
|
64
|
+
name: "step",
|
|
65
|
+
type: "number",
|
|
66
|
+
default: "1",
|
|
67
|
+
description: "Arrow-key and scrub increment, and the source of display precision. Shift multiplies arrows by 10 and divides scrubbing by 10."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "label",
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "Accessible name for the input. Required \u2014 the visible glyph is decorative."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "icon",
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "Semantic icon name rendered inside the field; doubles as the scrub handle. Any name the app's IconProvider resolves works \u2014 image tools typically supply their own checkerboard glyph for opacity, which is a domain icon rather than one Sable's contract carries."
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "prefix",
|
|
81
|
+
type: "ReactNode",
|
|
82
|
+
description: 'Short text used instead of an icon (e.g. "X" / "Y"), with the same scrub role.'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "suffix",
|
|
86
|
+
type: "ReactNode",
|
|
87
|
+
description: 'Unit rendered after the value inside the field (e.g. "%", "px").'
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "onGestureStart",
|
|
91
|
+
type: "() => void",
|
|
92
|
+
description: "Fires once when a scrub drag begins \u2014 open an undo transaction here, and drop expensive downstream work (e.g. a GPU renderer) to a cheap preview quality; without it a pipeline re-renders at full quality on every pointer move and the drag stutters."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "onGestureEnd",
|
|
96
|
+
type: "() => void",
|
|
97
|
+
description: "Fires when a scrub drag ends \u2014 close the undo transaction here and restore full render quality."
|
|
98
|
+
},
|
|
99
|
+
{ name: "disabled", type: "boolean", description: "Disables typing and scrubbing." },
|
|
100
|
+
{ name: "id", type: "string", description: "Input id, for a PropertyRow's htmlFor." }
|
|
101
|
+
],
|
|
102
|
+
a11y: [
|
|
103
|
+
"The input carries the accessible name via `label`; the glyph is aria-hidden because it is decorative.",
|
|
104
|
+
"Every scrub gesture is reachable from the keyboard: ArrowUp/ArrowDown step by `step`, Shift+Arrow by ten steps.",
|
|
105
|
+
"Enter commits, Escape reverts to the last committed value, and blur commits \u2014 so a partial edit is never silently kept."
|
|
106
|
+
],
|
|
107
|
+
tokensUsed: ["foreground", "muted-foreground", "ring", "panel-field", "panel-field-hover"],
|
|
108
|
+
examples: [
|
|
109
|
+
{
|
|
110
|
+
label: "Opacity with a glyph handle",
|
|
111
|
+
code: '<ScrubField label="Opacity" icon="grid" suffix="%" value={60} min={0} max={100} onValueChange={(v) => setOpacity(v)} />'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: "X/Y offset pair (PropertyPair puts two fields on one scan line)",
|
|
115
|
+
code: `<PropertyPair labels={["Offset X", "Offset Y"]}>
|
|
116
|
+
<ScrubField label="Offset X" prefix="X" value={x} min={-128} max={128} onValueChange={setX} />
|
|
117
|
+
<ScrubField label="Offset Y" prefix="Y" value={y} min={-128} max={128} onValueChange={setY} />
|
|
118
|
+
</PropertyPair>`
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
label: "No glyph \u2014 the property name is the handle",
|
|
122
|
+
code: `<PropertyRow label="Block size" scrub={{ value: size, onValueChange: setSize, min: 2, max: 256 }}>
|
|
123
|
+
<ScrubField label="Block size" value={size} min={2} max={256} suffix="px" onValueChange={setSize} />
|
|
124
|
+
</PropertyRow>`
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
label: "Paired with a slider (no glyph \u2014 one drag affordance per row)",
|
|
128
|
+
code: `<PropertyRow label="Block size" stacked>
|
|
129
|
+
<div className="flex items-center gap-2">
|
|
130
|
+
<Slider value={32} min={4} max={256} className="min-w-0 flex-1" />
|
|
131
|
+
<ScrubField label="Block size" value={32} min={4} max={256} step={1} suffix="px" className="w-16 shrink-0" onValueChange={(v) => setBlockSize(v)} />
|
|
132
|
+
</div>
|
|
133
|
+
</PropertyRow>`
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
};
|
|
137
|
+
export {
|
|
138
|
+
scrubFieldMeta
|
|
139
|
+
};
|