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,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module InputGroup
|
|
5
|
+
class Preview < ApplicationViewComponentPreview
|
|
6
|
+
def default
|
|
7
|
+
render_with_template
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Upstream's "Icon", "Kbd", "Dropdown" and "Spinner" — what an addon holds,
|
|
11
|
+
# where the default preview shows where an addon sits.
|
|
12
|
+
def addons
|
|
13
|
+
render_with_template
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<%# Upstream's "Icon", "Kbd", "Dropdown" and "Spinner": four things an addon
|
|
2
|
+
holds that the default preview does not show, which has text, buttons and a
|
|
3
|
+
textarea.
|
|
4
|
+
|
|
5
|
+
An addon is a slot for anything — its only argument is `align:`, and the
|
|
6
|
+
default preview covers all four of those. What changes here is what goes
|
|
7
|
+
inside one. %>
|
|
8
|
+
<div class="flex w-full max-w-md flex-col gap-6">
|
|
9
|
+
<%# An icon, which is the commonest case and the reason the addon has no
|
|
10
|
+
padding of its own. %>
|
|
11
|
+
<%= render(Shadcn::InputGroup::Component.new) do %>
|
|
12
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new) do %>
|
|
13
|
+
<%= render(Shadcn::Icon::Component.new("search")) %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<%= render(Shadcn::InputGroup::Input::Component.new(placeholder: "Search", "aria-label": "Search")) %>
|
|
16
|
+
<% end %>
|
|
17
|
+
|
|
18
|
+
<%# A shortcut on the trailing edge, which is what `Kbd` is for. %>
|
|
19
|
+
<%= render(Shadcn::InputGroup::Component.new) do %>
|
|
20
|
+
<%= render(Shadcn::InputGroup::Input::Component.new(placeholder: "Search commands", "aria-label": "Search commands")) %>
|
|
21
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new(align: :"inline-end")) do %>
|
|
22
|
+
<%= render(Shadcn::Kbd::Group::Component.new) do %>
|
|
23
|
+
<%= render(Shadcn::Kbd::Component.new) { "⌘" } %>
|
|
24
|
+
<%= render(Shadcn::Kbd::Component.new) { "K" } %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% end %>
|
|
28
|
+
|
|
29
|
+
<%# A menu hanging off the addon's own button. %>
|
|
30
|
+
<%= render(Shadcn::InputGroup::Component.new) do %>
|
|
31
|
+
<%= render(Shadcn::InputGroup::Input::Component.new(placeholder: "you@example.com", "aria-label": "Email")) %>
|
|
32
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new(align: :"inline-end")) do %>
|
|
33
|
+
<%= render(Shadcn::DropdownMenu::Component.new) do |m| %>
|
|
34
|
+
<% m.with_trigger(as: :button, class: "inline-flex items-center gap-1 text-sm text-muted-foreground") do %>
|
|
35
|
+
Work
|
|
36
|
+
<%= render(Shadcn::Icon::Component.new("chevron-down")) %>
|
|
37
|
+
<% end %>
|
|
38
|
+
<% m.with_menu_content(class: "w-56") do %>
|
|
39
|
+
<%= render(Shadcn::DropdownMenu::Item::Component.new) { "Work" } %>
|
|
40
|
+
<%= render(Shadcn::DropdownMenu::Item::Component.new) { "Personal" } %>
|
|
41
|
+
<% end %>
|
|
42
|
+
<% end %>
|
|
43
|
+
<% end %>
|
|
44
|
+
<% end %>
|
|
45
|
+
|
|
46
|
+
<%# A spinner, for a field that is checking something as you type. %>
|
|
47
|
+
<%= render(Shadcn::InputGroup::Component.new) do %>
|
|
48
|
+
<%= render(Shadcn::InputGroup::Input::Component.new(value: "octocat", "aria-label": "Username")) %>
|
|
49
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new(align: :"inline-end")) do %>
|
|
50
|
+
<%= render(Shadcn::Spinner::Component.new) %>
|
|
51
|
+
<% end %>
|
|
52
|
+
<% end %>
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<div class="flex w-full max-w-md flex-col gap-6">
|
|
2
|
+
<%= render(Shadcn::InputGroup::Component.new) do %>
|
|
3
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new) do %>
|
|
4
|
+
<%= render(Shadcn::InputGroup::Text::Component.new) { "https://" } %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<%= render(Shadcn::InputGroup::Input::Component.new(placeholder: "example.com")) %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
9
|
+
<%= render(Shadcn::InputGroup::Component.new) do %>
|
|
10
|
+
<%= render(Shadcn::InputGroup::Input::Component.new(placeholder: "Search")) %>
|
|
11
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new(align: :"inline-end")) do %>
|
|
12
|
+
<%= render(Shadcn::InputGroup::Button::Component.new) { "Go" } %>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<%= render(Shadcn::InputGroup::Component.new) do %>
|
|
17
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new(align: :"block-start")) do %>
|
|
18
|
+
<%= render(Shadcn::InputGroup::Text::Component.new) { "Describe the issue" } %>
|
|
19
|
+
<% end %>
|
|
20
|
+
<%= render(Shadcn::InputGroup::Textarea::Component.new(placeholder: "What happened?")) %>
|
|
21
|
+
<%= render(Shadcn::InputGroup::Addon::Component.new(align: :"block-end")) do %>
|
|
22
|
+
<%= render(Shadcn::InputGroup::Button::Component.new(size: :sm)) { "Submit" } %>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module InputGroup
|
|
5
|
+
module Text
|
|
6
|
+
# InputGroupText. A `<span>`, and like ButtonGroupText it carries no
|
|
7
|
+
# `data-slot` upstream, so it is not given one here.
|
|
8
|
+
class Component < ApplicationViewComponent
|
|
9
|
+
default_tag :span
|
|
10
|
+
|
|
11
|
+
style do
|
|
12
|
+
base {
|
|
13
|
+
"flex items-center gap-2 text-sm text-muted-foreground " \
|
|
14
|
+
"[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4"
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module InputGroup
|
|
5
|
+
module Textarea
|
|
6
|
+
# InputGroupTextarea renders the ported Textarea, and shares
|
|
7
|
+
# `data-slot="input-group-control"` with InputGroupInput — see that file
|
|
8
|
+
# for why the two must not be told apart.
|
|
9
|
+
class Component < Shadcn::Textarea::Component
|
|
10
|
+
slot_name :"input-group-control"
|
|
11
|
+
|
|
12
|
+
EXTRA_CLASSES = "flex-1 resize-none rounded-none border-0 bg-transparent py-3 " \
|
|
13
|
+
"shadow-none focus-visible:ring-0 dark:bg-transparent"
|
|
14
|
+
|
|
15
|
+
def css_classes(extra = nil)
|
|
16
|
+
super([ EXTRA_CLASSES, extra ].compact.join(" "))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module InputOtp
|
|
5
|
+
# Port of registry/new-york-v4/ui/input-otp.tsx
|
|
6
|
+
#
|
|
7
|
+
# Upstream builds this on the **input-otp** package, and this port does not.
|
|
8
|
+
# Measured: of its 715 lines, `input-otp.tsx` uses the root component and,
|
|
9
|
+
# per box, three values — `char`, `isActive` and `hasFakeCaret`. The rule
|
|
10
|
+
# behind them is six lines (input.tsx:596-618), and the mechanism under it
|
|
11
|
+
# is one real `<input>` laid invisibly over the boxes, which is what makes
|
|
12
|
+
# typing, paste, backspace, the arrow keys and a one-time-code autofill the
|
|
13
|
+
# browser's problem rather than ours.
|
|
14
|
+
#
|
|
15
|
+
# What the 715 lines mostly are is the part that cannot be ported by
|
|
16
|
+
# reading: 21 of them name Safari, iOS, a password manager or a selection
|
|
17
|
+
# quirk. features/input-otp.md says which of those this port answers and
|
|
18
|
+
# which it does not.
|
|
19
|
+
#
|
|
20
|
+
# The shape is upstream's, read from the rendered demo rather than from the
|
|
21
|
+
# TSX, which shows none of it: the boxes come first, and the input sits over
|
|
22
|
+
# them in an absolutely positioned layer.
|
|
23
|
+
class Component < ApplicationViewComponent
|
|
24
|
+
slot_name :"input-otp-container"
|
|
25
|
+
|
|
26
|
+
style do
|
|
27
|
+
base { "flex items-center gap-2 has-disabled:opacity-50" }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Everything the input needs to be a real one. `disabled:cursor-not-allowed`
|
|
31
|
+
# is upstream's class for it; the rest of its look is a rule in
|
|
32
|
+
# `shadcn.css`, because it is a technique rather than a style — see there.
|
|
33
|
+
INPUT_CLASSES = "disabled:cursor-not-allowed"
|
|
34
|
+
|
|
35
|
+
attr_reader :max_length, :name, :value, :disabled, :pattern, :autofocus, :input_attributes
|
|
36
|
+
|
|
37
|
+
def initialize(max_length: 6, name: nil, value: nil, disabled: false, pattern: nil,
|
|
38
|
+
autofocus: false, input: {}, **attributes)
|
|
39
|
+
@max_length = max_length.to_i
|
|
40
|
+
@name = name
|
|
41
|
+
@value = value.to_s
|
|
42
|
+
@disabled = disabled
|
|
43
|
+
@pattern = pattern
|
|
44
|
+
@autofocus = autofocus
|
|
45
|
+
@input_attributes = input
|
|
46
|
+
super(**attributes)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def element_attributes(**defaults)
|
|
50
|
+
super(**{
|
|
51
|
+
style: merged_style("position:relative"),
|
|
52
|
+
"data-controller" => "shadcn--input-otp",
|
|
53
|
+
"data-shadcn--input-otp-length-value" => max_length
|
|
54
|
+
}.merge(defaults))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def call
|
|
58
|
+
render_element(body: safe_join([ content, overlay ]))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Upstream's own arrangement: the boxes are the page, and the input is a
|
|
64
|
+
# layer over them that takes the pointer while the layer itself does not.
|
|
65
|
+
def overlay
|
|
66
|
+
tag.div(input, style: "position:absolute;inset:0;pointer-events:none")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def input
|
|
70
|
+
tag.input(**{
|
|
71
|
+
"data-slot": "input-otp",
|
|
72
|
+
"data-shadcn--input-otp-target": "input",
|
|
73
|
+
"data-action": "input->shadcn--input-otp#entered " \
|
|
74
|
+
"select->shadcn--input-otp#refresh " \
|
|
75
|
+
"keyup->shadcn--input-otp#refresh " \
|
|
76
|
+
"click->shadcn--input-otp#refresh " \
|
|
77
|
+
"focus->shadcn--input-otp#focus " \
|
|
78
|
+
"blur->shadcn--input-otp#refresh",
|
|
79
|
+
class: INPUT_CLASSES,
|
|
80
|
+
value: value.presence,
|
|
81
|
+
name:,
|
|
82
|
+
maxlength: max_length,
|
|
83
|
+
disabled: (true if disabled),
|
|
84
|
+
autofocus: (true if autofocus),
|
|
85
|
+
pattern:,
|
|
86
|
+
# The three that make a phone offer the code from a message, and stop
|
|
87
|
+
# a keyboard offering everything else.
|
|
88
|
+
autocomplete: "one-time-code",
|
|
89
|
+
inputmode: "numeric",
|
|
90
|
+
spellcheck: "false"
|
|
91
|
+
}.compact.merge(input_attributes))
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module InputOtp
|
|
5
|
+
class Preview < ApplicationViewComponentPreview
|
|
6
|
+
def default
|
|
7
|
+
render_with_template
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Upstream's "Pattern", "Separator" and "Disabled" — and the FormBuilder,
|
|
11
|
+
# since a code that is not submitted is a code for nothing.
|
|
12
|
+
def variations
|
|
13
|
+
render_with_template
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<%# Upstream's own example: six boxes, one real input over them.
|
|
2
|
+
|
|
3
|
+
Type into it and the boxes fill; the caret is drawn by the active box rather
|
|
4
|
+
than by the input, whose own is transparent. Paste a six-digit code and it
|
|
5
|
+
lands in one go, because the field the browser sees is an ordinary input.
|
|
6
|
+
|
|
7
|
+
Labelled, and that is the caller's job here as it is upstream's: there is one
|
|
8
|
+
input and it takes a name the way any input does. Unlabelled it fails axe,
|
|
9
|
+
which is how this preview shipped for about an hour. %>
|
|
10
|
+
<div class="flex flex-col gap-2">
|
|
11
|
+
<%= render(Shadcn::Label::Component.new(for: "otp-code")) { "Verification code" } %>
|
|
12
|
+
<%= render(Shadcn::InputOtp::Component.new(max_length: 6, name: "code", input: { id: "otp-code" })) do %>
|
|
13
|
+
<%= render(Shadcn::InputOtp::Group::Component.new) do %>
|
|
14
|
+
<% 6.times do %>
|
|
15
|
+
<%= render(Shadcn::InputOtp::Slot::Component.new) %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<%# Upstream's "Separator", "Pattern" and "Disabled".
|
|
2
|
+
|
|
3
|
+
The separator is markup rather than an argument — two groups with a minus
|
|
4
|
+
between them — which is why the component takes no "grouping" option. The
|
|
5
|
+
pattern and the input mode are the input's own attributes, passed through
|
|
6
|
+
`input:`: this port has one input and hands the caller its keys rather than
|
|
7
|
+
inventing arguments for each. %>
|
|
8
|
+
<div class="flex flex-col gap-8">
|
|
9
|
+
<%= render(Shadcn::InputOtp::Component.new(max_length: 6, name: "grouped", input: { "aria-label": "Grouped code" })) do %>
|
|
10
|
+
<%= render(Shadcn::InputOtp::Group::Component.new) do %>
|
|
11
|
+
<% 3.times do %><%= render(Shadcn::InputOtp::Slot::Component.new) %><% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%= render(Shadcn::InputOtp::Separator::Component.new) %>
|
|
14
|
+
<%= render(Shadcn::InputOtp::Group::Component.new) do %>
|
|
15
|
+
<% 3.times do %><%= render(Shadcn::InputOtp::Slot::Component.new) %><% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
19
|
+
<%= render(Shadcn::InputOtp::Component.new(
|
|
20
|
+
max_length: 4, name: "letters",
|
|
21
|
+
input: { inputmode: "text", pattern: "[A-Za-z]*", "aria-label": "Letters only" }
|
|
22
|
+
)) do %>
|
|
23
|
+
<%= render(Shadcn::InputOtp::Group::Component.new) do %>
|
|
24
|
+
<% 4.times do %><%= render(Shadcn::InputOtp::Slot::Component.new) %><% end %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
27
|
+
|
|
28
|
+
<%= render(Shadcn::InputOtp::Component.new(max_length: 4, value: "1234", disabled: true, input: { "aria-label": "Disabled code" })) do %>
|
|
29
|
+
<%= render(Shadcn::InputOtp::Group::Component.new) do %>
|
|
30
|
+
<% 4.times do %><%= render(Shadcn::InputOtp::Slot::Component.new) %><% end %>
|
|
31
|
+
<% end %>
|
|
32
|
+
<% end %>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module InputOtp
|
|
5
|
+
module Separator
|
|
6
|
+
# InputOTPSeparator — a minus between two groups. Upstream gives it a role
|
|
7
|
+
# and no classes at all.
|
|
8
|
+
class Component < ApplicationViewComponent
|
|
9
|
+
slot_name :"input-otp-separator"
|
|
10
|
+
|
|
11
|
+
def element_attributes(**defaults)
|
|
12
|
+
super(**{ role: "separator" }.merge(defaults))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
render_element(body: render(Icon::Component.new("minus")))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module InputOtp
|
|
5
|
+
module Slot
|
|
6
|
+
# InputOTPSlot — one box. It holds no state of its own: the character, the
|
|
7
|
+
# active mark and the caret are all written by the controller from the one
|
|
8
|
+
# input's value and selection.
|
|
9
|
+
#
|
|
10
|
+
# Upstream takes an `index`; this reads the boxes in the order they appear,
|
|
11
|
+
# which is the same answer without a number for a caller to get wrong.
|
|
12
|
+
class Component < ApplicationViewComponent
|
|
13
|
+
CARET_CLASSES = "pointer-events-none absolute inset-0 flex items-center justify-center"
|
|
14
|
+
BAR_CLASSES = "h-4 w-px animate-caret-blink bg-foreground duration-1000"
|
|
15
|
+
|
|
16
|
+
slot_name :"input-otp-slot"
|
|
17
|
+
|
|
18
|
+
style do
|
|
19
|
+
base {
|
|
20
|
+
"relative flex h-9 w-9 items-center justify-center border-y border-r border-input " \
|
|
21
|
+
"text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l " \
|
|
22
|
+
"last:rounded-r-md aria-invalid:border-destructive data-[active=true]:z-10 " \
|
|
23
|
+
"data-[active=true]:border-ring data-[active=true]:ring-[3px] " \
|
|
24
|
+
"data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive " \
|
|
25
|
+
"data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 " \
|
|
26
|
+
"dark:data-[active=true]:aria-invalid:ring-destructive/40"
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def element_attributes(**defaults)
|
|
31
|
+
super(**{
|
|
32
|
+
"data-active" => "false",
|
|
33
|
+
"data-shadcn--input-otp-target" => "slot"
|
|
34
|
+
}.merge(defaults))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def call
|
|
38
|
+
render_element(body: safe_join([ character, caret ]))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def character
|
|
44
|
+
tag.span("data-shadcn--input-otp-target": "char")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Rendered always and hidden until the box is both active and empty,
|
|
48
|
+
# which is upstream's `hasFakeCaret`. Server-rendered rather than
|
|
49
|
+
# created on demand: a component that adds elements from JavaScript is a
|
|
50
|
+
# component `turbo:morph` argues with.
|
|
51
|
+
def caret
|
|
52
|
+
tag.div(tag.div(class: BAR_CLASSES),
|
|
53
|
+
class: CARET_CLASSES,
|
|
54
|
+
hidden: true,
|
|
55
|
+
"data-shadcn--input-otp-target": "caret")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# The parts of the InputOTP family that are just an element with a
|
|
5
|
+
# `data-slot` and a fixed set of classes.
|
|
6
|
+
module InputOtp
|
|
7
|
+
extend Parts
|
|
8
|
+
|
|
9
|
+
part :group, slot: "input-otp-group", classes: "flex items-center"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Item
|
|
5
|
+
# Port of registry/new-york-v4/ui/item.tsx
|
|
6
|
+
#
|
|
7
|
+
# `group/item` is half a mechanism: `ItemMedia`'s
|
|
8
|
+
# `group-has-[[data-slot=item-description]]/item:…` classes reach back into
|
|
9
|
+
# this named group to shift the media when a description is present. Both
|
|
10
|
+
# halves have to stay exactly as upstream wrote them — parity checks that
|
|
11
|
+
# each class exists, not that they still refer to each other.
|
|
12
|
+
class Component < ApplicationViewComponent
|
|
13
|
+
slot_name :item
|
|
14
|
+
|
|
15
|
+
style do
|
|
16
|
+
base {
|
|
17
|
+
"group/item flex flex-wrap items-center rounded-md border border-transparent " \
|
|
18
|
+
"text-sm transition-colors duration-100 outline-none focus-visible:border-ring " \
|
|
19
|
+
"focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors " \
|
|
20
|
+
"[a]:hover:bg-accent/50"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
variants {
|
|
24
|
+
variant {
|
|
25
|
+
default { "bg-transparent" }
|
|
26
|
+
outline { "border-border" }
|
|
27
|
+
muted { "bg-muted/50" }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
size {
|
|
31
|
+
default { "gap-4 p-4" }
|
|
32
|
+
sm { "gap-2.5 px-4 py-3" }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
defaults { { variant: :default, size: :default } }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :variant, :size
|
|
40
|
+
|
|
41
|
+
def initialize(variant: :default, size: :default, **attributes)
|
|
42
|
+
@variant = variant&.to_sym || :default
|
|
43
|
+
@size = size&.to_sym || :default
|
|
44
|
+
super(**attributes)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def style_variants
|
|
48
|
+
{ variant:, size: }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def element_attributes(**defaults)
|
|
52
|
+
super(**{ "data-variant" => variant, "data-size" => size }.merge(defaults))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Item
|
|
5
|
+
module Group
|
|
6
|
+
# ItemGroup. Only a `data-slot` and classes apart from `role="list"`,
|
|
7
|
+
# which is why it is not a `part` — the macro declares no attributes.
|
|
8
|
+
#
|
|
9
|
+
# **`role="list"` obliges its children to be `role="listitem"`, and `Item`
|
|
10
|
+
# carries no role.** Adding one to `Item` itself would deviate from
|
|
11
|
+
# upstream's markup, so it is added here instead, through the `items`
|
|
12
|
+
# slot — the same layer the FormBuilder uses to supply the accessible
|
|
13
|
+
# name that Select and Switch cannot give themselves. A bare
|
|
14
|
+
# `Item::Component`, rendered outside this slot, still carries no role,
|
|
15
|
+
# exactly as upstream has it.
|
|
16
|
+
#
|
|
17
|
+
# `ItemSeparator` goes through the same slot rather than the block:
|
|
18
|
+
# `items` renders before block content (see `Card::Component`), so a
|
|
19
|
+
# separator placed as plain block content between two `with_item` calls
|
|
20
|
+
# would land after both of them instead of between them — the trap
|
|
21
|
+
# CLAUDE.md warns about. A polymorphic slot keeps both in the one
|
|
22
|
+
# ordered collection, where call order is preserved, and gives the
|
|
23
|
+
# separator its own setter (`with_separator`) rather than a flag that
|
|
24
|
+
# would otherwise let `Item` attributes reach a `role="none"` element.
|
|
25
|
+
class Component < ApplicationViewComponent
|
|
26
|
+
renders_many :items, types: {
|
|
27
|
+
item: {
|
|
28
|
+
renders: ->(**attributes) { Shadcn::Item::Component.new(role: "listitem", **attributes) },
|
|
29
|
+
as: :item
|
|
30
|
+
},
|
|
31
|
+
separator: {
|
|
32
|
+
renders: ->(**attributes) { Shadcn::Item::Separator::Component.new(**attributes) },
|
|
33
|
+
as: :separator
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
slot_name :"item-group"
|
|
38
|
+
|
|
39
|
+
style do
|
|
40
|
+
base { "group/item-group flex flex-col" }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def element_attributes(**defaults)
|
|
44
|
+
super(**{ role: "list" }.merge(defaults))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def call
|
|
48
|
+
render_element(body: safe_join([ *items, content ].compact))
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Item
|
|
5
|
+
module Media
|
|
6
|
+
# ItemMedia. Its base classes reach into the named group `Item` opens
|
|
7
|
+
# (`group-has-[[data-slot=item-description]]/item:…`) to shift the media
|
|
8
|
+
# down when the item has a description. That only works while `Item`
|
|
9
|
+
# still carries `group/item`.
|
|
10
|
+
class Component < ApplicationViewComponent
|
|
11
|
+
slot_name :"item-media"
|
|
12
|
+
|
|
13
|
+
style do
|
|
14
|
+
base {
|
|
15
|
+
"flex shrink-0 items-center justify-center gap-2 " \
|
|
16
|
+
"group-has-[[data-slot=item-description]]/item:translate-y-0.5 " \
|
|
17
|
+
"group-has-[[data-slot=item-description]]/item:self-start " \
|
|
18
|
+
"[&_svg]:pointer-events-none"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
variants {
|
|
22
|
+
variant {
|
|
23
|
+
default { "bg-transparent" }
|
|
24
|
+
icon {
|
|
25
|
+
"size-8 rounded-sm border bg-muted [&_svg:not([class*='size-'])]:size-4"
|
|
26
|
+
}
|
|
27
|
+
image {
|
|
28
|
+
"size-10 overflow-hidden rounded-sm [&_img]:size-full [&_img]:object-cover"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
defaults { { variant: :default } }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
attr_reader :variant
|
|
37
|
+
|
|
38
|
+
def initialize(variant: :default, **attributes)
|
|
39
|
+
@variant = variant&.to_sym || :default
|
|
40
|
+
super(**attributes)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def style_variants
|
|
44
|
+
{ variant: }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def element_attributes(**defaults)
|
|
48
|
+
super(**{ "data-variant" => variant }.merge(defaults))
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Item
|
|
5
|
+
class Preview < ApplicationViewComponentPreview
|
|
6
|
+
def default
|
|
7
|
+
render_with_template
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def outline
|
|
11
|
+
render_with_template
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Upstream's "Link", "Avatar" and "Image".
|
|
15
|
+
def link
|
|
16
|
+
render_with_template
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<%= render(Shadcn::Item::Group::Component.new(class: "w-full max-w-md")) do |group| %>
|
|
2
|
+
<% group.with_item do %>
|
|
3
|
+
<%= render(Shadcn::Item::Media::Component.new(variant: :icon)) do %>
|
|
4
|
+
<%= render(Shadcn::Icon::Component.new("circle")) %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<%= render(Shadcn::Item::Content::Component.new) do %>
|
|
7
|
+
<%= render(Shadcn::Item::Title::Component.new) { "Basic plan" } %>
|
|
8
|
+
<%= render(Shadcn::Item::Description::Component.new) do %>
|
|
9
|
+
Everything you need to get started, with <a href="#">no card required</a>.
|
|
10
|
+
<% end %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<%= render(Shadcn::Item::Actions::Component.new) do %>
|
|
13
|
+
<%= render(Shadcn::Button::Component.new(variant: :outline, size: :sm)) { "Choose" } %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
16
|
+
|
|
17
|
+
<% group.with_separator %>
|
|
18
|
+
|
|
19
|
+
<% group.with_item(variant: :muted, size: :sm) do %>
|
|
20
|
+
<%= render(Shadcn::Item::Header::Component.new) do %>
|
|
21
|
+
<%= render(Shadcn::Item::Title::Component.new) { "Pro plan" } %>
|
|
22
|
+
<%= render(Shadcn::Badge::Component.new) { "Popular" } %>
|
|
23
|
+
<% end %>
|
|
24
|
+
<%= render(Shadcn::Item::Content::Component.new) do %>
|
|
25
|
+
<%= render(Shadcn::Item::Description::Component.new) { "For teams shipping every day." } %>
|
|
26
|
+
<% end %>
|
|
27
|
+
<%= render(Shadcn::Item::Footer::Component.new) do %>
|
|
28
|
+
<%= render(Shadcn::Item::Description::Component.new) { "$20 per seat" } %>
|
|
29
|
+
<%= render(Shadcn::Button::Component.new(size: :sm)) { "Upgrade" } %>
|
|
30
|
+
<% end %>
|
|
31
|
+
<% end %>
|
|
32
|
+
<% end %>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<%# Upstream's "Link", "Avatar" and "Image".
|
|
2
|
+
|
|
3
|
+
An item that is a link is the whole element, not a link inside it: `as: :a`
|
|
4
|
+
is this port's `asChild`, so the row keeps its slots and its variants and
|
|
5
|
+
becomes an anchor. The media variants are the other half — `icon` is in the
|
|
6
|
+
default preview, `image` and the plain `default` are not.
|
|
7
|
+
|
|
8
|
+
Not inside an `ItemGroup`, and that is the point rather than an omission.
|
|
9
|
+
The group is `role="list"`, which may only hold `listitem` children, and
|
|
10
|
+
neither upstream's `Item` nor this one sets that role — so an item that
|
|
11
|
+
becomes an anchor becomes a `link` inside a `list`, which axe fails and a
|
|
12
|
+
screen reader reads as a broken list. A row that is a link belongs outside
|
|
13
|
+
the group, which is how upstream's own example shows it. %>
|
|
14
|
+
<div class="flex w-full max-w-md flex-col gap-4">
|
|
15
|
+
<%= render(Shadcn::Item::Component.new(as: :a, href: "#", variant: :outline)) do %>
|
|
16
|
+
<%= render(Shadcn::Item::Media::Component.new) do %>
|
|
17
|
+
<%= render(Shadcn::Avatar::Component.new) do |a| %>
|
|
18
|
+
<% a.with_fallback { "EW" } %>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|
|
21
|
+
<%= render(Shadcn::Item::Content::Component.new) do %>
|
|
22
|
+
<%= render(Shadcn::Item::Title::Component.new) { "Evelyn Wood" } %>
|
|
23
|
+
<%= render(Shadcn::Item::Description::Component.new) { "The whole row is the link." } %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<%= render(Shadcn::Item::Actions::Component.new) do %>
|
|
26
|
+
<%= render(Shadcn::Icon::Component.new("chevron-right")) %>
|
|
27
|
+
<% end %>
|
|
28
|
+
<% end %>
|
|
29
|
+
|
|
30
|
+
<%= render(Shadcn::Item::Component.new(variant: :outline)) do %>
|
|
31
|
+
<%= render(Shadcn::Item::Media::Component.new(variant: :image)) do %>
|
|
32
|
+
<div class="flex size-full items-center justify-center bg-muted text-xs text-foreground/70">IMG</div>
|
|
33
|
+
<% end %>
|
|
34
|
+
<%= render(Shadcn::Item::Content::Component.new) do %>
|
|
35
|
+
<%= render(Shadcn::Item::Title::Component.new) { "A picture, cropped to the box" } %>
|
|
36
|
+
<%= render(Shadcn::Item::Description::Component.new) { "The image media is size-10, rounded and object-cover." } %>
|
|
37
|
+
<% end %>
|
|
38
|
+
<% end %>
|
|
39
|
+
</div>
|