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,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Menubar
|
|
5
|
+
module SubTrigger
|
|
6
|
+
# Its own file for two differences from the dropdown's, both one token
|
|
7
|
+
# wide and both upstream's: `outline-none` where the dropdown writes
|
|
8
|
+
# `outline-hidden`, and a chevron sized `h-4 w-4` where the dropdown
|
|
9
|
+
# writes `size-4` (menubar.tsx:238). The same size, spelled differently —
|
|
10
|
+
# and `parity_spec` compares tokens, so the spelling is the port.
|
|
11
|
+
class Component < Shadcn::DropdownMenu::SubTrigger::Component
|
|
12
|
+
slot_name :"menubar-sub-trigger"
|
|
13
|
+
|
|
14
|
+
style do
|
|
15
|
+
base {
|
|
16
|
+
"flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm " \
|
|
17
|
+
"outline-none select-none focus:bg-accent focus:text-accent-foreground " \
|
|
18
|
+
"data-[inset]:pl-8 data-[state=open]:bg-accent " \
|
|
19
|
+
"data-[state=open]:text-accent-foreground"
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def chevron
|
|
26
|
+
render(Icon::Component.new("chevron-right", class: "ml-auto h-4 w-4"))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Menubar
|
|
5
|
+
module Trigger
|
|
6
|
+
# One name on the bar.
|
|
7
|
+
class Component < ApplicationViewComponent
|
|
8
|
+
default_tag :button
|
|
9
|
+
slot_name :"menubar-trigger"
|
|
10
|
+
|
|
11
|
+
style do
|
|
12
|
+
base {
|
|
13
|
+
"flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden " \
|
|
14
|
+
"select-none focus:bg-accent focus:text-accent-foreground " \
|
|
15
|
+
"data-[state=open]:bg-accent data-[state=open]:text-accent-foreground"
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def element_attributes(**defaults)
|
|
20
|
+
super(**{
|
|
21
|
+
type: "button",
|
|
22
|
+
role: "menuitem",
|
|
23
|
+
"aria-haspopup" => "menu",
|
|
24
|
+
"aria-expanded" => "false",
|
|
25
|
+
"data-state" => "closed",
|
|
26
|
+
"data-shadcn--dropdown-menu-target" => "trigger",
|
|
27
|
+
"data-shadcn--menubar-target" => "trigger",
|
|
28
|
+
# Two controllers listening to one element: the menu's, which opens
|
|
29
|
+
# and closes it, and the bar's, which decides what the arrows do and
|
|
30
|
+
# what a hover means while another menu is already open.
|
|
31
|
+
"data-action" => "click->shadcn--dropdown-menu#toggle " \
|
|
32
|
+
"keydown->shadcn--dropdown-menu#triggerKeydown " \
|
|
33
|
+
"keydown->shadcn--menubar#keydown " \
|
|
34
|
+
"pointerenter->shadcn--menubar#pointerEnter " \
|
|
35
|
+
"focus->shadcn--menubar#focused"
|
|
36
|
+
}.merge(defaults))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# The Menubar family — sixteen slots, and the third built on the dropdown's.
|
|
5
|
+
#
|
|
6
|
+
# Measured against `dropdown-menu.tsx`: eight carry byte-identical class
|
|
7
|
+
# strings once the prefix is normalised, and those are declared with `from:`.
|
|
8
|
+
# The rest differ for real and are written out: the items round to `rounded-xs`
|
|
9
|
+
# where the dropdown rounds to `rounded-sm`, the sub-trigger takes
|
|
10
|
+
# `outline-none` rather than `outline-hidden`, and anything reading a
|
|
11
|
+
# `--radix-*` property reads `--radix-menubar-*`.
|
|
12
|
+
module Menubar
|
|
13
|
+
extend Parts
|
|
14
|
+
|
|
15
|
+
part :label, slot: "menubar-label", from: DropdownMenu::Label::Component
|
|
16
|
+
|
|
17
|
+
part :separator, slot: "menubar-separator", from: DropdownMenu::Separator::Component
|
|
18
|
+
|
|
19
|
+
part :shortcut, slot: "menubar-shortcut", from: DropdownMenu::Shortcut::Component
|
|
20
|
+
|
|
21
|
+
part :group, slot: "menubar-group", from: DropdownMenu::Group::Component
|
|
22
|
+
|
|
23
|
+
part :radio_group, slot: "menubar-radio-group", from: DropdownMenu::RadioGroup::Component
|
|
24
|
+
|
|
25
|
+
part :item, slot: "menubar-item", from: DropdownMenu::Item::Component
|
|
26
|
+
|
|
27
|
+
# `rounded-xs`, where the dropdown's are `rounded-sm`. One token, and the
|
|
28
|
+
# only reason these are not `from:` like the rest.
|
|
29
|
+
part :checkbox_item, slot: "menubar-checkbox-item",
|
|
30
|
+
from: DropdownMenu::CheckboxItem::Component,
|
|
31
|
+
classes: "relative flex cursor-default items-center gap-2 rounded-xs " \
|
|
32
|
+
"py-1.5 pr-2 pl-8 text-sm outline-hidden select-none " \
|
|
33
|
+
"focus:bg-accent focus:text-accent-foreground " \
|
|
34
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50 " \
|
|
35
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 " \
|
|
36
|
+
"[&_svg:not([class*='size-'])]:size-4"
|
|
37
|
+
|
|
38
|
+
part :radio_item, slot: "menubar-radio-item",
|
|
39
|
+
from: DropdownMenu::RadioItem::Component,
|
|
40
|
+
classes: "relative flex cursor-default items-center gap-2 rounded-xs " \
|
|
41
|
+
"py-1.5 pr-2 pl-8 text-sm outline-hidden select-none " \
|
|
42
|
+
"focus:bg-accent focus:text-accent-foreground " \
|
|
43
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50 " \
|
|
44
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 " \
|
|
45
|
+
"[&_svg:not([class*='size-'])]:size-4"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Message
|
|
5
|
+
# Port of registry/new-york-v4/ui/message.tsx
|
|
6
|
+
#
|
|
7
|
+
# `align:` is not a cva variant upstream — the classes are one string and the
|
|
8
|
+
# side is chosen by `data-[align=end]:flex-row-reverse` reading the attribute
|
|
9
|
+
# this writes (message.tsx:23-26). Its own file all the same, because a
|
|
10
|
+
# computed attribute is exactly what `part` does not do.
|
|
11
|
+
class Component < ApplicationViewComponent
|
|
12
|
+
slot_name :message
|
|
13
|
+
|
|
14
|
+
style do
|
|
15
|
+
base {
|
|
16
|
+
"group/message relative flex w-full min-w-0 gap-2 text-sm " \
|
|
17
|
+
"data-[align=end]:flex-row-reverse"
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
attr_reader :align
|
|
22
|
+
|
|
23
|
+
def initialize(align: :start, **attributes)
|
|
24
|
+
@align = align&.to_sym || :start
|
|
25
|
+
super(**attributes)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def element_attributes(**defaults)
|
|
29
|
+
super(**{ "data-align" => align }.merge(defaults))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Message
|
|
5
|
+
class Preview < ApplicationViewComponentPreview
|
|
6
|
+
def default
|
|
7
|
+
render_with_template
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Upstream's "Actions" and "Attachment".
|
|
11
|
+
def actions
|
|
12
|
+
render_with_template
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<%# Upstream's "Actions" and "Attachment".
|
|
2
|
+
|
|
3
|
+
Both live in the content column rather than beside the bubble, which is
|
|
4
|
+
what makes them line up with it whichever way the message is aligned: the
|
|
5
|
+
footer holds the row of buttons, and an attachment sits above the bubble as
|
|
6
|
+
another block in the same column.
|
|
7
|
+
|
|
8
|
+
The buttons are `icon-xs` ghosts and each has a name of its own — an
|
|
9
|
+
icon-only control that says nothing is a control a screen reader cannot
|
|
10
|
+
offer, which is the thing upstream's own accessibility note on this page is
|
|
11
|
+
about. %>
|
|
12
|
+
<div class="flex w-[420px] flex-col gap-6">
|
|
13
|
+
<%= render(Shadcn::Message::Group::Component.new) do %>
|
|
14
|
+
<%= render(Shadcn::Message::Component.new(align: :end)) do %>
|
|
15
|
+
<%= render(Shadcn::Message::Content::Component.new) do %>
|
|
16
|
+
<%= render(Shadcn::Attachment::Component.new(size: :sm)) do %>
|
|
17
|
+
<%= render(Shadcn::Attachment::Media::Component.new) { "PDF" } %>
|
|
18
|
+
<%= render(Shadcn::Attachment::Content::Component.new) do %>
|
|
19
|
+
<%= render(Shadcn::Attachment::Title::Component.new) { "contract.pdf" } %>
|
|
20
|
+
<%= render(Shadcn::Attachment::Description::Component.new) { "184 KB" } %>
|
|
21
|
+
<% end %>
|
|
22
|
+
<% end %>
|
|
23
|
+
<%= render(Shadcn::Bubble::Component.new(align: :end)) do %>
|
|
24
|
+
<%= render(Shadcn::Bubble::Content::Component.new) { "Signed and sent back." } %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% end %>
|
|
28
|
+
|
|
29
|
+
<%= render(Shadcn::Message::Component.new) do %>
|
|
30
|
+
<%= render(Shadcn::Message::Avatar::Component.new) do %>
|
|
31
|
+
<%= render(Shadcn::Avatar::Component.new(class: "size-8")) do |avatar| %>
|
|
32
|
+
<% avatar.with_fallback { "SC" } %>
|
|
33
|
+
<% end %>
|
|
34
|
+
<% end %>
|
|
35
|
+
<%= render(Shadcn::Message::Content::Component.new) do %>
|
|
36
|
+
<%= render(Shadcn::Bubble::Component.new(variant: :muted)) do %>
|
|
37
|
+
<%= render(Shadcn::Bubble::Content::Component.new) { "Got it — filing it now." } %>
|
|
38
|
+
<% end %>
|
|
39
|
+
<%= render(Shadcn::Message::Footer::Component.new) do %>
|
|
40
|
+
<div class="flex items-center gap-1">
|
|
41
|
+
<% [[ "check", "Copy" ], [ "circle", "Retry" ], [ "x", "Dismiss" ]].each do |icon, label| %>
|
|
42
|
+
<%= render(Shadcn::Button::Component.new(variant: :ghost, size: :"icon-xs", "aria-label": label)) do %>
|
|
43
|
+
<%= render(Shadcn::Icon::Component.new(icon)) %>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
</div>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% end %>
|
|
49
|
+
<% end %>
|
|
50
|
+
<% end %>
|
|
51
|
+
</div>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<%# The composition upstream's own demo renders, read from it rather than
|
|
2
|
+
inferred from the TSX: a group of messages, each an avatar beside a
|
|
3
|
+
content column, and the *bubble* nested inside that column. The message
|
|
4
|
+
lays out the row; the bubble is what carries the surface.
|
|
5
|
+
|
|
6
|
+
`align: :end` is what turns a message around — `data-[align=end]` reverses
|
|
7
|
+
the row and pushes the bubble and the footer to the other side. %>
|
|
8
|
+
<div class="flex w-[420px] flex-col gap-6">
|
|
9
|
+
<%= render(Shadcn::Message::Group::Component.new) do %>
|
|
10
|
+
<%= render(Shadcn::Message::Component.new) do %>
|
|
11
|
+
<%= render(Shadcn::Message::Avatar::Component.new) do %>
|
|
12
|
+
<%= render(Shadcn::Avatar::Component.new(class: "size-8")) do |avatar| %>
|
|
13
|
+
<% avatar.with_fallback { "SC" } %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<%= render(Shadcn::Message::Content::Component.new) do %>
|
|
17
|
+
<%= render(Shadcn::Bubble::Component.new(variant: :muted)) do %>
|
|
18
|
+
<%= render(Shadcn::Bubble::Content::Component.new) do %>
|
|
19
|
+
I checked the registry and the component is published.
|
|
20
|
+
<% end %>
|
|
21
|
+
<% end %>
|
|
22
|
+
<% end %>
|
|
23
|
+
<% end %>
|
|
24
|
+
|
|
25
|
+
<%= render(Shadcn::Message::Component.new(align: :end)) do %>
|
|
26
|
+
<%= render(Shadcn::Message::Content::Component.new) do %>
|
|
27
|
+
<%= render(Shadcn::Message::Header::Component.new) { "You" } %>
|
|
28
|
+
<%= render(Shadcn::Bubble::Component.new(align: :end)) do %>
|
|
29
|
+
<%= render(Shadcn::Bubble::Content::Component.new) { "Thanks — I will pull it in." } %>
|
|
30
|
+
<% end %>
|
|
31
|
+
<%= render(Shadcn::Message::Footer::Component.new) { "9:41 AM" } %>
|
|
32
|
+
<% end %>
|
|
33
|
+
<% end %>
|
|
34
|
+
<% end %>
|
|
35
|
+
</div>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# The parts of the Message family that are just an element with a
|
|
5
|
+
# `data-slot` and a fixed set of classes. Anything with variants, slots or
|
|
6
|
+
# markup of its own keeps its own `component.rb`.
|
|
7
|
+
#
|
|
8
|
+
# Five of the six are exactly that: only `Message` itself computes an
|
|
9
|
+
# attribute, from `align:`.
|
|
10
|
+
module Message
|
|
11
|
+
extend Parts
|
|
12
|
+
|
|
13
|
+
part :group, slot: "message-group", classes: "flex min-w-0 flex-col gap-2"
|
|
14
|
+
|
|
15
|
+
part :avatar, slot: "message-avatar",
|
|
16
|
+
classes: "flex w-fit min-w-8 shrink-0 items-center justify-center self-end " \
|
|
17
|
+
"overflow-hidden rounded-full bg-muted " \
|
|
18
|
+
"group-has-data-[slot=message-footer]/message:-translate-y-8"
|
|
19
|
+
|
|
20
|
+
part :content, slot: "message-content",
|
|
21
|
+
classes: "flex w-full min-w-0 flex-col gap-2.5 wrap-break-word " \
|
|
22
|
+
"group-data-[align=end]/message:*:data-slot:self-end"
|
|
23
|
+
|
|
24
|
+
part :header, slot: "message-header",
|
|
25
|
+
classes: "flex max-w-full min-w-0 items-center px-3 text-xs font-medium " \
|
|
26
|
+
"text-muted-foreground " \
|
|
27
|
+
"group-has-data-[variant=ghost]/message:px-0"
|
|
28
|
+
|
|
29
|
+
part :footer, slot: "message-footer",
|
|
30
|
+
classes: "flex max-w-full min-w-0 items-center px-3 text-xs font-medium " \
|
|
31
|
+
"text-muted-foreground " \
|
|
32
|
+
"group-has-data-[variant=ghost]/message:px-0 " \
|
|
33
|
+
"group-data-[align=end]/message:justify-end"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module MessageScroller
|
|
5
|
+
module Button
|
|
6
|
+
# The floating "jump to the end" control, and its start-side twin.
|
|
7
|
+
#
|
|
8
|
+
# A Button with different defaults — `secondary`, `icon-sm` — plus the
|
|
9
|
+
# positioning and the transition, so it subclasses rather than being
|
|
10
|
+
# declared with `part … from:`, which restamps the slot and leaves the
|
|
11
|
+
# arguments alone.
|
|
12
|
+
#
|
|
13
|
+
# `data-active` is the controller's to write and decides everything
|
|
14
|
+
# visible: the button is not hidden when there is nowhere to scroll, it is
|
|
15
|
+
# scaled, faded and pushed off its edge, with a slower easing on the way
|
|
16
|
+
# out than on the way in. Rendered `false` so it starts out of sight
|
|
17
|
+
# without a frame of flicker before the controller connects.
|
|
18
|
+
class Component < Shadcn::Button::Component
|
|
19
|
+
slot_name :"message-scroller-button"
|
|
20
|
+
|
|
21
|
+
style do
|
|
22
|
+
base {
|
|
23
|
+
"absolute inset-s-1/2 -translate-x-1/2 border-border bg-background " \
|
|
24
|
+
"text-foreground transition-[translate,scale,opacity] duration-200 " \
|
|
25
|
+
"hover:bg-muted hover:text-foreground " \
|
|
26
|
+
"data-[active=false]:pointer-events-none data-[active=false]:scale-95 " \
|
|
27
|
+
"data-[active=false]:opacity-0 data-[active=false]:duration-400 " \
|
|
28
|
+
"data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] " \
|
|
29
|
+
"data-[active=true]:translate-y-0 data-[active=true]:scale-100 " \
|
|
30
|
+
"data-[active=true]:opacity-100 " \
|
|
31
|
+
"data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] " \
|
|
32
|
+
"data-[direction=end]:bottom-4 " \
|
|
33
|
+
"data-[direction=end]:data-[active=false]:translate-y-full " \
|
|
34
|
+
"data-[direction=start]:top-4 " \
|
|
35
|
+
"data-[direction=start]:data-[active=false]:-translate-y-full " \
|
|
36
|
+
"rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180"
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
attr_reader :direction
|
|
41
|
+
|
|
42
|
+
def initialize(direction: :end, variant: :secondary, size: :"icon-sm", **attributes)
|
|
43
|
+
@direction = direction&.to_sym || :end
|
|
44
|
+
super(variant:, size:, **attributes)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def element_attributes(**defaults)
|
|
48
|
+
super(**{
|
|
49
|
+
"data-direction" => direction,
|
|
50
|
+
"data-active" => "false",
|
|
51
|
+
# Out of the tab order while there is nowhere to scroll, as the
|
|
52
|
+
# primitive does (components.tsx:400). It is invisible and
|
|
53
|
+
# `pointer-events-none` in that state, so leaving it tabbable would
|
|
54
|
+
# give a keyboard a stop that a pointer does not have.
|
|
55
|
+
tabindex: -1,
|
|
56
|
+
"data-shadcn--message-scroller-target" => "button",
|
|
57
|
+
"data-action" => "shadcn--message-scroller#jump"
|
|
58
|
+
}.merge(defaults))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# The chevron and its name. Upstream renders one arrow and rotates it for
|
|
62
|
+
# the start direction (message-scroller.tsx:108-115), which is why there
|
|
63
|
+
# is one icon here and a `rotate-180` in the classes above.
|
|
64
|
+
def call
|
|
65
|
+
return render_element(body: content) if content.present?
|
|
66
|
+
|
|
67
|
+
render_element(
|
|
68
|
+
body: safe_join([
|
|
69
|
+
render(Shadcn::Icon::Component.new("chevron-down")),
|
|
70
|
+
tag.span(shadcn_t("message_scroller.#{direction == :end ? 'scroll_to_end' : 'scroll_to_start'}"),
|
|
71
|
+
class: "sr-only")
|
|
72
|
+
])
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module MessageScroller
|
|
5
|
+
# Port of registry/new-york-v4/ui/message-scroller.tsx, which is a thin
|
|
6
|
+
# wrapper over `@shadcn/react/message-scroller` — vendored at
|
|
7
|
+
# `vendor/shadcn-react/` so the Stimulus port has a source to answer to.
|
|
8
|
+
#
|
|
9
|
+
# Upstream's `MessageScrollerProvider` renders no DOM at all: it is pure
|
|
10
|
+
# context holding the five options below (components.tsx:89-107). There is
|
|
11
|
+
# nothing to reproduce, so the options are Stimulus values and the
|
|
12
|
+
# controller lives on this element — the same answer `useSidebar` got.
|
|
13
|
+
class Component < ApplicationViewComponent
|
|
14
|
+
slot_name :"message-scroller"
|
|
15
|
+
|
|
16
|
+
style do
|
|
17
|
+
base {
|
|
18
|
+
"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden"
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
attr_reader :auto_scroll, :default_scroll_position, :scroll_edge_threshold,
|
|
23
|
+
:scroll_margin, :scroll_previous_item_peek
|
|
24
|
+
|
|
25
|
+
# Defaults are upstream's own (components.tsx:89-96). `scrollEdgeThreshold`,
|
|
26
|
+
# `scrollMargin` and `scrollPreviousItemPeek` are undefined there and fall
|
|
27
|
+
# back inside the primitive; passing nil here leaves the value off the
|
|
28
|
+
# element so the controller's own default applies, rather than baking a
|
|
29
|
+
# number this file cannot check.
|
|
30
|
+
def initialize(auto_scroll: false, default_scroll_position: :end,
|
|
31
|
+
scroll_edge_threshold: nil, scroll_margin: nil,
|
|
32
|
+
scroll_previous_item_peek: nil, **attributes)
|
|
33
|
+
@auto_scroll = auto_scroll
|
|
34
|
+
@default_scroll_position = default_scroll_position
|
|
35
|
+
@scroll_edge_threshold = scroll_edge_threshold
|
|
36
|
+
@scroll_margin = scroll_margin
|
|
37
|
+
@scroll_previous_item_peek = scroll_previous_item_peek
|
|
38
|
+
super(**attributes)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def element_attributes(**defaults)
|
|
42
|
+
super(**values.merge(defaults))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def values
|
|
48
|
+
{
|
|
49
|
+
"data-controller" => "shadcn--message-scroller",
|
|
50
|
+
"data-shadcn--message-scroller-auto-scroll-value" => auto_scroll,
|
|
51
|
+
"data-shadcn--message-scroller-default-scroll-position-value" => default_scroll_position,
|
|
52
|
+
"data-shadcn--message-scroller-scroll-edge-threshold-value" => scroll_edge_threshold,
|
|
53
|
+
"data-shadcn--message-scroller-scroll-margin-value" => scroll_margin,
|
|
54
|
+
"data-shadcn--message-scroller-scroll-previous-item-peek-value" => scroll_previous_item_peek
|
|
55
|
+
}.compact
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module MessageScroller
|
|
5
|
+
module Content
|
|
6
|
+
# The column of messages, and the tail spacer under it.
|
|
7
|
+
#
|
|
8
|
+
# The spacer is not decoration and not a slot: it is a hidden sibling of
|
|
9
|
+
# the rows whose height the controller sets, so the last message can be
|
|
10
|
+
# scrolled to the *top* of the viewport rather than stopping at the bottom
|
|
11
|
+
# (components.tsx:301-307). It is also the reason `scroll_geometry.js`
|
|
12
|
+
# measures the rows instead of reading `scrollHeight`, which the spacer
|
|
13
|
+
# inflates.
|
|
14
|
+
#
|
|
15
|
+
# `role="log"` with `aria-relevant="additions"` is upstream's default and
|
|
16
|
+
# is what makes an arriving message announce itself. Both are defaults, so
|
|
17
|
+
# a caller who knows better can say so.
|
|
18
|
+
class Component < ApplicationViewComponent
|
|
19
|
+
slot_name :"message-scroller-content"
|
|
20
|
+
|
|
21
|
+
style do
|
|
22
|
+
base { "flex h-max min-h-full flex-col gap-8" }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def element_attributes(**defaults)
|
|
26
|
+
super(**{
|
|
27
|
+
role: "log",
|
|
28
|
+
"aria-relevant" => "additions",
|
|
29
|
+
"data-shadcn--message-scroller-target" => "content"
|
|
30
|
+
}.merge(defaults))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def call
|
|
34
|
+
render_element(body: safe_join([ content, spacer ]))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def spacer
|
|
40
|
+
tag.div(
|
|
41
|
+
"aria-hidden": true,
|
|
42
|
+
"data-message-scroller-spacer": "",
|
|
43
|
+
"data-shadcn--message-scroller-target": "spacer",
|
|
44
|
+
hidden: true
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module MessageScroller
|
|
5
|
+
module Item
|
|
6
|
+
# One row. Its two attributes are the markup's half of the contract with
|
|
7
|
+
# `scroll_geometry.js`, which reads `dataset.messageId` and
|
|
8
|
+
# `dataset.scrollAnchor` — so they are rendered whether or not a controller
|
|
9
|
+
# is present.
|
|
10
|
+
#
|
|
11
|
+
# `data-scroll-anchor` is written as the string `"false"` rather than
|
|
12
|
+
# omitted, exactly as upstream does (components.tsx:340). Nothing here
|
|
13
|
+
# depends on the difference, but a host's CSS might.
|
|
14
|
+
#
|
|
15
|
+
# `content-visibility: auto` lets the browser skip laying out rows that are
|
|
16
|
+
# off screen, and `contain-intrinsic-size` is the guess it uses for their
|
|
17
|
+
# height until it does. They arrive as arbitrary properties because
|
|
18
|
+
# Tailwind has no utility for either.
|
|
19
|
+
class Component < ApplicationViewComponent
|
|
20
|
+
slot_name :"message-scroller-item"
|
|
21
|
+
|
|
22
|
+
style do
|
|
23
|
+
base {
|
|
24
|
+
"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]"
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
attr_reader :message_id, :scroll_anchor
|
|
29
|
+
|
|
30
|
+
def initialize(message_id: nil, scroll_anchor: false, **attributes)
|
|
31
|
+
@message_id = message_id
|
|
32
|
+
@scroll_anchor = scroll_anchor
|
|
33
|
+
super(**attributes)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def element_attributes(**defaults)
|
|
37
|
+
super(**{
|
|
38
|
+
"data-message-id" => message_id,
|
|
39
|
+
"data-scroll-anchor" => scroll_anchor.to_s
|
|
40
|
+
}.compact.merge(defaults))
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<%# The markup only. The Stimulus controller does not exist yet, so nothing
|
|
2
|
+
here follows the live end, sizes the tail spacer or lights the buttons —
|
|
3
|
+
both stay at `data-active="false"`, which is how they render.
|
|
4
|
+
|
|
5
|
+
That is deliberate rather than unfinished: the rows carry `data-message-id`
|
|
6
|
+
and `data-scroll-anchor`, which is the markup's half of the contract
|
|
7
|
+
`shadcn/scroll_geometry.js` already reads, and building the controller
|
|
8
|
+
against real markup beats inventing target names for it. See
|
|
9
|
+
`.claude/docs/features/message-scroller.md`.
|
|
10
|
+
|
|
11
|
+
The height is the preview's, not the component's: the scroller is
|
|
12
|
+
`size-full`, so it takes whatever it is put in — and with no height at all
|
|
13
|
+
there is nothing to scroll and nothing to see. %>
|
|
14
|
+
<%# `bg-card`, and that is not decoration. The buttons are `bg-background` with
|
|
15
|
+
no border width — upstream's own string (message-scroller.tsx:102), and the
|
|
16
|
+
`new-york-v4` Button's `secondary` variant adds no border either — so on a
|
|
17
|
+
surface that is *also* `--background` they have no visible edge at all. They
|
|
18
|
+
are meant to float over a panel, which is what a chat log sits in.
|
|
19
|
+
|
|
20
|
+
Worth knowing before comparing this to ui.shadcn.com: that page now serves
|
|
21
|
+
the Base UI registry, whose Button is `rounded-2xl border`. Measured on the
|
|
22
|
+
live demo. Its buttons look different because it is a different Button, not
|
|
23
|
+
because this port dropped something. %>
|
|
24
|
+
<div class="h-[420px] w-[420px] rounded-xl border bg-card">
|
|
25
|
+
<%= render(Shadcn::MessageScroller::Component.new(auto_scroll: true)) do %>
|
|
26
|
+
<%= render(Shadcn::MessageScroller::Viewport::Component.new) do %>
|
|
27
|
+
<%= render(Shadcn::MessageScroller::Content::Component.new(class: "p-4")) do %>
|
|
28
|
+
<%# Enough of them to overflow the frame. A scroller whose content
|
|
29
|
+
fits has nothing to follow and nothing to publish: `scrollHeight`
|
|
30
|
+
equals `clientHeight`, `data-scrollable` never appears, and every
|
|
31
|
+
assertion about it passes for the wrong reason. %>
|
|
32
|
+
<% [
|
|
33
|
+
[ "Is the registry entry published?", :start ],
|
|
34
|
+
[ "It is — the component and the example both went out this morning.", :end ],
|
|
35
|
+
[ "Good. What changed in the last release?", :start ],
|
|
36
|
+
[ "The scroller keeps the viewport steady when older messages load above it.", :end ],
|
|
37
|
+
[ "That is the part everyone gets wrong.", :start ],
|
|
38
|
+
[ "It is also the part with the most tests upstream.", :end ],
|
|
39
|
+
[ "Does it still follow the end while a reply streams in?", :start ],
|
|
40
|
+
[ "It does, and it stops the moment you scroll up to read.", :end ],
|
|
41
|
+
[ "What brings it back?", :start ],
|
|
42
|
+
[ "The button at the bottom, or reaching the end yourself.", :end ],
|
|
43
|
+
[ "And the tail spacer?", :start ],
|
|
44
|
+
[ "It is what lets the last message reach the top instead of the bottom.", :end ]
|
|
45
|
+
].each_with_index do |(text, align), index| %>
|
|
46
|
+
<% id = "m#{index + 1}" %>
|
|
47
|
+
<%# No row here is anchored, deliberately. `scroll_anchor: true` marks
|
|
48
|
+
a turn the scroller takes to the *top* of the viewport, and it
|
|
49
|
+
acts on any anchor it has not handled yet — so a server-rendered
|
|
50
|
+
one is jumped to on load and then holds following off, which is
|
|
51
|
+
correct and makes a fixture that says nothing about anything else.
|
|
52
|
+
The behaviour is covered where it actually happens, on a turn that
|
|
53
|
+
arrives: see `spec/system/message_scroller_spec.rb`. %>
|
|
54
|
+
<%= render(Shadcn::MessageScroller::Item::Component.new(message_id: id)) do %>
|
|
55
|
+
<%= render(Shadcn::Message::Component.new(align:)) do %>
|
|
56
|
+
<%= render(Shadcn::Message::Content::Component.new) do %>
|
|
57
|
+
<%= render(Shadcn::Bubble::Component.new(
|
|
58
|
+
variant: align == :end ? :default : :muted, align:
|
|
59
|
+
)) do %>
|
|
60
|
+
<%= render(Shadcn::Bubble::Content::Component.new) { text } %>
|
|
61
|
+
<% end %>
|
|
62
|
+
<% end %>
|
|
63
|
+
<% end %>
|
|
64
|
+
<% end %>
|
|
65
|
+
<% end %>
|
|
66
|
+
<% end %>
|
|
67
|
+
<% end %>
|
|
68
|
+
|
|
69
|
+
<%= render(Shadcn::MessageScroller::Button::Component.new(direction: :start)) %>
|
|
70
|
+
<%= render(Shadcn::MessageScroller::Button::Component.new) %>
|
|
71
|
+
<% end %>
|
|
72
|
+
</div>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module MessageScroller
|
|
5
|
+
module Viewport
|
|
6
|
+
# The scroll container. Three of its classes are shadcn's own CSS rather
|
|
7
|
+
# than Tailwind's — `scroll-fade-b`, `scrollbar-thin`,
|
|
8
|
+
# `scrollbar-gutter-stable` — reproduced at the end of `shadcn.css`;
|
|
9
|
+
# without them these would be inert and `parity_spec`, which compares class
|
|
10
|
+
# text and not generated CSS, would not notice.
|
|
11
|
+
#
|
|
12
|
+
# `data-autoscrolling:scrollbar-none` is the one variant here that reads an
|
|
13
|
+
# attribute the controller writes: the scrollbar is hidden while a
|
|
14
|
+
# programmatic scroll is in flight, so a smooth jump does not flicker one
|
|
15
|
+
# in and out.
|
|
16
|
+
class Component < ApplicationViewComponent
|
|
17
|
+
slot_name :"message-scroller-viewport"
|
|
18
|
+
|
|
19
|
+
style do
|
|
20
|
+
base {
|
|
21
|
+
"size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin " \
|
|
22
|
+
"scrollbar-gutter-stable overflow-y-auto overscroll-contain " \
|
|
23
|
+
"contain-content data-autoscrolling:scrollbar-none"
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# `tabindex: 0` is the primitive's (components.tsx:209) and is not
|
|
28
|
+
# decoration: a scrollable region with no focusable content inside it
|
|
29
|
+
# cannot be scrolled from a keyboard at all unless it is focusable
|
|
30
|
+
# itself. axe fails the page without it, which is how the omission was
|
|
31
|
+
# found.
|
|
32
|
+
def element_attributes(**defaults)
|
|
33
|
+
super(**{
|
|
34
|
+
tabindex: 0,
|
|
35
|
+
"data-shadcn--message-scroller-target" => "viewport"
|
|
36
|
+
}.merge(defaults))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|