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,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
module Dialog
|
|
6
|
+
# The palette: a Command inside a Dialog, which is what upstream's
|
|
7
|
+
# `CommandDialog` is — it renders no markup of its own beyond the classes
|
|
8
|
+
# it layers on both.
|
|
9
|
+
#
|
|
10
|
+
# The title and the description are `sr-only` and required rather than
|
|
11
|
+
# optional, exactly as upstream defaults them: a dialog with no
|
|
12
|
+
# accessible name is a dialog a screen reader opens into silence.
|
|
13
|
+
class Component < ApplicationViewComponent
|
|
14
|
+
# Upstream's own spacing for a palette in a dialog, which is where the
|
|
15
|
+
# `cmdk-*` attributes earn their keep: the rows are taller and the
|
|
16
|
+
# headings are indented, and every selector reaches this port's DOM.
|
|
17
|
+
COMMAND_CLASSES = "**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 " \
|
|
18
|
+
"[&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground " \
|
|
19
|
+
"[&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 " \
|
|
20
|
+
"[&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 " \
|
|
21
|
+
"[&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 " \
|
|
22
|
+
"[&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
|
|
23
|
+
CONTENT_CLASSES = "overflow-hidden p-0"
|
|
24
|
+
|
|
25
|
+
attr_reader :title, :description, :show_close_button, :label
|
|
26
|
+
|
|
27
|
+
def initialize(title: "Command Palette", description: "Search for a command to run...",
|
|
28
|
+
show_close_button: true, label: nil, **attributes)
|
|
29
|
+
@title = title
|
|
30
|
+
@description = description
|
|
31
|
+
@show_close_button = show_close_button
|
|
32
|
+
@label = label
|
|
33
|
+
super(**attributes)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The trigger belongs to the Dialog, not to this component, so the slot
|
|
37
|
+
# only *carries* what the caller wrote — its content, and the attributes
|
|
38
|
+
# that come with it — and `call` hands both to the Dialog's own trigger.
|
|
39
|
+
# Nesting one trigger inside another renders an empty button, which is
|
|
40
|
+
# what axe reported the first time.
|
|
41
|
+
# `view_context.capture`, and the block kept rather than rendered here:
|
|
42
|
+
# the block was written in the caller's template, so capturing it inside
|
|
43
|
+
# this component writes to the wrong buffer and the button comes out
|
|
44
|
+
# empty — which is what axe reported, twice.
|
|
45
|
+
renders_one :trigger, lambda { |**options, &block|
|
|
46
|
+
@trigger_options = options
|
|
47
|
+
@trigger_block = block
|
|
48
|
+
nil
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
def call
|
|
52
|
+
render(Shadcn::Dialog::Component.new(**attributes)) do |dialog|
|
|
53
|
+
dialog.with_trigger(**@trigger_options.to_h) { view_context.capture(&@trigger_block) } if trigger?
|
|
54
|
+
dialog.with_dialog_content(class: CONTENT_CLASSES, show_close_button:) do |dialog_content|
|
|
55
|
+
dialog_content.with_header(class: "sr-only") do |header|
|
|
56
|
+
header.with_title { title }
|
|
57
|
+
header.with_description { description }
|
|
58
|
+
end
|
|
59
|
+
concat(command)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def command
|
|
67
|
+
render(Command::Component.new(label:, class: COMMAND_CLASSES)) { content }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
module Empty
|
|
6
|
+
# What is shown when nothing matches. Rendered hidden and revealed by the
|
|
7
|
+
# controller: the server cannot know what a caller will type, and an empty
|
|
8
|
+
# state that only exists once JavaScript has run is one a reader sees
|
|
9
|
+
# flash in.
|
|
10
|
+
class Component < ApplicationViewComponent
|
|
11
|
+
default_tag :div
|
|
12
|
+
slot_name :"command-empty"
|
|
13
|
+
|
|
14
|
+
style do
|
|
15
|
+
base { "py-6 text-center text-sm" }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def element_attributes(**defaults)
|
|
19
|
+
super(**{
|
|
20
|
+
"cmdk-empty" => "",
|
|
21
|
+
role: "presentation",
|
|
22
|
+
hidden: true,
|
|
23
|
+
"data-shadcn--command-target" => "empty"
|
|
24
|
+
}.merge(defaults))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
module Group
|
|
6
|
+
# A titled run of items. cmdk renders three elements — the group, an
|
|
7
|
+
# `aria-hidden` heading and a `role="group"` wrapper named by it
|
|
8
|
+
# (`vendor/cmdk/index.tsx:750-764`) — and shadcn's classes select the
|
|
9
|
+
# middle one by `[cmdk-group-heading]`, so all three are reproduced.
|
|
10
|
+
#
|
|
11
|
+
# The whole group hides when every item in it is filtered away, which is
|
|
12
|
+
# the controller's job and the reason `hidden` is not a caller's argument.
|
|
13
|
+
class Component < ApplicationViewComponent
|
|
14
|
+
default_tag :div
|
|
15
|
+
slot_name :"command-group"
|
|
16
|
+
|
|
17
|
+
style do
|
|
18
|
+
base {
|
|
19
|
+
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 " \
|
|
20
|
+
"[&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs " \
|
|
21
|
+
"[&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground"
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
attr_reader :heading
|
|
26
|
+
|
|
27
|
+
def initialize(heading: nil, **attributes)
|
|
28
|
+
@heading = heading
|
|
29
|
+
super(**attributes)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def element_attributes(**defaults)
|
|
33
|
+
super(**{
|
|
34
|
+
"cmdk-group" => "",
|
|
35
|
+
role: "presentation",
|
|
36
|
+
"data-shadcn--command-target" => "group"
|
|
37
|
+
}.merge(defaults))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call
|
|
41
|
+
render_element(body: safe_join([ title, items ].compact))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def heading_id
|
|
47
|
+
@heading_id ||= "shadcn-command-heading-#{SecureRandom.hex(4)}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def title
|
|
51
|
+
return unless heading.present?
|
|
52
|
+
|
|
53
|
+
tag.div(heading, id: heading_id, "cmdk-group-heading": "", "aria-hidden": "true")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def items
|
|
57
|
+
tag.div(content, "cmdk-group-items": "", role: "group",
|
|
58
|
+
"aria-labelledby": (heading_id if heading.present?))
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
module Input
|
|
6
|
+
# The search field, wrapped in the row that holds the magnifier —
|
|
7
|
+
# upstream renders both from one component and gives each its own slot.
|
|
8
|
+
class Component < ApplicationViewComponent
|
|
9
|
+
WRAPPER_CLASSES = "flex h-9 items-center gap-2 border-b px-3"
|
|
10
|
+
ICON_CLASSES = "size-4 shrink-0 opacity-50"
|
|
11
|
+
|
|
12
|
+
default_tag :input
|
|
13
|
+
slot_name :"command-input"
|
|
14
|
+
|
|
15
|
+
style do
|
|
16
|
+
base {
|
|
17
|
+
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden " \
|
|
18
|
+
"placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
attr_reader :ids
|
|
23
|
+
|
|
24
|
+
def initialize(ids: {}, **attributes)
|
|
25
|
+
@ids = ids
|
|
26
|
+
super(**attributes)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# cmdk's own attributes, read from `vendor/cmdk/index.tsx:801-816`. The
|
|
30
|
+
# combobox is always expanded because the list is always there — a
|
|
31
|
+
# palette has nothing to open.
|
|
32
|
+
def element_attributes(**defaults)
|
|
33
|
+
super(**{
|
|
34
|
+
"cmdk-input" => "",
|
|
35
|
+
type: "text",
|
|
36
|
+
id: ids[:input],
|
|
37
|
+
role: "combobox",
|
|
38
|
+
autocomplete: "off",
|
|
39
|
+
autocorrect: "off",
|
|
40
|
+
spellcheck: "false",
|
|
41
|
+
"aria-autocomplete" => "list",
|
|
42
|
+
"aria-expanded" => "true",
|
|
43
|
+
"aria-controls" => ids[:list],
|
|
44
|
+
"aria-labelledby" => ids[:label],
|
|
45
|
+
"data-shadcn--command-target" => "search",
|
|
46
|
+
"data-action" => "input->shadcn--command#search keydown->shadcn--command#keydown"
|
|
47
|
+
}.compact.merge(defaults))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The wrapper is the component's own markup rather than a part a caller
|
|
51
|
+
# composes, which is upstream's shape too.
|
|
52
|
+
def call
|
|
53
|
+
tag.div(
|
|
54
|
+
safe_join([
|
|
55
|
+
render(Icon::Component.new("search", class: ICON_CLASSES)),
|
|
56
|
+
render_element
|
|
57
|
+
]),
|
|
58
|
+
class: WRAPPER_CLASSES,
|
|
59
|
+
"data-slot": "command-input-wrapper",
|
|
60
|
+
"cmdk-input-wrapper": ""
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
module Item
|
|
6
|
+
# One option. `role="option"`, `aria-selected` for the virtual focus, and
|
|
7
|
+
# `data-selected` for the classes — cmdk sets both, and shadcn's own
|
|
8
|
+
# `data-[selected=true]:bg-accent` reads the second.
|
|
9
|
+
class Component < ApplicationViewComponent
|
|
10
|
+
default_tag :div
|
|
11
|
+
slot_name :"command-item"
|
|
12
|
+
|
|
13
|
+
style do
|
|
14
|
+
base {
|
|
15
|
+
"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm " \
|
|
16
|
+
"outline-hidden select-none data-[disabled=true]:pointer-events-none " \
|
|
17
|
+
"data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent " \
|
|
18
|
+
"data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 " \
|
|
19
|
+
"[&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground"
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :value, :keywords, :disabled, :selected
|
|
24
|
+
|
|
25
|
+
# `value:` is what is searched where it is given, and the item's own text
|
|
26
|
+
# otherwise — cmdk's rule. `keywords:` are searched too and never shown,
|
|
27
|
+
# which is how "Preferences" is found by typing "settings".
|
|
28
|
+
def initialize(value: nil, keywords: nil, disabled: false, selected: false, **attributes)
|
|
29
|
+
@value = value
|
|
30
|
+
@keywords = Array(keywords)
|
|
31
|
+
@disabled = disabled
|
|
32
|
+
@selected = selected
|
|
33
|
+
super(**attributes)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def element_attributes(**defaults)
|
|
37
|
+
super(**{
|
|
38
|
+
"cmdk-item" => "",
|
|
39
|
+
id: item_id,
|
|
40
|
+
role: "option",
|
|
41
|
+
"aria-disabled" => (disabled.presence && "true"),
|
|
42
|
+
"aria-selected" => selected.to_s,
|
|
43
|
+
"data-disabled" => disabled.to_s,
|
|
44
|
+
"data-selected" => selected.to_s,
|
|
45
|
+
"data-value" => value,
|
|
46
|
+
"data-keywords" => (keywords.join(" ").presence),
|
|
47
|
+
"data-shadcn--command-target" => "item",
|
|
48
|
+
"data-action" => "click->shadcn--command#choose pointermove->shadcn--command#hover"
|
|
49
|
+
}.compact.merge(defaults))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# An item needs a name of its own for `aria-activedescendant` to point
|
|
55
|
+
# at it, and a caller has no reason to invent one.
|
|
56
|
+
def item_id
|
|
57
|
+
attributes[:id] || "shadcn-command-item-#{SecureRandom.hex(4)}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
module List
|
|
6
|
+
# The scrolling list of options. `role="listbox"`, and the input drives it
|
|
7
|
+
# from outside through `aria-activedescendant` — the virtual focus this
|
|
8
|
+
# gem already uses for the searchable select.
|
|
9
|
+
class Component < ApplicationViewComponent
|
|
10
|
+
default_tag :div
|
|
11
|
+
slot_name :"command-list"
|
|
12
|
+
|
|
13
|
+
style do
|
|
14
|
+
base { "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto" }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :ids
|
|
18
|
+
|
|
19
|
+
def initialize(ids: {}, **attributes)
|
|
20
|
+
@ids = ids
|
|
21
|
+
super(**attributes)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def element_attributes(**defaults)
|
|
25
|
+
super(**{
|
|
26
|
+
"cmdk-list" => "",
|
|
27
|
+
id: ids[:list],
|
|
28
|
+
role: "listbox",
|
|
29
|
+
"aria-labelledby" => ids[:label],
|
|
30
|
+
"data-shadcn--command-target" => "list"
|
|
31
|
+
}.compact.merge(defaults))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
class Preview < ApplicationViewComponentPreview
|
|
6
|
+
# Upstream's own example: a palette in a box, with two groups and the
|
|
7
|
+
# shortcuts beside the rows.
|
|
8
|
+
def default
|
|
9
|
+
render_with_template
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Upstream's "Dialog": the same list inside a Dialog. The shortcut that
|
|
13
|
+
# opens it is the caller's — `data-action` on any element, or the Dialog's
|
|
14
|
+
# own trigger.
|
|
15
|
+
def dialog
|
|
16
|
+
render_with_template
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# What ranking buys, which filtering does not: type "gp" and Group Policy
|
|
20
|
+
# comes first, because a palette answers "what did you mean".
|
|
21
|
+
def ranking
|
|
22
|
+
render_with_template
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<%# Upstream's own example. The items are ordinary components in the block, in
|
|
2
|
+
order — the list is server-rendered and the controller only filters, ranks
|
|
3
|
+
and walks it. %>
|
|
4
|
+
<%= render(Shadcn::Command::Component.new(label: "Command palette", class: "rounded-lg border shadow-md md:min-w-[450px]")) do |command| %>
|
|
5
|
+
<% command.with_command_input(placeholder: "Type a command or search...") %>
|
|
6
|
+
<% command.with_command_list do %>
|
|
7
|
+
<%= render(Shadcn::Command::Empty::Component.new) { "No results found." } %>
|
|
8
|
+
<%= render(Shadcn::Command::Group::Component.new(heading: "Suggestions")) do %>
|
|
9
|
+
<%= render(Shadcn::Command::Item::Component.new) do %>
|
|
10
|
+
<%= render(Shadcn::Icon::Component.new("calendar")) %>
|
|
11
|
+
<span>Calendar</span>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%= render(Shadcn::Command::Item::Component.new) do %>
|
|
14
|
+
<%= render(Shadcn::Icon::Component.new("search")) %>
|
|
15
|
+
<span>Search Emoji</span>
|
|
16
|
+
<% end %>
|
|
17
|
+
<%= render(Shadcn::Command::Item::Component.new(disabled: true)) do %>
|
|
18
|
+
<%= render(Shadcn::Icon::Component.new("calculator")) %>
|
|
19
|
+
<span>Calculator</span>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% end %>
|
|
22
|
+
<%= render(Shadcn::Command::Separator::Component.new) %>
|
|
23
|
+
<%= render(Shadcn::Command::Group::Component.new(heading: "Settings")) do %>
|
|
24
|
+
<%= render(Shadcn::Command::Item::Component.new(keywords: %w[account me])) do %>
|
|
25
|
+
<%= render(Shadcn::Icon::Component.new("user")) %>
|
|
26
|
+
<span>Profile</span>
|
|
27
|
+
<%= render(Shadcn::Command::Shortcut::Component.new) { "⌘P" } %>
|
|
28
|
+
<% end %>
|
|
29
|
+
<%= render(Shadcn::Command::Item::Component.new(keywords: %w[invoice payment])) do %>
|
|
30
|
+
<%= render(Shadcn::Icon::Component.new("credit-card")) %>
|
|
31
|
+
<span>Billing</span>
|
|
32
|
+
<%= render(Shadcn::Command::Shortcut::Component.new) { "⌘B" } %>
|
|
33
|
+
<% end %>
|
|
34
|
+
<%= render(Shadcn::Command::Item::Component.new(keywords: %w[preferences])) do %>
|
|
35
|
+
<%= render(Shadcn::Icon::Component.new("settings")) %>
|
|
36
|
+
<span>Settings</span>
|
|
37
|
+
<%= render(Shadcn::Command::Shortcut::Component.new) { "⌘S" } %>
|
|
38
|
+
<% end %>
|
|
39
|
+
<% end %>
|
|
40
|
+
<% end %>
|
|
41
|
+
<% end %>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<%# Upstream's "Dialog": the same palette inside a Dialog, whose title and
|
|
2
|
+
description are `sr-only` and not optional — a dialog with no accessible
|
|
3
|
+
name opens into silence.
|
|
4
|
+
|
|
5
|
+
The shortcut that opens it is the caller's: any element with the Dialog's
|
|
6
|
+
own trigger action, or a `keydown@document` of your own. %>
|
|
7
|
+
<%= render(Shadcn::Command::Dialog::Component.new(label: "Command palette")) do |palette| %>
|
|
8
|
+
<% palette.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) do %>
|
|
9
|
+
Open the palette
|
|
10
|
+
<% end %>
|
|
11
|
+
<%= render(Shadcn::Command::Input::Component.new(placeholder: "Type a command or search...")) %>
|
|
12
|
+
<%= render(Shadcn::Command::List::Component.new) do %>
|
|
13
|
+
<%= render(Shadcn::Command::Empty::Component.new) { "No results found." } %>
|
|
14
|
+
<%= render(Shadcn::Command::Group::Component.new(heading: "Suggestions")) do %>
|
|
15
|
+
<% [ [ "calendar", "Calendar" ], [ "search", "Search Emoji" ], [ "calculator", "Calculator" ] ].each do |icon, label| %>
|
|
16
|
+
<%= render(Shadcn::Command::Item::Component.new) do %>
|
|
17
|
+
<%= render(Shadcn::Icon::Component.new(icon)) %>
|
|
18
|
+
<span><%= label %></span>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% end %>
|
|
22
|
+
<%= render(Shadcn::Command::Separator::Component.new) %>
|
|
23
|
+
<%= render(Shadcn::Command::Group::Component.new(heading: "Settings")) do %>
|
|
24
|
+
<% [ [ "user", "Profile", "⌘P" ], [ "credit-card", "Billing", "⌘B" ], [ "settings", "Settings", "⌘S" ] ].each do |icon, label, key| %>
|
|
25
|
+
<%= render(Shadcn::Command::Item::Component.new) do %>
|
|
26
|
+
<%= render(Shadcn::Icon::Component.new(icon)) %>
|
|
27
|
+
<span><%= label %></span>
|
|
28
|
+
<%= render(Shadcn::Command::Shortcut::Component.new) { key } %>
|
|
29
|
+
<% end %>
|
|
30
|
+
<% end %>
|
|
31
|
+
<% end %>
|
|
32
|
+
<% end %>
|
|
33
|
+
<% end %>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<%# What ranking buys, and filtering does not. Type `gp`: Group Policy comes
|
|
2
|
+
first, because `cmdk`'s scorer rewards a match at the start of a word — the
|
|
3
|
+
same file is ported at `app/javascript/shadcn/command_score.js`.
|
|
4
|
+
|
|
5
|
+
Then type `settings` and Preferences appears, which has the word nowhere in
|
|
6
|
+
it: `keywords:` are searched and never shown. %>
|
|
7
|
+
<%= render(Shadcn::Command::Component.new(label: "Search", class: "rounded-lg border shadow-md md:min-w-[450px]")) do |command| %>
|
|
8
|
+
<% command.with_command_input(placeholder: "Try gp, or settings…") %>
|
|
9
|
+
<% command.with_command_list do %>
|
|
10
|
+
<%= render(Shadcn::Command::Empty::Component.new) { "No results found." } %>
|
|
11
|
+
<% { "Groups" => nil, "Group Policy" => nil, "Grouping rules" => nil,
|
|
12
|
+
"Preferences" => %w[settings config], "General" => nil }.each do |label, keywords| %>
|
|
13
|
+
<%= render(Shadcn::Command::Item::Component.new(keywords:)) { label } %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Command
|
|
5
|
+
module Separator
|
|
6
|
+
# A rule between groups, and decorative: `aria-hidden` where cmdk writes
|
|
7
|
+
# `role="separator"` (`vendor/cmdk/index.tsx:780`).
|
|
8
|
+
#
|
|
9
|
+
# A `role="listbox"` may only contain options and groups, and upstream's
|
|
10
|
+
# own palette puts the separator inside the list — so cmdk's markup makes
|
|
11
|
+
# the listbox invalid, and axe fails it. Nothing is lost by hiding it: a
|
|
12
|
+
# separator with no name conveys nothing to a screen reader, and the
|
|
13
|
+
# groups either side of it are already named. This is the same call the
|
|
14
|
+
# toaster made about a `role` on an `<li>`.
|
|
15
|
+
class Component < ApplicationViewComponent
|
|
16
|
+
default_tag :div
|
|
17
|
+
slot_name :"command-separator"
|
|
18
|
+
|
|
19
|
+
style do
|
|
20
|
+
base { "-mx-1 h-px bg-border" }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def element_attributes(**defaults)
|
|
24
|
+
super(**{
|
|
25
|
+
"cmdk-separator" => "",
|
|
26
|
+
"aria-hidden" => "true",
|
|
27
|
+
"data-shadcn--command-target" => "separator"
|
|
28
|
+
}.merge(defaults))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# The parts of the Command family that are an element with a `data-slot` and
|
|
5
|
+
# fixed classes. Everything else — the root, the input, the list, the group,
|
|
6
|
+
# the item, the separator and the dialog — carries an attribute `part` cannot
|
|
7
|
+
# express, mostly `cmdk-*` and a role.
|
|
8
|
+
module Command
|
|
9
|
+
extend Parts
|
|
10
|
+
|
|
11
|
+
part :shortcut, slot: "command-shortcut", tag: :span,
|
|
12
|
+
classes: "ml-auto text-xs tracking-widest text-muted-foreground"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Concerns
|
|
5
|
+
# Shared behaviour of the three components shadcn builds on Radix's Dialog
|
|
6
|
+
# primitive: Dialog, Sheet and AlertDialog.
|
|
7
|
+
#
|
|
8
|
+
# It is a module rather than a superclass because ViewComponent refuses to
|
|
9
|
+
# let a subclass redeclare an inherited slot, and each of the three needs
|
|
10
|
+
# its own `trigger` / content slot types.
|
|
11
|
+
module ModalRoot
|
|
12
|
+
def self.included(base)
|
|
13
|
+
base.class_eval do
|
|
14
|
+
attr_reader :open, :modal
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Radix keeps alert dialogs open on an outside click; AlertDialog says so
|
|
19
|
+
# by overriding this.
|
|
20
|
+
def dismissable? = true
|
|
21
|
+
|
|
22
|
+
def initialize(open: false, modal: true, **attributes)
|
|
23
|
+
@open = open
|
|
24
|
+
@modal = modal
|
|
25
|
+
super(**attributes)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def element_attributes(**defaults)
|
|
29
|
+
super(**{
|
|
30
|
+
style: merged_style(ApplicationViewComponent::CONTENTS_STYLE),
|
|
31
|
+
"data-controller" => "shadcn--dialog",
|
|
32
|
+
"data-shadcn--dialog-open-value" => open,
|
|
33
|
+
"data-shadcn--dialog-modal-value" => modal,
|
|
34
|
+
"data-shadcn--dialog-dismissable-value" => dismissable?
|
|
35
|
+
}.merge(defaults))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def call
|
|
39
|
+
render_element(body: safe_join([ trigger, dialog_content, content ].compact))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Concerns
|
|
5
|
+
# The hidden input that carries a control's value into the form, for the
|
|
6
|
+
# three families whose value is a single scalar: Select, RadioGroup and
|
|
7
|
+
# ToggleGroup.
|
|
8
|
+
#
|
|
9
|
+
# That input is **ours** — Radix bubbles a native control instead, and
|
|
10
|
+
# nothing upstream describes it. Which is precisely why it needed an opening:
|
|
11
|
+
# a host cannot address something the library invented and keeps to itself.
|
|
12
|
+
#
|
|
13
|
+
# `input_attributes:` is that opening. It reaches the input and nothing else:
|
|
14
|
+
#
|
|
15
|
+
# Shadcn::Select::Component.new(
|
|
16
|
+
# name: "post[author_id]",
|
|
17
|
+
# input_attributes: { id: "author-id", form: "other-form" }
|
|
18
|
+
# )
|
|
19
|
+
#
|
|
20
|
+
# Found by installing the gem in an application that wires one select to
|
|
21
|
+
# another: choosing a client reloads that client's sites. The obvious way to
|
|
22
|
+
# do it is a Stimulus controller on the element whose `.value` is the
|
|
23
|
+
# selection and which fires `change` — the hidden input, and there was no way
|
|
24
|
+
# to name it. Attaching to the root works and is what that host settled on,
|
|
25
|
+
# but two things have no such workaround: `id`, which a `<label for>` or any
|
|
26
|
+
# external script needs, and `form`, which is how HTML lets a control submit
|
|
27
|
+
# with a form it does not sit inside.
|
|
28
|
+
#
|
|
29
|
+
# ## Why only the single-valued families
|
|
30
|
+
#
|
|
31
|
+
# Combobox in `multiple` mode, Slider with several thumbs and Calendar in
|
|
32
|
+
# `range` or `multiple` mode all render *several* hidden inputs. There is no
|
|
33
|
+
# single element there to be "the control's value", and copying a caller's
|
|
34
|
+
# attributes onto each is wrong in both of the ways that matter: `id` would
|
|
35
|
+
# be duplicated, which is invalid, and `data-controller` would connect the
|
|
36
|
+
# same controller once per input.
|
|
37
|
+
#
|
|
38
|
+
# Those families take their attributes on the root instead, which reaches
|
|
39
|
+
# them through `**attributes` and — since 0.2.1 — concatenates
|
|
40
|
+
# `data-controller` with the component's own rather than replacing it.
|
|
41
|
+
#
|
|
42
|
+
# ## Why the target is passed in rather than derived
|
|
43
|
+
#
|
|
44
|
+
# Each including component writes its own `data-shadcn--…-target` literally,
|
|
45
|
+
# even though the concern could work it out from the class name.
|
|
46
|
+
# `stimulus_contract_spec` finds targets by reading those literals out of the
|
|
47
|
+
# source; a derived one would be invisible to it, and the check that every
|
|
48
|
+
# target a component names exists in the JavaScript would quietly stop
|
|
49
|
+
# covering this input.
|
|
50
|
+
module SubmitsValue
|
|
51
|
+
def self.included(base)
|
|
52
|
+
base.class_eval do
|
|
53
|
+
attr_reader :input_attributes
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def initialize(input_attributes: {}, **attributes)
|
|
58
|
+
@input_attributes = input_attributes || {}
|
|
59
|
+
super(**attributes)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
# A caller cannot detach the input from the control it belongs to: `name`
|
|
65
|
+
# and `value` are asserted again after their attributes are merged in.
|
|
66
|
+
# Everything else is theirs, including the Stimulus target — unusual to
|
|
67
|
+
# replace, but it is their component to break.
|
|
68
|
+
#
|
|
69
|
+
# The re-assertion does not move those two keys. `Hash#merge` on a key that
|
|
70
|
+
# is already present updates the value and keeps its insertion position, so
|
|
71
|
+
# the attribute order the components emitted before this concern existed is
|
|
72
|
+
# unchanged — which is what keeps every rendered snapshot byte-identical.
|
|
73
|
+
def hidden_input_attributes(**defaults)
|
|
74
|
+
{ "type" => "hidden", "name" => name, "value" => value }
|
|
75
|
+
.merge(defaults.transform_keys(&:to_s))
|
|
76
|
+
.merge(input_attributes.transform_keys(&:to_s))
|
|
77
|
+
.merge("name" => name, "value" => value)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module ContextMenu
|
|
5
|
+
# Port of registry/new-york-v4/ui/context-menu.tsx.
|
|
6
|
+
#
|
|
7
|
+
# Driven by `shadcn--dropdown-menu`, not a controller of its own: the two
|
|
8
|
+
# families declare the same slots and the menu's whole behaviour once open
|
|
9
|
+
# — roving focus, typeahead, submenus, checkbox and radio items — is the
|
|
10
|
+
# dropdown's. What differs is the way in, which is one action and one value.
|
|
11
|
+
class Component < ApplicationViewComponent
|
|
12
|
+
renders_one :trigger, "Shadcn::ContextMenu::Trigger::Component"
|
|
13
|
+
renders_one :menu_content, "Shadcn::ContextMenu::Content::Component"
|
|
14
|
+
|
|
15
|
+
slot_name :"context-menu"
|
|
16
|
+
|
|
17
|
+
attr_reader :loop
|
|
18
|
+
|
|
19
|
+
# `loop:` is the dropdown's own addition, kept here because both share the
|
|
20
|
+
# controller — Radix has it as a prop and shadcn passes it in neither file.
|
|
21
|
+
def initialize(loop: false, **attributes)
|
|
22
|
+
@loop = loop
|
|
23
|
+
super(**attributes)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def element_attributes(**defaults)
|
|
27
|
+
super(**{
|
|
28
|
+
style: merged_style(CONTENTS_STYLE),
|
|
29
|
+
"data-controller" => "shadcn--dropdown-menu",
|
|
30
|
+
"data-shadcn--dropdown-menu-prefix-value" => "context-menu",
|
|
31
|
+
"data-shadcn--dropdown-menu-loop-value" => loop,
|
|
32
|
+
# A context menu opens where the pointer is, so it has no side to
|
|
33
|
+
# prefer and no gap to leave: the point *is* the corner.
|
|
34
|
+
"data-shadcn--dropdown-menu-side-value" => "bottom",
|
|
35
|
+
"data-shadcn--dropdown-menu-align-value" => "start",
|
|
36
|
+
"data-shadcn--dropdown-menu-side-offset-value" => 0
|
|
37
|
+
}.merge(defaults))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call
|
|
41
|
+
render_element(body: safe_join([ trigger, menu_content, content ].compact))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|