shadcn_view_component 0.3.3
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +255 -0
- data/MIT-LICENSE +20 -0
- data/README.md +604 -0
- data/app/assets/stylesheets/shadcn-themes.css +1075 -0
- data/app/assets/stylesheets/shadcn.css +853 -0
- data/app/components/shadcn/accordion/component.rb +44 -0
- data/app/components/shadcn/accordion/content/component.rb +44 -0
- data/app/components/shadcn/accordion/item/component.rb +41 -0
- data/app/components/shadcn/accordion/preview.rb +16 -0
- data/app/components/shadcn/accordion/previews/default.html.erb +10 -0
- data/app/components/shadcn/accordion/previews/multiple.html.erb +13 -0
- data/app/components/shadcn/accordion/trigger/component.rb +52 -0
- data/app/components/shadcn/alert/component.rb +52 -0
- data/app/components/shadcn/alert/preview.rb +11 -0
- data/app/components/shadcn/alert/previews/default.html.erb +8 -0
- data/app/components/shadcn/alert.rb +17 -0
- data/app/components/shadcn/alert_dialog/action/component.rb +35 -0
- data/app/components/shadcn/alert_dialog/cancel/component.rb +16 -0
- data/app/components/shadcn/alert_dialog/component.rb +20 -0
- data/app/components/shadcn/alert_dialog/content/component.rb +55 -0
- data/app/components/shadcn/alert_dialog/header/component.rb +33 -0
- data/app/components/shadcn/alert_dialog/preview.rb +16 -0
- data/app/components/shadcn/alert_dialog/previews/default.html.erb +13 -0
- data/app/components/shadcn/alert_dialog/previews/small_with_media.html.erb +38 -0
- data/app/components/shadcn/alert_dialog.rb +32 -0
- data/app/components/shadcn/application_view_component.rb +225 -0
- data/app/components/shadcn/application_view_component_preview.rb +8 -0
- data/app/components/shadcn/aspect_ratio/component.rb +34 -0
- data/app/components/shadcn/aspect_ratio/preview.rb +16 -0
- data/app/components/shadcn/aspect_ratio/previews/default.html.erb +5 -0
- data/app/components/shadcn/aspect_ratio/previews/ratios.html.erb +12 -0
- data/app/components/shadcn/attachment/action/component.rb +19 -0
- data/app/components/shadcn/attachment/component.rb +76 -0
- data/app/components/shadcn/attachment/media/component.rb +56 -0
- data/app/components/shadcn/attachment/preview.rb +11 -0
- data/app/components/shadcn/attachment/previews/default.html.erb +80 -0
- data/app/components/shadcn/attachment/trigger/component.rb +31 -0
- data/app/components/shadcn/attachment.rb +42 -0
- data/app/components/shadcn/avatar/component.rb +43 -0
- data/app/components/shadcn/avatar/fallback/component.rb +23 -0
- data/app/components/shadcn/avatar/image/component.rb +20 -0
- data/app/components/shadcn/avatar/preview.rb +11 -0
- data/app/components/shadcn/avatar/previews/default.html.erb +13 -0
- data/app/components/shadcn/avatar.rb +32 -0
- data/app/components/shadcn/badge/component.rb +57 -0
- data/app/components/shadcn/badge/preview.rb +11 -0
- data/app/components/shadcn/badge/previews/default.html.erb +5 -0
- data/app/components/shadcn/breadcrumb/component.rb +15 -0
- data/app/components/shadcn/breadcrumb/ellipsis/component.rb +28 -0
- data/app/components/shadcn/breadcrumb/page/component.rb +25 -0
- data/app/components/shadcn/breadcrumb/preview.rb +16 -0
- data/app/components/shadcn/breadcrumb/previews/custom_separator.html.erb +17 -0
- data/app/components/shadcn/breadcrumb/previews/default.html.erb +15 -0
- data/app/components/shadcn/breadcrumb/separator/component.rb +31 -0
- data/app/components/shadcn/breadcrumb.rb +18 -0
- data/app/components/shadcn/bubble/component.rb +90 -0
- data/app/components/shadcn/bubble/preview.rb +16 -0
- data/app/components/shadcn/bubble/previews/alignment.html.erb +33 -0
- data/app/components/shadcn/bubble/previews/default.html.erb +22 -0
- data/app/components/shadcn/bubble/reactions/component.rb +54 -0
- data/app/components/shadcn/bubble.rb +24 -0
- data/app/components/shadcn/button/component.rb +85 -0
- data/app/components/shadcn/button/preview.rb +31 -0
- data/app/components/shadcn/button/previews/default.html.erb +8 -0
- data/app/components/shadcn/button/previews/sizes.html.erb +5 -0
- data/app/components/shadcn/button/previews/variants.html.erb +5 -0
- data/app/components/shadcn/button_group/component.rb +53 -0
- data/app/components/shadcn/button_group/preview.rb +15 -0
- data/app/components/shadcn/button_group/previews/default.html.erb +18 -0
- data/app/components/shadcn/button_group/previews/vertical.html.erb +5 -0
- data/app/components/shadcn/button_group/separator/component.rb +30 -0
- data/app/components/shadcn/button_group/text/component.rb +20 -0
- data/app/components/shadcn/calendar/component.rb +558 -0
- data/app/components/shadcn/calendar/month.rb +74 -0
- data/app/components/shadcn/calendar/preview.rb +64 -0
- data/app/components/shadcn/calendar/previews/booked.html.erb +18 -0
- data/app/components/shadcn/calendar/previews/custom_cell_size.html.erb +11 -0
- data/app/components/shadcn/calendar/previews/date_and_time.html.erb +31 -0
- data/app/components/shadcn/calendar/previews/default.html.erb +8 -0
- data/app/components/shadcn/calendar/previews/dropdown_caption.html.erb +11 -0
- data/app/components/shadcn/calendar/previews/in_a_form.html.erb +8 -0
- data/app/components/shadcn/calendar/previews/presets.html.erb +20 -0
- data/app/components/shadcn/calendar/previews/range.html.erb +10 -0
- data/app/components/shadcn/calendar/previews/week_numbers.html.erb +8 -0
- data/app/components/shadcn/card/component.rb +24 -0
- data/app/components/shadcn/card/header/component.rb +26 -0
- data/app/components/shadcn/card/preview.rb +16 -0
- data/app/components/shadcn/card/previews/default.html.erb +18 -0
- data/app/components/shadcn/card/previews/image.html.erb +37 -0
- data/app/components/shadcn/card.rb +21 -0
- data/app/components/shadcn/carousel/component.rb +61 -0
- data/app/components/shadcn/carousel/content/component.rb +86 -0
- data/app/components/shadcn/carousel/item/component.rb +42 -0
- data/app/components/shadcn/carousel/next/component.rb +59 -0
- data/app/components/shadcn/carousel/preview.rb +22 -0
- data/app/components/shadcn/carousel/previews/default.html.erb +22 -0
- data/app/components/shadcn/carousel/previews/sizes.html.erb +42 -0
- data/app/components/shadcn/carousel/previews/vertical.html.erb +27 -0
- data/app/components/shadcn/carousel/previous/component.rb +59 -0
- data/app/components/shadcn/chart/area/component.rb +43 -0
- data/app/components/shadcn/chart/bar/component.rb +75 -0
- data/app/components/shadcn/chart/cartesian/component.rb +152 -0
- data/app/components/shadcn/chart/component.rb +124 -0
- data/app/components/shadcn/chart/focusable.rb +38 -0
- data/app/components/shadcn/chart/legend/component.rb +55 -0
- data/app/components/shadcn/chart/line/component.rb +50 -0
- data/app/components/shadcn/chart/pie/component.rb +169 -0
- data/app/components/shadcn/chart/plot.rb +147 -0
- data/app/components/shadcn/chart/preview.rb +45 -0
- data/app/components/shadcn/chart/previews/area.html.erb +31 -0
- data/app/components/shadcn/chart/previews/bar.html.erb +32 -0
- data/app/components/shadcn/chart/previews/bar_stacked.html.erb +30 -0
- data/app/components/shadcn/chart/previews/default.html.erb +30 -0
- data/app/components/shadcn/chart/previews/donut.html.erb +16 -0
- data/app/components/shadcn/chart/previews/line.html.erb +30 -0
- data/app/components/shadcn/chart/previews/percentages.html.erb +17 -0
- data/app/components/shadcn/chart/table/component.rb +75 -0
- data/app/components/shadcn/chart/tooltip/component.rb +111 -0
- data/app/components/shadcn/checkbox/component.rb +109 -0
- data/app/components/shadcn/checkbox/preview.rb +16 -0
- data/app/components/shadcn/checkbox/previews/default.html.erb +14 -0
- data/app/components/shadcn/checkbox/previews/states.html.erb +23 -0
- data/app/components/shadcn/collapsible/component.rb +35 -0
- data/app/components/shadcn/collapsible/content/component.rb +20 -0
- data/app/components/shadcn/collapsible/preview.rb +11 -0
- data/app/components/shadcn/collapsible/previews/default.html.erb +9 -0
- data/app/components/shadcn/collapsible/trigger/component.rb +23 -0
- data/app/components/shadcn/combobox/chip/component.rb +60 -0
- data/app/components/shadcn/combobox/chip_input/component.rb +43 -0
- data/app/components/shadcn/combobox/chips/component.rb +54 -0
- data/app/components/shadcn/combobox/clear/component.rb +32 -0
- data/app/components/shadcn/combobox/component.rb +113 -0
- data/app/components/shadcn/combobox/content/component.rb +59 -0
- data/app/components/shadcn/combobox/empty/component.rb +23 -0
- data/app/components/shadcn/combobox/input/component.rb +85 -0
- data/app/components/shadcn/combobox/item/component.rb +69 -0
- data/app/components/shadcn/combobox/list/component.rb +27 -0
- data/app/components/shadcn/combobox/preview.rb +31 -0
- data/app/components/shadcn/combobox/previews/default.html.erb +20 -0
- data/app/components/shadcn/combobox/previews/grouped.html.erb +25 -0
- data/app/components/shadcn/combobox/previews/multiple.html.erb +28 -0
- data/app/components/shadcn/combobox/previews/with_clear.html.erb +16 -0
- data/app/components/shadcn/combobox/trigger/component.rb +54 -0
- data/app/components/shadcn/combobox.rb +16 -0
- data/app/components/shadcn/command/component.rb +67 -0
- data/app/components/shadcn/command/dialog/component.rb +72 -0
- data/app/components/shadcn/command/empty/component.rb +29 -0
- data/app/components/shadcn/command/group/component.rb +63 -0
- data/app/components/shadcn/command/input/component.rb +66 -0
- data/app/components/shadcn/command/item/component.rb +62 -0
- data/app/components/shadcn/command/list/component.rb +36 -0
- data/app/components/shadcn/command/preview.rb +26 -0
- data/app/components/shadcn/command/previews/default.html.erb +41 -0
- data/app/components/shadcn/command/previews/dialog.html.erb +33 -0
- data/app/components/shadcn/command/previews/ranking.html.erb +16 -0
- data/app/components/shadcn/command/separator/component.rb +33 -0
- data/app/components/shadcn/command.rb +14 -0
- data/app/components/shadcn/concerns/modal_root.rb +43 -0
- data/app/components/shadcn/concerns/submits_value.rb +81 -0
- data/app/components/shadcn/context_menu/component.rb +45 -0
- data/app/components/shadcn/context_menu/content/component.rb +40 -0
- data/app/components/shadcn/context_menu/preview.rb +16 -0
- data/app/components/shadcn/context_menu/previews/default.html.erb +34 -0
- data/app/components/shadcn/context_menu/previews/items.html.erb +35 -0
- data/app/components/shadcn/context_menu/sub/component.rb +47 -0
- data/app/components/shadcn/context_menu/sub_content/component.rb +31 -0
- data/app/components/shadcn/context_menu/trigger/component.rb +50 -0
- data/app/components/shadcn/context_menu.rb +43 -0
- data/app/components/shadcn/dialog/close/component.rb +20 -0
- data/app/components/shadcn/dialog/component.rb +20 -0
- data/app/components/shadcn/dialog/content/component.rb +78 -0
- data/app/components/shadcn/dialog/header/component.rb +23 -0
- data/app/components/shadcn/dialog/overlay/component.rb +28 -0
- data/app/components/shadcn/dialog/preview.rb +28 -0
- data/app/components/shadcn/dialog/previews/default.html.erb +17 -0
- data/app/components/shadcn/dialog/previews/inside_stacking_context.html.erb +25 -0
- data/app/components/shadcn/dialog/previews/no_close_button.html.erb +15 -0
- data/app/components/shadcn/dialog/previews/scrollable_content.html.erb +29 -0
- data/app/components/shadcn/dialog/trigger/component.rb +24 -0
- data/app/components/shadcn/dialog.rb +17 -0
- data/app/components/shadcn/drawer/component.rb +33 -0
- data/app/components/shadcn/drawer/content/component.rb +95 -0
- data/app/components/shadcn/drawer/header/component.rb +34 -0
- data/app/components/shadcn/drawer/preview.rb +29 -0
- data/app/components/shadcn/drawer/previews/default.html.erb +21 -0
- data/app/components/shadcn/drawer/previews/scrollable.html.erb +20 -0
- data/app/components/shadcn/drawer/previews/scrollable_side.html.erb +21 -0
- data/app/components/shadcn/drawer/previews/sides.html.erb +17 -0
- data/app/components/shadcn/drawer.rb +27 -0
- data/app/components/shadcn/dropdown_menu/checkbox_item/component.rb +61 -0
- data/app/components/shadcn/dropdown_menu/component.rb +48 -0
- data/app/components/shadcn/dropdown_menu/content/component.rb +49 -0
- data/app/components/shadcn/dropdown_menu/group/component.rb +16 -0
- data/app/components/shadcn/dropdown_menu/item/component.rb +50 -0
- data/app/components/shadcn/dropdown_menu/preview.rb +16 -0
- data/app/components/shadcn/dropdown_menu/previews/checkboxes_and_radio.html.erb +34 -0
- data/app/components/shadcn/dropdown_menu/previews/default.html.erb +23 -0
- data/app/components/shadcn/dropdown_menu/radio_group/component.rb +16 -0
- data/app/components/shadcn/dropdown_menu/radio_item/component.rb +63 -0
- data/app/components/shadcn/dropdown_menu/sub/component.rb +44 -0
- data/app/components/shadcn/dropdown_menu/sub_content/component.rb +45 -0
- data/app/components/shadcn/dropdown_menu/sub_trigger/component.rb +58 -0
- data/app/components/shadcn/dropdown_menu/trigger/component.rb +25 -0
- data/app/components/shadcn/dropdown_menu.rb +18 -0
- data/app/components/shadcn/empty/component.rb +17 -0
- data/app/components/shadcn/empty/media/component.rb +48 -0
- data/app/components/shadcn/empty/preview.rb +16 -0
- data/app/components/shadcn/empty/previews/default.html.erb +15 -0
- data/app/components/shadcn/empty/previews/media.html.erb +32 -0
- data/app/components/shadcn/empty.rb +26 -0
- data/app/components/shadcn/field/component.rb +61 -0
- data/app/components/shadcn/field/error/component.rb +49 -0
- data/app/components/shadcn/field/legend/component.rb +30 -0
- data/app/components/shadcn/field/preview.rb +17 -0
- data/app/components/shadcn/field/previews/default.html.erb +29 -0
- data/app/components/shadcn/field/previews/form_builder.html.erb +38 -0
- data/app/components/shadcn/field/separator/component.rb +35 -0
- data/app/components/shadcn/field.rb +44 -0
- data/app/components/shadcn/hover_card/component.rb +51 -0
- data/app/components/shadcn/hover_card/content/component.rb +45 -0
- data/app/components/shadcn/hover_card/preview.rb +16 -0
- data/app/components/shadcn/hover_card/previews/default.html.erb +36 -0
- data/app/components/shadcn/hover_card/previews/sides.html.erb +15 -0
- data/app/components/shadcn/hover_card/trigger/component.rb +33 -0
- data/app/components/shadcn/icon/component.rb +76 -0
- data/app/components/shadcn/icon.rb +43 -0
- data/app/components/shadcn/input/component.rb +26 -0
- data/app/components/shadcn/input/preview.rb +16 -0
- data/app/components/shadcn/input/previews/default.html.erb +5 -0
- data/app/components/shadcn/input/previews/states.html.erb +20 -0
- data/app/components/shadcn/input_group/addon/component.rb +65 -0
- data/app/components/shadcn/input_group/button/component.rb +40 -0
- data/app/components/shadcn/input_group/component.rb +43 -0
- data/app/components/shadcn/input_group/input/component.rb +25 -0
- data/app/components/shadcn/input_group/preview.rb +17 -0
- data/app/components/shadcn/input_group/previews/addons.html.erb +53 -0
- data/app/components/shadcn/input_group/previews/default.html.erb +25 -0
- data/app/components/shadcn/input_group/text/component.rb +20 -0
- data/app/components/shadcn/input_group/textarea/component.rb +21 -0
- data/app/components/shadcn/input_otp/component.rb +95 -0
- data/app/components/shadcn/input_otp/preview.rb +17 -0
- data/app/components/shadcn/input_otp/previews/default.html.erb +19 -0
- data/app/components/shadcn/input_otp/previews/variations.html.erb +33 -0
- data/app/components/shadcn/input_otp/separator/component.rb +21 -0
- data/app/components/shadcn/input_otp/slot/component.rb +60 -0
- data/app/components/shadcn/input_otp.rb +11 -0
- data/app/components/shadcn/item/component.rb +56 -0
- data/app/components/shadcn/item/group/component.rb +53 -0
- data/app/components/shadcn/item/media/component.rb +53 -0
- data/app/components/shadcn/item/preview.rb +20 -0
- data/app/components/shadcn/item/previews/default.html.erb +32 -0
- data/app/components/shadcn/item/previews/link.html.erb +39 -0
- data/app/components/shadcn/item/previews/outline.html.erb +8 -0
- data/app/components/shadcn/item/separator/component.rb +24 -0
- data/app/components/shadcn/item.rb +34 -0
- data/app/components/shadcn/kbd/component.rb +23 -0
- data/app/components/shadcn/kbd/group/component.rb +17 -0
- data/app/components/shadcn/kbd/preview.rb +11 -0
- data/app/components/shadcn/kbd/previews/default.html.erb +4 -0
- data/app/components/shadcn/label/component.rb +20 -0
- data/app/components/shadcn/label/preview.rb +11 -0
- data/app/components/shadcn/label/previews/default.html.erb +4 -0
- data/app/components/shadcn/marker/component.rb +46 -0
- data/app/components/shadcn/marker/icon/component.rb +23 -0
- data/app/components/shadcn/marker/preview.rb +17 -0
- data/app/components/shadcn/marker/previews/default.html.erb +18 -0
- data/app/components/shadcn/marker/previews/status.html.erb +32 -0
- data/app/components/shadcn/marker.rb +17 -0
- data/app/components/shadcn/menubar/component.rb +36 -0
- data/app/components/shadcn/menubar/content/component.rb +49 -0
- data/app/components/shadcn/menubar/menu/component.rb +39 -0
- data/app/components/shadcn/menubar/preview.rb +16 -0
- data/app/components/shadcn/menubar/previews/default.html.erb +52 -0
- data/app/components/shadcn/menubar/previews/items.html.erb +38 -0
- data/app/components/shadcn/menubar/sub/component.rb +43 -0
- data/app/components/shadcn/menubar/sub_content/component.rb +31 -0
- data/app/components/shadcn/menubar/sub_trigger/component.rb +31 -0
- data/app/components/shadcn/menubar/trigger/component.rb +41 -0
- data/app/components/shadcn/menubar.rb +47 -0
- data/app/components/shadcn/message/component.rb +33 -0
- data/app/components/shadcn/message/preview.rb +16 -0
- data/app/components/shadcn/message/previews/actions.html.erb +51 -0
- data/app/components/shadcn/message/previews/default.html.erb +35 -0
- data/app/components/shadcn/message.rb +35 -0
- data/app/components/shadcn/message_scroller/button/component.rb +78 -0
- data/app/components/shadcn/message_scroller/component.rb +59 -0
- data/app/components/shadcn/message_scroller/content/component.rb +50 -0
- data/app/components/shadcn/message_scroller/item/component.rb +45 -0
- data/app/components/shadcn/message_scroller/preview.rb +11 -0
- data/app/components/shadcn/message_scroller/previews/default.html.erb +72 -0
- data/app/components/shadcn/message_scroller/viewport/component.rb +41 -0
- data/app/components/shadcn/mode_switcher/component.rb +67 -0
- data/app/components/shadcn/mode_switcher/preview.rb +11 -0
- data/app/components/shadcn/mode_switcher/previews/default.html.erb +5 -0
- data/app/components/shadcn/mode_toggle/component.rb +75 -0
- data/app/components/shadcn/mode_toggle/preview.rb +11 -0
- data/app/components/shadcn/mode_toggle/previews/default.html.erb +20 -0
- data/app/components/shadcn/native_select/component.rb +59 -0
- data/app/components/shadcn/native_select/preview.rb +16 -0
- data/app/components/shadcn/native_select/previews/default.html.erb +9 -0
- data/app/components/shadcn/native_select/previews/groups.html.erb +26 -0
- data/app/components/shadcn/native_select.rb +16 -0
- data/app/components/shadcn/navigation_menu/component.rb +51 -0
- data/app/components/shadcn/navigation_menu/content/component.rb +58 -0
- data/app/components/shadcn/navigation_menu/preview.rb +11 -0
- data/app/components/shadcn/navigation_menu/previews/default.html.erb +49 -0
- data/app/components/shadcn/navigation_menu/trigger/component.rb +59 -0
- data/app/components/shadcn/navigation_menu.rb +28 -0
- data/app/components/shadcn/pagination/component.rb +19 -0
- data/app/components/shadcn/pagination/ellipsis/component.rb +28 -0
- data/app/components/shadcn/pagination/link/component.rb +37 -0
- data/app/components/shadcn/pagination/next/component.rb +31 -0
- data/app/components/shadcn/pagination/preview.rb +16 -0
- data/app/components/shadcn/pagination/previews/default.html.erb +18 -0
- data/app/components/shadcn/pagination/previews/simple.html.erb +39 -0
- data/app/components/shadcn/pagination/previous/component.rb +31 -0
- data/app/components/shadcn/pagination.rb +14 -0
- data/app/components/shadcn/parts.rb +38 -0
- data/app/components/shadcn/popover/anchor/component.rb +17 -0
- data/app/components/shadcn/popover/component.rb +42 -0
- data/app/components/shadcn/popover/content/component.rb +40 -0
- data/app/components/shadcn/popover/preview.rb +28 -0
- data/app/components/shadcn/popover/previews/align.html.erb +13 -0
- data/app/components/shadcn/popover/previews/default.html.erb +9 -0
- data/app/components/shadcn/popover/previews/inside_containing_block.html.erb +41 -0
- data/app/components/shadcn/popover/previews/inside_stacking_context.html.erb +30 -0
- data/app/components/shadcn/popover/trigger/component.rb +24 -0
- data/app/components/shadcn/popover.rb +16 -0
- data/app/components/shadcn/progress/component.rb +62 -0
- data/app/components/shadcn/progress/preview.rb +11 -0
- data/app/components/shadcn/progress/previews/default.html.erb +5 -0
- data/app/components/shadcn/radio_group/component.rb +51 -0
- data/app/components/shadcn/radio_group/item/component.rb +74 -0
- data/app/components/shadcn/radio_group/preview.rb +16 -0
- data/app/components/shadcn/radio_group/previews/default.html.erb +15 -0
- data/app/components/shadcn/radio_group/previews/states.html.erb +41 -0
- data/app/components/shadcn/resizable/component.rb +59 -0
- data/app/components/shadcn/resizable/handle/component.rb +70 -0
- data/app/components/shadcn/resizable/panel/component.rb +53 -0
- data/app/components/shadcn/resizable/preview.rb +23 -0
- data/app/components/shadcn/resizable/previews/default.html.erb +25 -0
- data/app/components/shadcn/resizable/previews/vertical.html.erb +19 -0
- data/app/components/shadcn/resizable/previews/with_handle.html.erb +17 -0
- data/app/components/shadcn/scroll_area/component.rb +84 -0
- data/app/components/shadcn/scroll_area/preview.rb +11 -0
- data/app/components/shadcn/scroll_area/previews/default.html.erb +36 -0
- data/app/components/shadcn/scroll_area/scrollbar/component.rb +72 -0
- data/app/components/shadcn/scroll_area/viewport/component.rb +70 -0
- data/app/components/shadcn/scroll_area.rb +14 -0
- data/app/components/shadcn/select/component.rb +67 -0
- data/app/components/shadcn/select/content/component.rb +157 -0
- data/app/components/shadcn/select/empty/component.rb +38 -0
- data/app/components/shadcn/select/group/component.rb +16 -0
- data/app/components/shadcn/select/item/component.rb +71 -0
- data/app/components/shadcn/select/list/component.rb +41 -0
- data/app/components/shadcn/select/preview.rb +24 -0
- data/app/components/shadcn/select/previews/default.html.erb +17 -0
- data/app/components/shadcn/select/previews/scrollable.html.erb +19 -0
- data/app/components/shadcn/select/previews/searchable.html.erb +18 -0
- data/app/components/shadcn/select/previews/states.html.erb +25 -0
- data/app/components/shadcn/select/search/component.rb +54 -0
- data/app/components/shadcn/select/trigger/component.rb +78 -0
- data/app/components/shadcn/select/value/component.rb +28 -0
- data/app/components/shadcn/select.rb +15 -0
- data/app/components/shadcn/separator/component.rb +41 -0
- data/app/components/shadcn/separator/preview.rb +11 -0
- data/app/components/shadcn/separator/previews/default.html.erb +9 -0
- data/app/components/shadcn/sheet/component.rb +16 -0
- data/app/components/shadcn/sheet/content/component.rb +98 -0
- data/app/components/shadcn/sheet/header/component.rb +23 -0
- data/app/components/shadcn/sheet/preview.rb +16 -0
- data/app/components/shadcn/sheet/previews/default.html.erb +16 -0
- data/app/components/shadcn/sheet/previews/no_close_button.html.erb +14 -0
- data/app/components/shadcn/sheet.rb +22 -0
- data/app/components/shadcn/sidebar/component.rb +232 -0
- data/app/components/shadcn/sidebar/input/component.rb +25 -0
- data/app/components/shadcn/sidebar/menu_action/component.rb +58 -0
- data/app/components/shadcn/sidebar/menu_button/component.rb +100 -0
- data/app/components/shadcn/sidebar/menu_skeleton/component.rb +51 -0
- data/app/components/shadcn/sidebar/menu_sub_button/component.rb +60 -0
- data/app/components/shadcn/sidebar/preview.rb +22 -0
- data/app/components/shadcn/sidebar/previews/default.html.erb +189 -0
- data/app/components/shadcn/sidebar/previews/floating.html.erb +39 -0
- data/app/components/shadcn/sidebar/previews/inset.html.erb +48 -0
- data/app/components/shadcn/sidebar/provider/component.rb +53 -0
- data/app/components/shadcn/sidebar/rail/component.rb +43 -0
- data/app/components/shadcn/sidebar/separator/component.rb +23 -0
- data/app/components/shadcn/sidebar/trigger/component.rb +39 -0
- data/app/components/shadcn/sidebar.rb +98 -0
- data/app/components/shadcn/skeleton/component.rb +14 -0
- data/app/components/shadcn/skeleton/preview.rb +11 -0
- data/app/components/shadcn/skeleton/previews/default.html.erb +7 -0
- data/app/components/shadcn/slider/component.rb +145 -0
- data/app/components/shadcn/slider/preview.rb +16 -0
- data/app/components/shadcn/slider/previews/default.html.erb +17 -0
- data/app/components/shadcn/slider/previews/vertical.html.erb +7 -0
- data/app/components/shadcn/slider/range/component.rb +51 -0
- data/app/components/shadcn/slider/thumb/component.rb +58 -0
- data/app/components/shadcn/slider/track/component.rb +32 -0
- data/app/components/shadcn/spinner/component.rb +21 -0
- data/app/components/shadcn/spinner/preview.rb +11 -0
- data/app/components/shadcn/spinner/previews/default.html.erb +7 -0
- data/app/components/shadcn/switch/component.rb +104 -0
- data/app/components/shadcn/switch/preview.rb +11 -0
- data/app/components/shadcn/switch/previews/default.html.erb +24 -0
- data/app/components/shadcn/table/component.rb +26 -0
- data/app/components/shadcn/table/preview.rb +16 -0
- data/app/components/shadcn/table/previews/default.html.erb +19 -0
- data/app/components/shadcn/table/previews/footer.html.erb +25 -0
- data/app/components/shadcn/table.rb +33 -0
- data/app/components/shadcn/tabs/component.rb +40 -0
- data/app/components/shadcn/tabs/content/component.rb +34 -0
- data/app/components/shadcn/tabs/list/component.rb +51 -0
- data/app/components/shadcn/tabs/preview.rb +16 -0
- data/app/components/shadcn/tabs/previews/default.html.erb +21 -0
- data/app/components/shadcn/tabs/previews/line.html.erb +23 -0
- data/app/components/shadcn/tabs/trigger/component.rb +66 -0
- data/app/components/shadcn/textarea/component.rb +24 -0
- data/app/components/shadcn/textarea/preview.rb +16 -0
- data/app/components/shadcn/textarea/previews/default.html.erb +3 -0
- data/app/components/shadcn/textarea/previews/states.html.erb +18 -0
- data/app/components/shadcn/theme_selector/component.rb +88 -0
- data/app/components/shadcn/theme_selector/preview.rb +17 -0
- data/app/components/shadcn/theme_selector/previews/all_themes.html.erb +20 -0
- data/app/components/shadcn/theme_selector/previews/default.html.erb +18 -0
- data/app/components/shadcn/toaster/component.rb +139 -0
- data/app/components/shadcn/toaster/preview.rb +16 -0
- data/app/components/shadcn/toaster/previews/default.html.erb +19 -0
- data/app/components/shadcn/toaster/previews/from_the_server.html.erb +15 -0
- data/app/components/shadcn/toaster/toast/component.rb +134 -0
- data/app/components/shadcn/toggle/component.rb +81 -0
- data/app/components/shadcn/toggle/preview.rb +11 -0
- data/app/components/shadcn/toggle/previews/default.html.erb +6 -0
- data/app/components/shadcn/toggle_group/component.rb +62 -0
- data/app/components/shadcn/toggle_group/item/component.rb +59 -0
- data/app/components/shadcn/toggle_group/preview.rb +16 -0
- data/app/components/shadcn/toggle_group/previews/default.html.erb +12 -0
- data/app/components/shadcn/toggle_group/previews/sizes.html.erb +37 -0
- data/app/components/shadcn/tooltip/component.rb +38 -0
- data/app/components/shadcn/tooltip/content/component.rb +62 -0
- data/app/components/shadcn/tooltip/preview.rb +21 -0
- data/app/components/shadcn/tooltip/previews/default.html.erb +4 -0
- data/app/components/shadcn/tooltip/previews/sides.html.erb +19 -0
- data/app/components/shadcn/tooltip/previews/with_keyboard_shortcut.html.erb +11 -0
- data/app/components/shadcn/tooltip/provider/component.rb +28 -0
- data/app/components/shadcn/tooltip/trigger/component.rb +25 -0
- data/app/helpers/shadcn_view_component/form_helper.rb +25 -0
- data/app/helpers/shadcn_view_component/theme_helper.rb +61 -0
- data/app/javascript/shadcn/animation.js +180 -0
- data/app/javascript/shadcn/command_score.js +110 -0
- data/app/javascript/shadcn/controllers/accordion_controller.js +127 -0
- data/app/javascript/shadcn/controllers/avatar_controller.js +32 -0
- data/app/javascript/shadcn/controllers/calendar_controller.js +633 -0
- data/app/javascript/shadcn/controllers/carousel_controller.js +139 -0
- data/app/javascript/shadcn/controllers/chart_controller.js +110 -0
- data/app/javascript/shadcn/controllers/checkbox_controller.js +61 -0
- data/app/javascript/shadcn/controllers/collapsible_controller.js +55 -0
- data/app/javascript/shadcn/controllers/combobox_controller.js +360 -0
- data/app/javascript/shadcn/controllers/command_controller.js +199 -0
- data/app/javascript/shadcn/controllers/dialog_controller.js +154 -0
- data/app/javascript/shadcn/controllers/drawer_controller.js +265 -0
- data/app/javascript/shadcn/controllers/dropdown_menu_controller.js +259 -0
- data/app/javascript/shadcn/controllers/hover_card_controller.js +85 -0
- data/app/javascript/shadcn/controllers/input_group_controller.js +17 -0
- data/app/javascript/shadcn/controllers/input_otp_controller.js +80 -0
- data/app/javascript/shadcn/controllers/menubar_controller.js +151 -0
- data/app/javascript/shadcn/controllers/message_scroller_controller.js +456 -0
- data/app/javascript/shadcn/controllers/navigation_menu_controller.js +211 -0
- data/app/javascript/shadcn/controllers/popover_controller.js +66 -0
- data/app/javascript/shadcn/controllers/radio_group_controller.js +69 -0
- data/app/javascript/shadcn/controllers/resizable_controller.js +167 -0
- data/app/javascript/shadcn/controllers/scroll_area_controller.js +253 -0
- data/app/javascript/shadcn/controllers/select_controller.js +320 -0
- data/app/javascript/shadcn/controllers/sidebar_controller.js +273 -0
- data/app/javascript/shadcn/controllers/slider_controller.js +230 -0
- data/app/javascript/shadcn/controllers/switch_controller.js +39 -0
- data/app/javascript/shadcn/controllers/tabs_controller.js +81 -0
- data/app/javascript/shadcn/controllers/theme_controller.js +67 -0
- data/app/javascript/shadcn/controllers/toaster_controller.js +281 -0
- data/app/javascript/shadcn/controllers/toggle_controller.js +24 -0
- data/app/javascript/shadcn/controllers/toggle_group_controller.js +73 -0
- data/app/javascript/shadcn/controllers/tooltip_controller.js +58 -0
- data/app/javascript/shadcn/direction.js +41 -0
- data/app/javascript/shadcn/dismiss.js +73 -0
- data/app/javascript/shadcn/floating.js +207 -0
- data/app/javascript/shadcn/focus.js +86 -0
- data/app/javascript/shadcn/id.js +14 -0
- data/app/javascript/shadcn/index.js +110 -0
- data/app/javascript/shadcn/popper.js +262 -0
- data/app/javascript/shadcn/scroll_geometry.js +267 -0
- data/app/javascript/shadcn/theme.js +161 -0
- data/app/javascript/shadcn/top_layer.js +59 -0
- data/app/javascript/shadcn/typeahead.js +99 -0
- data/config/importmap.rb +6 -0
- data/config/locales/en.yml +62 -0
- data/lib/generators/shadcn_view_component/install/install_generator.rb +149 -0
- data/lib/shadcn_view_component/engine.rb +73 -0
- data/lib/shadcn_view_component/form_builder.rb +264 -0
- data/lib/shadcn_view_component/icon_registry.rb +66 -0
- data/lib/shadcn_view_component/icons.rb +32 -0
- data/lib/shadcn_view_component/themes.rb +1065 -0
- data/lib/shadcn_view_component/version.rb +3 -0
- data/lib/shadcn_view_component.rb +82 -0
- data/lib/tasks/icons.rake +53 -0
- data/lib/tasks/themes.rake +171 -0
- metadata +608 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Calendar
|
|
5
|
+
class Preview < ApplicationViewComponentPreview
|
|
6
|
+
# Upstream's own first example, minus the border it wraps it in: a single
|
|
7
|
+
# month with today selected.
|
|
8
|
+
def default
|
|
9
|
+
render_with_template
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Upstream's "Month and Year Selector".
|
|
13
|
+
def dropdown_caption
|
|
14
|
+
render_with_template
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Upstream's "Range Calendar".
|
|
18
|
+
def range
|
|
19
|
+
render_with_template
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Upstream's "Presets".
|
|
23
|
+
def presets
|
|
24
|
+
render_with_template
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Upstream's "Date and Time Picker".
|
|
28
|
+
def date_and_time
|
|
29
|
+
render_with_template
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Upstream's "Booked dates".
|
|
33
|
+
def booked
|
|
34
|
+
render_with_template
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Upstream's "Custom Cell Size".
|
|
38
|
+
def custom_cell_size
|
|
39
|
+
render_with_template
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Upstream's "Week Numbers".
|
|
43
|
+
def week_numbers
|
|
44
|
+
render_with_template
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The hidden inputs a Rails form posts.
|
|
48
|
+
def in_a_form
|
|
49
|
+
render_with_template
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The month is an argument here so a month can be asked for by URL. That
|
|
53
|
+
# is what `spec/system/calendar_spec.rb` compares the browser's own render
|
|
54
|
+
# against: the grid exists twice — in `Calendar::Month` and in the
|
|
55
|
+
# controller — and the only thing that keeps the two honest is asking the
|
|
56
|
+
# server what it would have drawn.
|
|
57
|
+
#
|
|
58
|
+
# @param month text
|
|
59
|
+
def month(month: "2026-09-01")
|
|
60
|
+
render_component(month: Date.parse(month), class: "rounded-md border shadow-sm")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<%# Upstream's "Booked dates": the taken days are refused and struck through.
|
|
2
|
+
`disabled:` takes anything answering `===` — a Date, a Range, or a list of
|
|
3
|
+
them — so the booking rule is written where the app already keeps it.
|
|
4
|
+
|
|
5
|
+
The line through them is the caller's, not the component's: upstream reaches
|
|
6
|
+
for `modifiers` and `modifiersClassNames`, which this port does not have, and
|
|
7
|
+
a class on the root reaches the same cells. %>
|
|
8
|
+
<%
|
|
9
|
+
booked = [ Date.new(2026, 8, 4), Date.new(2026, 8, 5),
|
|
10
|
+
Date.new(2026, 8, 11)..Date.new(2026, 8, 13),
|
|
11
|
+
Date.new(2026, 8, 20), Date.new(2026, 8, 26)..Date.new(2026, 8, 28) ]
|
|
12
|
+
%>
|
|
13
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
14
|
+
month: Date.new(2026, 8, 1),
|
|
15
|
+
selected: Date.new(2026, 8, 17),
|
|
16
|
+
disabled: booked,
|
|
17
|
+
class: "rounded-md border shadow-sm [&_td[data-disabled]>button]:line-through"
|
|
18
|
+
)) %>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%# Upstream's "Custom Cell Size": the whole calendar is sized from one custom
|
|
2
|
+
property, so a caller changes `--cell-size` and everything follows. %>
|
|
3
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
4
|
+
mode: :range,
|
|
5
|
+
month: Date.new(2026, 8, 1),
|
|
6
|
+
selected: Date.new(2026, 8, 9)..Date.new(2026, 8, 19),
|
|
7
|
+
caption_layout: :dropdown,
|
|
8
|
+
start_month: Date.new(2024, 1, 1),
|
|
9
|
+
end_month: Date.new(2030, 12, 31),
|
|
10
|
+
class: "rounded-md border shadow-sm [--cell-size:--spacing(12)]"
|
|
11
|
+
)) %>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<%# Upstream's "Date and Time Picker": a date, then the two ends of the day it
|
|
2
|
+
covers. The times are real `<input type="time">` fields, so the browser's own
|
|
3
|
+
picker and validation come with them — the same call the gem makes for
|
|
4
|
+
`native_select`.
|
|
5
|
+
|
|
6
|
+
`step` is in *seconds*, so 900 is a quarter of an hour. Measured in Chrome:
|
|
7
|
+
the field's arrows then move 09:00 → 09:15 → 09:30, and a typed 09:07 is
|
|
8
|
+
refused at submit with the browser's own message. What it does not do is
|
|
9
|
+
turn the field into a list — the segments still take any digits, and the
|
|
10
|
+
complaint comes afterwards. Where only a quarter-hour will do, the control
|
|
11
|
+
is a `<select>` rather than this one. %>
|
|
12
|
+
<div class="w-fit rounded-md border shadow-sm">
|
|
13
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
14
|
+
month: Date.new(2026, 8, 1),
|
|
15
|
+
selected: Date.new(2026, 8, 12)
|
|
16
|
+
)) %>
|
|
17
|
+
<div class="flex gap-3 border-t p-3">
|
|
18
|
+
<%= render(Shadcn::Field::Component.new(class: "flex-1")) do |field| %>
|
|
19
|
+
<% field.with_label(for: "calendar-start-time") { "Start Time" } %>
|
|
20
|
+
<% field.with_field_content do %>
|
|
21
|
+
<%= render(Shadcn::Input::Component.new(id: "calendar-start-time", type: "time", value: "09:00", step: 900)) %>
|
|
22
|
+
<% end %>
|
|
23
|
+
<% end %>
|
|
24
|
+
<%= render(Shadcn::Field::Component.new(class: "flex-1")) do |field| %>
|
|
25
|
+
<% field.with_label(for: "calendar-end-time") { "End Time" } %>
|
|
26
|
+
<% field.with_field_content do %>
|
|
27
|
+
<%= render(Shadcn::Input::Component.new(id: "calendar-end-time", type: "time", value: "17:00", step: 900)) %>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% end %>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# Upstream's "Calendar" example. The month is fixed rather than `Date.current`
|
|
2
|
+
so the snapshot does not change every day — the same reason the component
|
|
3
|
+
takes `month:` at all. %>
|
|
4
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
5
|
+
month: Date.new(2026, 8, 1),
|
|
6
|
+
selected: Date.new(2026, 8, 12),
|
|
7
|
+
class: "rounded-md border shadow-sm"
|
|
8
|
+
)) %>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%# Upstream's "Month and Year Selector": the caption becomes two native
|
|
2
|
+
`<select>`s laid invisible over the label, so the control is the real one and
|
|
3
|
+
what you read is the span underneath it. %>
|
|
4
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
5
|
+
month: Date.new(2026, 8, 1),
|
|
6
|
+
selected: Date.new(2026, 8, 12),
|
|
7
|
+
caption_layout: :dropdown,
|
|
8
|
+
start_month: Date.new(2020, 1, 1),
|
|
9
|
+
end_month: Date.new(2030, 12, 31),
|
|
10
|
+
class: "rounded-md border shadow-sm"
|
|
11
|
+
)) %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# The half a Rails form sees: the component renders the hidden inputs and the
|
|
2
|
+
controller rewrites them, so `params[:booking][:on]` is a date the model can
|
|
3
|
+
take. With a model, `f.shadcn_calendar :on` does all of this. %>
|
|
4
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
5
|
+
month: Date.new(2026, 8, 1),
|
|
6
|
+
name: "booking[on]",
|
|
7
|
+
class: "rounded-md border shadow-sm"
|
|
8
|
+
)) %>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<%# Upstream's "Presets": five shortcuts beside the month. Upstream's own
|
|
2
|
+
example holds them in React state; here the offset in days rides on the
|
|
3
|
+
button and the controller does the arithmetic, so a host writes no
|
|
4
|
+
JavaScript. The buttons are block content, which lands inside the root —
|
|
5
|
+
which is what lets their `data-action` reach the controller. %>
|
|
6
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
7
|
+
month: Date.current,
|
|
8
|
+
class: "rounded-md border shadow-sm"
|
|
9
|
+
)) do %>
|
|
10
|
+
<div class="flex flex-col gap-2 border-t pt-3">
|
|
11
|
+
<% { "Today" => 0, "Tomorrow" => 1, "In 3 days" => 3, "In a week" => 7, "In 2 weeks" => 14 }.each do |label, offset| %>
|
|
12
|
+
<%= render(Shadcn::Button::Component.new(
|
|
13
|
+
variant: :outline,
|
|
14
|
+
size: :sm,
|
|
15
|
+
"data-action": "click->shadcn--calendar#preset",
|
|
16
|
+
"data-shadcn--calendar-offset-param": offset
|
|
17
|
+
)) { label } %>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
<% end %>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%# Upstream's "Range Calendar": two months side by side and one range across
|
|
2
|
+
both. The two ends are two dates, so in a form they are two attributes —
|
|
3
|
+
`f.shadcn_calendar :starts_on, mode: :range, to: :ends_on`. %>
|
|
4
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
5
|
+
mode: :range,
|
|
6
|
+
month: Date.new(2026, 1, 1),
|
|
7
|
+
selected: Date.new(2026, 1, 12)..Date.new(2026, 2, 10),
|
|
8
|
+
number_of_months: 2,
|
|
9
|
+
class: "rounded-md border shadow-sm"
|
|
10
|
+
)) %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# Upstream's "Week Numbers". The number is ISO-8601 — `Date#cweek` — where
|
|
2
|
+
upstream's follows the locale, which is written up in features/calendar.md. %>
|
|
3
|
+
<%= render(Shadcn::Calendar::Component.new(
|
|
4
|
+
month: Date.new(2026, 1, 1),
|
|
5
|
+
selected: Date.new(2026, 1, 15),
|
|
6
|
+
show_week_number: true,
|
|
7
|
+
class: "rounded-md border shadow-sm"
|
|
8
|
+
)) %>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Card
|
|
5
|
+
# Port of registry/new-york-v4/ui/card.tsx
|
|
6
|
+
class Component < ApplicationViewComponent
|
|
7
|
+
renders_one :header, "Shadcn::Card::Header::Component"
|
|
8
|
+
renders_one :card_content, "Shadcn::Card::Content::Component"
|
|
9
|
+
renders_one :footer, "Shadcn::Card::Footer::Component"
|
|
10
|
+
|
|
11
|
+
slot_name :card
|
|
12
|
+
|
|
13
|
+
style do
|
|
14
|
+
base {
|
|
15
|
+
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm"
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
render_element(body: safe_join([ header, card_content, footer, content ].compact))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Card
|
|
5
|
+
module Header
|
|
6
|
+
class Component < ApplicationViewComponent
|
|
7
|
+
renders_one :title, "Shadcn::Card::Title::Component"
|
|
8
|
+
renders_one :description, "Shadcn::Card::Description::Component"
|
|
9
|
+
renders_one :action, "Shadcn::Card::Action::Component"
|
|
10
|
+
|
|
11
|
+
slot_name :"card-header"
|
|
12
|
+
|
|
13
|
+
style do
|
|
14
|
+
base {
|
|
15
|
+
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start " \
|
|
16
|
+
"gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6"
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call
|
|
21
|
+
render_element(body: safe_join([ title, description, action, content ].compact))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<%= render(Shadcn::Card::Component.new(class: "w-full max-w-sm")) do |card| %>
|
|
2
|
+
<% card.with_header do |h| %>
|
|
3
|
+
<% h.with_title { "Login to your account" } %>
|
|
4
|
+
<% h.with_description { "Enter your email below to login." } %>
|
|
5
|
+
<% h.with_action do %>
|
|
6
|
+
<%= render(Shadcn::Button::Component.new(variant: :link, size: :sm)) { "Sign Up" } %>
|
|
7
|
+
<% end %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% card.with_card_content do %>
|
|
10
|
+
<div class="flex flex-col gap-4">
|
|
11
|
+
<%= render(Shadcn::Label::Component.new(for: "email")) { "Email" } %>
|
|
12
|
+
<%= render(Shadcn::Input::Component.new(id: "email", type: "email", placeholder: "m@example.com")) %>
|
|
13
|
+
</div>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% card.with_footer(class: "flex-col gap-2") do %>
|
|
16
|
+
<%= render(Shadcn::Button::Component.new(class: "w-full")) { "Login" } %>
|
|
17
|
+
<% end %>
|
|
18
|
+
<% end %>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<%# Upstream's "Image": the picture is the card's first child, full width, and
|
|
2
|
+
the card's top padding comes off so it sits flush against the edge.
|
|
3
|
+
|
|
4
|
+
Everything is rendered in the *block*, none of it through the `header` and
|
|
5
|
+
`footer` slots. `Card#call` emits its slots and then the block, so an image
|
|
6
|
+
written first but passed as block content lands last — under the footer,
|
|
7
|
+
which is what the first version of this preview did. Upstream has no such
|
|
8
|
+
reordering: its Card renders `{children}` and the source order is the DOM
|
|
9
|
+
order. The select and dropdown previews render their items in the block for
|
|
10
|
+
the same reason.
|
|
11
|
+
|
|
12
|
+
Two more things are the caller's here and the component's there. The Card in
|
|
13
|
+
the registry this gem ports is `flex flex-col gap-6 rounded-xl border
|
|
14
|
+
bg-card py-6 …` and nothing else — no `has-[>img:first-child]:pt-0`, no
|
|
15
|
+
`*:[img:first-child]:rounded-t-xl` — so `pt-0` and `overflow-hidden` are
|
|
16
|
+
written out. Measured on the docs page on 2026-08-12, where the Card also
|
|
17
|
+
carries `--card-spacing`, `ring-1 ring-foreground/10` and a `size`, none of
|
|
18
|
+
which is in `vendor/shadcn/ui/card.tsx`: that is the other registry, and it
|
|
19
|
+
is why this is close rather than identical.
|
|
20
|
+
|
|
21
|
+
The footer's top padding is not written here: `card-footer` carries
|
|
22
|
+
`[.border-t]:pt-6`, so giving it a border is what asks for it.
|
|
23
|
+
|
|
24
|
+
A block of colour rather than a photograph: the gallery ships no binary
|
|
25
|
+
assets, and `aspect-video w-full` is the part of the shape that matters. %>
|
|
26
|
+
<%= render(Shadcn::Card::Component.new(class: "w-full max-w-sm overflow-hidden pt-0")) do %>
|
|
27
|
+
<div class="flex aspect-video w-full items-center justify-center bg-muted text-sm text-foreground/70">
|
|
28
|
+
Where the picture goes
|
|
29
|
+
</div>
|
|
30
|
+
<%= render(Shadcn::Card::Header::Component.new) do |h| %>
|
|
31
|
+
<% h.with_title { "Lakeside cabin" } %>
|
|
32
|
+
<% h.with_description { "Two bedrooms, one jetty." } %>
|
|
33
|
+
<% end %>
|
|
34
|
+
<%= render(Shadcn::Card::Footer::Component.new(class: "border-t bg-muted/50")) do %>
|
|
35
|
+
<%= render(Shadcn::Button::Component.new(class: "w-full")) { "Book" } %>
|
|
36
|
+
<% end %>
|
|
37
|
+
<% end %>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# The parts of the Card family that are just an element with a
|
|
5
|
+
# `data-slot` and a fixed set of classes. Anything with variants, slots or
|
|
6
|
+
# markup of its own keeps its own `component.rb`.
|
|
7
|
+
module Card
|
|
8
|
+
extend Parts
|
|
9
|
+
|
|
10
|
+
part :action, slot: "card-action",
|
|
11
|
+
classes: "col-start-2 row-span-2 row-start-1 self-start justify-self-end"
|
|
12
|
+
|
|
13
|
+
part :content, slot: "card-content", classes: "px-6"
|
|
14
|
+
|
|
15
|
+
part :description, slot: "card-description", classes: "text-sm text-muted-foreground"
|
|
16
|
+
|
|
17
|
+
part :footer, slot: "card-footer", classes: "flex items-center px-6 [.border-t]:pt-6"
|
|
18
|
+
|
|
19
|
+
part :title, slot: "card-title", classes: "leading-none font-semibold"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Carousel
|
|
5
|
+
# Port of registry/new-york-v4/ui/carousel.tsx
|
|
6
|
+
#
|
|
7
|
+
# Upstream builds this on **embla-carousel**, and this port does not. That
|
|
8
|
+
# is a measurement rather than a preference: of embla's 3,170 lines,
|
|
9
|
+
# `carousel.tsx` reaches for six things — `scrollPrev`, `scrollNext`,
|
|
10
|
+
# `canScrollPrev`, `canScrollNext` and the `select`/`reInit` events — and
|
|
11
|
+
# everything else about the component is flex markup and two buttons.
|
|
12
|
+
#
|
|
13
|
+
# The six are what a scroll container already answers. The viewport is a
|
|
14
|
+
# scroller with snap points, so the browser does the dragging, the momentum
|
|
15
|
+
# and the snapping, and this controller reads `scrollLeft` for the two
|
|
16
|
+
# `canScroll` questions and writes it for the two `scroll` ones. It is the
|
|
17
|
+
# same trade `scroll-area` made — the layout is CSS, and the controller
|
|
18
|
+
# computes a number per axis.
|
|
19
|
+
#
|
|
20
|
+
# What is *not* reproduced is in features/carousel.md: `opts` (embla's
|
|
21
|
+
# `loop`, `align`, `slidesToScroll`), the `api` object, its event stream,
|
|
22
|
+
# and plugins. None has markup, so `parity_spec` cannot see their absence;
|
|
23
|
+
# the feature doc is where that is written down.
|
|
24
|
+
class Component < ApplicationViewComponent
|
|
25
|
+
renders_one :carousel_content, "Shadcn::Carousel::Content::Component"
|
|
26
|
+
renders_one :previous, "Shadcn::Carousel::Previous::Component"
|
|
27
|
+
renders_one :next_control, "Shadcn::Carousel::Next::Component"
|
|
28
|
+
|
|
29
|
+
slot_name :carousel
|
|
30
|
+
|
|
31
|
+
style do
|
|
32
|
+
base { "relative" }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_reader :orientation
|
|
36
|
+
|
|
37
|
+
def initialize(orientation: :horizontal, **attributes)
|
|
38
|
+
@orientation = orientation&.to_sym == :vertical ? :vertical : :horizontal
|
|
39
|
+
super(**attributes)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def element_attributes(**defaults)
|
|
43
|
+
super(**{
|
|
44
|
+
role: "region",
|
|
45
|
+
"aria-roledescription" => "carousel",
|
|
46
|
+
"data-orientation" => orientation,
|
|
47
|
+
"data-controller" => "shadcn--carousel",
|
|
48
|
+
"data-shadcn--carousel-orientation-value" => orientation,
|
|
49
|
+
# Capture, as upstream does (`onKeyDownCapture`, carousel.tsx:119): a
|
|
50
|
+
# slide can hold controls of its own, and one that stops a keydown
|
|
51
|
+
# would otherwise take the carousel's arrows with it.
|
|
52
|
+
"data-action" => "keydown->shadcn--carousel#keydown:capture"
|
|
53
|
+
}.merge(defaults))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def call
|
|
57
|
+
render_element(body: safe_join([ carousel_content, previous, next_control, content ].compact))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Carousel
|
|
5
|
+
module Content
|
|
6
|
+
# CarouselContent — the viewport, with the flex track inside it.
|
|
7
|
+
#
|
|
8
|
+
# The viewport keeps upstream's `overflow-hidden` and nothing else, which
|
|
9
|
+
# matters: `overflow: hidden` still makes an element a scroll container,
|
|
10
|
+
# so `scrollLeft` works on it even though a person cannot drag it. What
|
|
11
|
+
# turns dragging back on is a rule in `shadcn.css` keyed on this
|
|
12
|
+
# `data-slot`, beside the one that hides the scroll area's scrollbars —
|
|
13
|
+
# the same shape of answer, in the same place.
|
|
14
|
+
class Component < ApplicationViewComponent
|
|
15
|
+
renders_many :items, "Shadcn::Carousel::Item::Component"
|
|
16
|
+
|
|
17
|
+
slot_name :"carousel-content"
|
|
18
|
+
|
|
19
|
+
style do
|
|
20
|
+
base { "overflow-hidden" }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :orientation
|
|
24
|
+
|
|
25
|
+
def initialize(orientation: :horizontal, **attributes)
|
|
26
|
+
@orientation = orientation&.to_sym == :vertical ? :vertical : :horizontal
|
|
27
|
+
# Held for the track and kept off the viewport, which is upstream's
|
|
28
|
+
# arrangement: `{...props}` and the className land on the inner div.
|
|
29
|
+
@track = attributes
|
|
30
|
+
super()
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The caller's attributes went to the track above, so the viewport is
|
|
34
|
+
# given only its own.
|
|
35
|
+
def element_attributes(**defaults)
|
|
36
|
+
super(**{
|
|
37
|
+
# Upstream sets no tabindex, and upstream's viewport is not a
|
|
38
|
+
# scroller: embla translates a track inside a hidden overflow, so
|
|
39
|
+
# there is no region for a keyboard to be shut out of. Ours is a
|
|
40
|
+
# scroller, which is the whole mechanism, and axe fails a scrollable
|
|
41
|
+
# region with no keyboard access — the same divergence, for the same
|
|
42
|
+
# reason, as `scroll-area-viewport`.
|
|
43
|
+
#
|
|
44
|
+
# It earns its place beyond the audit: Tab reaches the slides and
|
|
45
|
+
# the arrows move them, where before the only way through was the
|
|
46
|
+
# two buttons.
|
|
47
|
+
tabindex: "0",
|
|
48
|
+
role: "group",
|
|
49
|
+
"aria-roledescription" => "slides",
|
|
50
|
+
"data-orientation" => orientation,
|
|
51
|
+
"data-shadcn--carousel-target" => "viewport"
|
|
52
|
+
}.merge(defaults))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Upstream gives the *track* the caller's className and leaves the
|
|
56
|
+
# viewport with `overflow-hidden` and nothing else (carousel.tsx:138-152).
|
|
57
|
+
# This port had it the other way round, so a preview asking for a
|
|
58
|
+
# smaller gutter with `-ml-2` put it on the viewport, where it does
|
|
59
|
+
# nothing, while the track kept `-ml-4` and the items took `pl-2`. A
|
|
60
|
+
# gutter that disagrees with its own padding is a slide whose content
|
|
61
|
+
# starts outside the window, which is a card with no left border.
|
|
62
|
+
def call
|
|
63
|
+
render_element(body: tag.div(safe_join([ items, content ].flatten.compact), **track_attributes))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def track_attributes
|
|
69
|
+
extra = @track.except(:class, "class")
|
|
70
|
+
|
|
71
|
+
# Merged rather than concatenated: a caller asking for a smaller gutter
|
|
72
|
+
# passes `-ml-2`, and `flex -ml-4 -ml-2` leaves both in the attribute
|
|
73
|
+
# for the cascade to arbitrate. `cn` is what resolves that everywhere
|
|
74
|
+
# else in this port.
|
|
75
|
+
extra.merge(class: ShadcnViewComponent.cn(track_classes, @track[:class] || @track["class"]))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def track_classes
|
|
79
|
+
horizontal? ? "flex -ml-4" : "flex -mt-4 flex-col"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def horizontal? = orientation == :horizontal
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Carousel
|
|
5
|
+
module Item
|
|
6
|
+
# CarouselItem — one slide, full width until the caller says otherwise
|
|
7
|
+
# with a `basis-*` of its own, which is upstream's "Sizes" example.
|
|
8
|
+
class Component < ApplicationViewComponent
|
|
9
|
+
slot_name :"carousel-item"
|
|
10
|
+
|
|
11
|
+
style do
|
|
12
|
+
base { "min-w-0 shrink-0 grow-0 basis-full" }
|
|
13
|
+
|
|
14
|
+
variants {
|
|
15
|
+
orientation {
|
|
16
|
+
horizontal { "pl-4" }
|
|
17
|
+
vertical { "pt-4" }
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
defaults { { orientation: :horizontal } }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_reader :orientation
|
|
25
|
+
|
|
26
|
+
def initialize(orientation: :horizontal, **attributes)
|
|
27
|
+
@orientation = orientation&.to_sym == :vertical ? :vertical : :horizontal
|
|
28
|
+
super(**attributes)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def style_variants = { orientation: }
|
|
32
|
+
|
|
33
|
+
def element_attributes(**defaults)
|
|
34
|
+
super(**{
|
|
35
|
+
role: "group",
|
|
36
|
+
"aria-roledescription" => "slide"
|
|
37
|
+
}.merge(defaults))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Carousel
|
|
5
|
+
module Next
|
|
6
|
+
# CarouselNext — the button's own variants, as `pagination-link` takes
|
|
7
|
+
# them: upstream renders a `<Button variant="outline" size="icon">` and
|
|
8
|
+
# adds its placement on top, so the classes come from
|
|
9
|
+
# `Button.variant_classes` rather than from a style block of this
|
|
10
|
+
# component's own. Redefining `style` here would *replace* the button's
|
|
11
|
+
# base rather than add to it, which is a round control with no round.
|
|
12
|
+
class Component < ApplicationViewComponent
|
|
13
|
+
default_tag :button
|
|
14
|
+
slot_name :"carousel-next"
|
|
15
|
+
|
|
16
|
+
PLACEMENT = {
|
|
17
|
+
horizontal: "top-1/2 -right-12 -translate-y-1/2",
|
|
18
|
+
vertical: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90"
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
attr_reader :orientation, :variant, :size
|
|
22
|
+
|
|
23
|
+
def initialize(orientation: :horizontal, variant: :outline, size: :icon, **attributes)
|
|
24
|
+
@orientation = orientation&.to_sym == :vertical ? :vertical : :horizontal
|
|
25
|
+
@variant = variant&.to_sym || :outline
|
|
26
|
+
@size = size&.to_sym || :icon
|
|
27
|
+
super(**attributes)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Disabled until the controller says otherwise: at rest a carousel is at
|
|
31
|
+
# one end, and which end has room is a question about a viewport the
|
|
32
|
+
# server has never measured.
|
|
33
|
+
def element_attributes(**defaults)
|
|
34
|
+
super(**{
|
|
35
|
+
type: "button",
|
|
36
|
+
disabled: true,
|
|
37
|
+
"data-shadcn--carousel-target" => "next",
|
|
38
|
+
"data-action" => "click->shadcn--carousel#next"
|
|
39
|
+
}.merge(defaults))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def css_classes(extra = nil)
|
|
43
|
+
Button::Component.variant_classes(
|
|
44
|
+
variant:,
|
|
45
|
+
size:,
|
|
46
|
+
class: [ "absolute size-8 rounded-full", PLACEMENT.fetch(orientation), extra ].compact.join(" ")
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def call
|
|
51
|
+
render_element(body: safe_join([
|
|
52
|
+
render(Icon::Component.new("arrow-right")),
|
|
53
|
+
tag.span(shadcn_t("carousel.next"), class: "sr-only")
|
|
54
|
+
]))
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Carousel
|
|
5
|
+
class Preview < ApplicationViewComponentPreview
|
|
6
|
+
def default
|
|
7
|
+
render_with_template
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Upstream's "Sizes" and "Spacing": both are the caller's classes on the
|
|
11
|
+
# item, which is why neither is an argument.
|
|
12
|
+
def sizes
|
|
13
|
+
render_with_template
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Upstream's "Orientation".
|
|
17
|
+
def vertical
|
|
18
|
+
render_with_template
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%# Upstream's own example: five slides, each the width of the viewport, with
|
|
2
|
+
the two controls sitting outside the box — `-left-12` and `-right-12`, which
|
|
3
|
+
is why the page needs room around it. %>
|
|
4
|
+
<div class="px-14">
|
|
5
|
+
<%= render(Shadcn::Carousel::Component.new(class: "w-full max-w-xs")) do |c| %>
|
|
6
|
+
<% c.with_carousel_content do |content| %>
|
|
7
|
+
<% 5.times do |i| %>
|
|
8
|
+
<% content.with_item do %>
|
|
9
|
+
<div class="p-1">
|
|
10
|
+
<%= render(Shadcn::Card::Component.new) do |card| %>
|
|
11
|
+
<% card.with_card_content(class: "flex aspect-square items-center justify-center p-6") do %>
|
|
12
|
+
<span class="text-4xl font-semibold"><%= i + 1 %></span>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|
|
18
|
+
<% end %>
|
|
19
|
+
<% c.with_previous %>
|
|
20
|
+
<% c.with_next_control %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|