velvetkit 0.1.0.beta
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 +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +197 -0
- data/lib/generators/velvetkit/add/add_generator.rb +111 -0
- data/lib/generators/velvetkit/ai/ai_generator.rb +78 -0
- data/lib/generators/velvetkit/helpers.rb +64 -0
- data/lib/generators/velvetkit/install/install_generator.rb +108 -0
- data/lib/velvetkit/namespace.rb +57 -0
- data/lib/velvetkit/reference.rb +108 -0
- data/lib/velvetkit/registry.rb +162 -0
- data/lib/velvetkit/version.rb +5 -0
- data/lib/velvetkit.rb +28 -0
- data/registry/app/assets/tailwind/velvetkit.css +342 -0
- data/registry/app/components/ui/accordion/content.html.erb +5 -0
- data/registry/app/components/ui/accordion/content.rb +34 -0
- data/registry/app/components/ui/accordion/item.html.erb +1 -0
- data/registry/app/components/ui/accordion/item.rb +40 -0
- data/registry/app/components/ui/accordion/trigger.html.erb +1 -0
- data/registry/app/components/ui/accordion/trigger.rb +37 -0
- data/registry/app/components/ui/accordion.html.erb +7 -0
- data/registry/app/components/ui/accordion.rb +34 -0
- data/registry/app/components/ui/alert/description.html.erb +1 -0
- data/registry/app/components/ui/alert/description.rb +12 -0
- data/registry/app/components/ui/alert/title.html.erb +1 -0
- data/registry/app/components/ui/alert/title.rb +12 -0
- data/registry/app/components/ui/alert.html.erb +16 -0
- data/registry/app/components/ui/alert.rb +55 -0
- data/registry/app/components/ui/avatar/fallback.html.erb +1 -0
- data/registry/app/components/ui/avatar/fallback.rb +12 -0
- data/registry/app/components/ui/avatar/image.rb +20 -0
- data/registry/app/components/ui/avatar.html.erb +1 -0
- data/registry/app/components/ui/avatar.rb +56 -0
- data/registry/app/components/ui/avatar_group.html.erb +1 -0
- data/registry/app/components/ui/avatar_group.rb +35 -0
- data/registry/app/components/ui/badge.html.erb +1 -0
- data/registry/app/components/ui/badge.rb +38 -0
- data/registry/app/components/ui/banner.html.erb +10 -0
- data/registry/app/components/ui/banner.rb +47 -0
- data/registry/app/components/ui/base.rb +53 -0
- data/registry/app/components/ui/breadcrumb/auto_ellipsis.html.erb +23 -0
- data/registry/app/components/ui/breadcrumb/auto_ellipsis.rb +12 -0
- data/registry/app/components/ui/breadcrumb/ellipsis.html.erb +18 -0
- data/registry/app/components/ui/breadcrumb/ellipsis.rb +8 -0
- data/registry/app/components/ui/breadcrumb/item.html.erb +1 -0
- data/registry/app/components/ui/breadcrumb/item.rb +12 -0
- data/registry/app/components/ui/breadcrumb/item_slot.html.erb +10 -0
- data/registry/app/components/ui/breadcrumb/item_slot.rb +47 -0
- data/registry/app/components/ui/breadcrumb/list.html.erb +1 -0
- data/registry/app/components/ui/breadcrumb/list.rb +12 -0
- data/registry/app/components/ui/breadcrumb/separator.html.erb +1 -0
- data/registry/app/components/ui/breadcrumb/separator.rb +12 -0
- data/registry/app/components/ui/breadcrumb.html.erb +30 -0
- data/registry/app/components/ui/breadcrumb.rb +83 -0
- data/registry/app/components/ui/button.html.erb +1 -0
- data/registry/app/components/ui/button.rb +81 -0
- data/registry/app/components/ui/button_to.html.erb +1 -0
- data/registry/app/components/ui/button_to.rb +33 -0
- data/registry/app/components/ui/card/content.html.erb +1 -0
- data/registry/app/components/ui/card/content.rb +12 -0
- data/registry/app/components/ui/card/description.html.erb +1 -0
- data/registry/app/components/ui/card/description.rb +12 -0
- data/registry/app/components/ui/card/footer.html.erb +1 -0
- data/registry/app/components/ui/card/footer.rb +12 -0
- data/registry/app/components/ui/card/header.html.erb +1 -0
- data/registry/app/components/ui/card/header.rb +15 -0
- data/registry/app/components/ui/card/title.html.erb +1 -0
- data/registry/app/components/ui/card/title.rb +12 -0
- data/registry/app/components/ui/card.html.erb +1 -0
- data/registry/app/components/ui/card.rb +18 -0
- data/registry/app/components/ui/checkbox.html.erb +18 -0
- data/registry/app/components/ui/checkbox.rb +133 -0
- data/registry/app/components/ui/data_grid.html.erb +2 -0
- data/registry/app/components/ui/data_grid.rb +84 -0
- data/registry/app/components/ui/date_picker.html.erb +70 -0
- data/registry/app/components/ui/date_picker.rb +111 -0
- data/registry/app/components/ui/dialog/close.html.erb +7 -0
- data/registry/app/components/ui/dialog/close.rb +53 -0
- data/registry/app/components/ui/dialog/content.html.erb +26 -0
- data/registry/app/components/ui/dialog/content.rb +102 -0
- data/registry/app/components/ui/dialog/description.html.erb +1 -0
- data/registry/app/components/ui/dialog/description.rb +16 -0
- data/registry/app/components/ui/dialog/footer.html.erb +1 -0
- data/registry/app/components/ui/dialog/footer.rb +14 -0
- data/registry/app/components/ui/dialog/header.html.erb +1 -0
- data/registry/app/components/ui/dialog/header.rb +16 -0
- data/registry/app/components/ui/dialog/title.html.erb +1 -0
- data/registry/app/components/ui/dialog/title.rb +16 -0
- data/registry/app/components/ui/dialog/trigger.html.erb +5 -0
- data/registry/app/components/ui/dialog/trigger.rb +75 -0
- data/registry/app/components/ui/dialog.html.erb +3 -0
- data/registry/app/components/ui/dialog.rb +41 -0
- data/registry/app/components/ui/divider.html.erb +9 -0
- data/registry/app/components/ui/divider.rb +41 -0
- data/registry/app/components/ui/icon.html.erb +1 -0
- data/registry/app/components/ui/icon.rb +41 -0
- data/registry/app/components/ui/image.html.erb +1 -0
- data/registry/app/components/ui/image.rb +74 -0
- data/registry/app/components/ui/input.html.erb +9 -0
- data/registry/app/components/ui/input.rb +127 -0
- data/registry/app/components/ui/input_group/addon.html.erb +6 -0
- data/registry/app/components/ui/input_group/addon.rb +51 -0
- data/registry/app/components/ui/input_group/field.rb +26 -0
- data/registry/app/components/ui/input_group.html.erb +5 -0
- data/registry/app/components/ui/input_group.rb +55 -0
- data/registry/app/components/ui/label.html.erb +2 -0
- data/registry/app/components/ui/label.rb +48 -0
- data/registry/app/components/ui/link.html.erb +1 -0
- data/registry/app/components/ui/link.rb +64 -0
- data/registry/app/components/ui/menu/content.html.erb +5 -0
- data/registry/app/components/ui/menu/content.rb +106 -0
- data/registry/app/components/ui/menu/group.html.erb +1 -0
- data/registry/app/components/ui/menu/group.rb +19 -0
- data/registry/app/components/ui/menu/item.html.erb +1 -0
- data/registry/app/components/ui/menu/item.rb +68 -0
- data/registry/app/components/ui/menu/label.html.erb +1 -0
- data/registry/app/components/ui/menu/label.rb +33 -0
- data/registry/app/components/ui/menu/separator.html.erb +1 -0
- data/registry/app/components/ui/menu/separator.rb +20 -0
- data/registry/app/components/ui/menu/trigger.html.erb +1 -0
- data/registry/app/components/ui/menu/trigger.rb +29 -0
- data/registry/app/components/ui/menu.html.erb +3 -0
- data/registry/app/components/ui/menu.rb +23 -0
- data/registry/app/components/ui/native_select.html.erb +16 -0
- data/registry/app/components/ui/native_select.rb +109 -0
- data/registry/app/components/ui/pagination.html.erb +34 -0
- data/registry/app/components/ui/pagination.rb +62 -0
- data/registry/app/components/ui/password_input.html.erb +20 -0
- data/registry/app/components/ui/password_input.rb +94 -0
- data/registry/app/components/ui/popover/content.html.erb +12 -0
- data/registry/app/components/ui/popover/content.rb +83 -0
- data/registry/app/components/ui/popover/trigger.html.erb +1 -0
- data/registry/app/components/ui/popover/trigger.rb +29 -0
- data/registry/app/components/ui/popover.html.erb +3 -0
- data/registry/app/components/ui/popover.rb +24 -0
- data/registry/app/components/ui/radio_group/item.html.erb +18 -0
- data/registry/app/components/ui/radio_group/item.rb +97 -0
- data/registry/app/components/ui/radio_group.html.erb +1 -0
- data/registry/app/components/ui/radio_group.rb +35 -0
- data/registry/app/components/ui/select.html.erb +60 -0
- data/registry/app/components/ui/select.rb +181 -0
- data/registry/app/components/ui/sheet/close.rb +4 -0
- data/registry/app/components/ui/sheet/content.html.erb +24 -0
- data/registry/app/components/ui/sheet/content.rb +97 -0
- data/registry/app/components/ui/sheet/trigger.rb +4 -0
- data/registry/app/components/ui/sheet.html.erb +3 -0
- data/registry/app/components/ui/sheet.rb +37 -0
- data/registry/app/components/ui/sidebar/content.html.erb +1 -0
- data/registry/app/components/ui/sidebar/content.rb +18 -0
- data/registry/app/components/ui/sidebar/footer.html.erb +3 -0
- data/registry/app/components/ui/sidebar/footer.rb +16 -0
- data/registry/app/components/ui/sidebar/group.html.erb +1 -0
- data/registry/app/components/ui/sidebar/group.rb +19 -0
- data/registry/app/components/ui/sidebar/group_label.html.erb +1 -0
- data/registry/app/components/ui/sidebar/group_label.rb +18 -0
- data/registry/app/components/ui/sidebar/header.html.erb +1 -0
- data/registry/app/components/ui/sidebar/header.rb +16 -0
- data/registry/app/components/ui/sidebar/inset.html.erb +1 -0
- data/registry/app/components/ui/sidebar/inset.rb +17 -0
- data/registry/app/components/ui/sidebar/menu.html.erb +1 -0
- data/registry/app/components/ui/sidebar/menu.rb +18 -0
- data/registry/app/components/ui/sidebar/menu_button.html.erb +1 -0
- data/registry/app/components/ui/sidebar/menu_button.rb +30 -0
- data/registry/app/components/ui/sidebar/menu_item.html.erb +1 -0
- data/registry/app/components/ui/sidebar/menu_item.rb +23 -0
- data/registry/app/components/ui/sidebar/trigger.html.erb +1 -0
- data/registry/app/components/ui/sidebar/trigger.rb +24 -0
- data/registry/app/components/ui/sidebar/wrapper.html.erb +1 -0
- data/registry/app/components/ui/sidebar/wrapper.rb +40 -0
- data/registry/app/components/ui/sidebar.html.erb +11 -0
- data/registry/app/components/ui/sidebar.rb +29 -0
- data/registry/app/components/ui/spinner.html.erb +1 -0
- data/registry/app/components/ui/spinner.rb +20 -0
- data/registry/app/components/ui/switch.html.erb +12 -0
- data/registry/app/components/ui/switch.rb +109 -0
- data/registry/app/components/ui/table/cell.html.erb +1 -0
- data/registry/app/components/ui/table/cell.rb +16 -0
- data/registry/app/components/ui/table/column.html.erb +1 -0
- data/registry/app/components/ui/table/column.rb +18 -0
- data/registry/app/components/ui/table/head.html.erb +1 -0
- data/registry/app/components/ui/table/head.rb +13 -0
- data/registry/app/components/ui/table/row.html.erb +1 -0
- data/registry/app/components/ui/table/row.rb +26 -0
- data/registry/app/components/ui/table.html.erb +4 -0
- data/registry/app/components/ui/table.rb +45 -0
- data/registry/app/components/ui/tabs/content.html.erb +1 -0
- data/registry/app/components/ui/tabs/content.rb +43 -0
- data/registry/app/components/ui/tabs/list.html.erb +1 -0
- data/registry/app/components/ui/tabs/list.rb +28 -0
- data/registry/app/components/ui/tabs/trigger.html.erb +1 -0
- data/registry/app/components/ui/tabs/trigger.rb +91 -0
- data/registry/app/components/ui/tabs.html.erb +3 -0
- data/registry/app/components/ui/tabs.rb +27 -0
- data/registry/app/components/ui/text.html.erb +1 -0
- data/registry/app/components/ui/text.rb +48 -0
- data/registry/app/components/ui/theme_toggle.html.erb +9 -0
- data/registry/app/components/ui/theme_toggle.rb +63 -0
- data/registry/app/components/ui/tooltip/content.html.erb +1 -0
- data/registry/app/components/ui/tooltip/content.rb +65 -0
- data/registry/app/components/ui/tooltip/trigger.html.erb +1 -0
- data/registry/app/components/ui/tooltip/trigger.rb +33 -0
- data/registry/app/components/ui/tooltip.html.erb +3 -0
- data/registry/app/components/ui/tooltip.rb +24 -0
- data/registry/app/components/ui/typography/blockquote.html.erb +1 -0
- data/registry/app/components/ui/typography/blockquote.rb +15 -0
- data/registry/app/components/ui/typography/code.html.erb +1 -0
- data/registry/app/components/ui/typography/code.rb +25 -0
- data/registry/app/components/ui/typography/h1.rb +7 -0
- data/registry/app/components/ui/typography/h2.rb +7 -0
- data/registry/app/components/ui/typography/h3.rb +7 -0
- data/registry/app/components/ui/typography/h4.rb +7 -0
- data/registry/app/components/ui/typography/large.rb +7 -0
- data/registry/app/components/ui/typography/lead.rb +7 -0
- data/registry/app/components/ui/typography/muted.rb +7 -0
- data/registry/app/components/ui/typography/small.rb +7 -0
- data/registry/app/javascript/ag_grid.ts +26 -0
- data/registry/app/javascript/cally.ts +8 -0
- data/registry/app/javascript/controllers/ui/_internal/use_dismiss.ts +88 -0
- data/registry/app/javascript/controllers/ui/_internal/use_floating.ts +112 -0
- data/registry/app/javascript/controllers/ui/accordion_controller.ts +100 -0
- data/registry/app/javascript/controllers/ui/alert_controller.ts +7 -0
- data/registry/app/javascript/controllers/ui/banner_controller.ts +7 -0
- data/registry/app/javascript/controllers/ui/data_grid_controller.ts +198 -0
- data/registry/app/javascript/controllers/ui/date_picker_controller.ts +141 -0
- data/registry/app/javascript/controllers/ui/dialog_controller.ts +70 -0
- data/registry/app/javascript/controllers/ui/menu_controller.ts +201 -0
- data/registry/app/javascript/controllers/ui/password_visibility_controller.ts +43 -0
- data/registry/app/javascript/controllers/ui/popover_controller.ts +108 -0
- data/registry/app/javascript/controllers/ui/select_controller.ts +274 -0
- data/registry/app/javascript/controllers/ui/sidebar_controller.ts +64 -0
- data/registry/app/javascript/controllers/ui/tabs_controller.ts +74 -0
- data/registry/app/javascript/controllers/ui/theme_controller.ts +101 -0
- data/registry/app/javascript/controllers/ui/tooltip_controller.ts +102 -0
- data/registry/app/javascript/velvetkit_icons.ts +58 -0
- data/registry/app/views/layouts/_theme_script.html.erb +19 -0
- data/registry/components.yml +102 -0
- data/registry/config/locales/velvetkit.en.yml +56 -0
- data/registry/docs/agents.md +62 -0
- data/registry/test/components/previews/ui/accordion_preview/faq_style.html.erb +20 -0
- data/registry/test/components/previews/ui/accordion_preview/multiple.html.erb +27 -0
- data/registry/test/components/previews/ui/accordion_preview/single.html.erb +22 -0
- data/registry/test/components/previews/ui/accordion_preview.rb +31 -0
- data/registry/test/components/previews/ui/alert_preview/title_only.html.erb +12 -0
- data/registry/test/components/previews/ui/alert_preview/variants.html.erb +22 -0
- data/registry/test/components/previews/ui/alert_preview/with_icon.html.erb +12 -0
- data/registry/test/components/previews/ui/alert_preview/with_link.html.erb +18 -0
- data/registry/test/components/previews/ui/alert_preview.rb +34 -0
- data/registry/test/components/previews/ui/avatar_group_preview/default.html.erb +11 -0
- data/registry/test/components/previews/ui/avatar_group_preview/overflow.html.erb +23 -0
- data/registry/test/components/previews/ui/avatar_group_preview/small.html.erb +12 -0
- data/registry/test/components/previews/ui/avatar_group_preview.rb +23 -0
- data/registry/test/components/previews/ui/avatar_preview/colors.html.erb +8 -0
- data/registry/test/components/previews/ui/avatar_preview/shapes.html.erb +10 -0
- data/registry/test/components/previews/ui/avatar_preview/sizes.html.erb +8 -0
- data/registry/test/components/previews/ui/avatar_preview/with_image.html.erb +10 -0
- data/registry/test/components/previews/ui/avatar_preview.rb +24 -0
- data/registry/test/components/previews/ui/badge_preview/sizes.html.erb +5 -0
- data/registry/test/components/previews/ui/badge_preview/variants.html.erb +8 -0
- data/registry/test/components/previews/ui/badge_preview/with_icon.html.erb +14 -0
- data/registry/test/components/previews/ui/badge_preview.rb +20 -0
- data/registry/test/components/previews/ui/banner_preview/introduction.html.erb +9 -0
- data/registry/test/components/previews/ui/banner_preview/promotion.html.erb +9 -0
- data/registry/test/components/previews/ui/banner_preview/with_illustration.html.erb +12 -0
- data/registry/test/components/previews/ui/banner_preview.rb +25 -0
- data/registry/test/components/previews/ui/breadcrumb_preview/collapsed.html.erb +50 -0
- data/registry/test/components/previews/ui/breadcrumb_preview/default.html.erb +8 -0
- data/registry/test/components/previews/ui/breadcrumb_preview/long_path.html.erb +8 -0
- data/registry/test/components/previews/ui/breadcrumb_preview/medium.html.erb +7 -0
- data/registry/test/components/previews/ui/breadcrumb_preview/with_avatar.html.erb +8 -0
- data/registry/test/components/previews/ui/breadcrumb_preview.rb +66 -0
- data/registry/test/components/previews/ui/button_preview/disabled.html.erb +39 -0
- data/registry/test/components/previews/ui/button_preview/icon_only.html.erb +17 -0
- data/registry/test/components/previews/ui/button_preview/loading.html.erb +12 -0
- data/registry/test/components/previews/ui/button_preview/sizes.html.erb +6 -0
- data/registry/test/components/previews/ui/button_preview/variants.html.erb +8 -0
- data/registry/test/components/previews/ui/button_preview/with_both_icons.html.erb +12 -0
- data/registry/test/components/previews/ui/button_preview/with_leading_icon.html.erb +22 -0
- data/registry/test/components/previews/ui/button_preview/with_trailing_icon.html.erb +14 -0
- data/registry/test/components/previews/ui/button_preview.rb +65 -0
- data/registry/test/components/previews/ui/button_to_preview/states.html.erb +8 -0
- data/registry/test/components/previews/ui/button_to_preview/variants.html.erb +5 -0
- data/registry/test/components/previews/ui/button_to_preview/with_icon.html.erb +11 -0
- data/registry/test/components/previews/ui/button_to_preview.rb +21 -0
- data/registry/test/components/previews/ui/card_preview/complete.html.erb +31 -0
- data/registry/test/components/previews/ui/card_preview/default.html.erb +7 -0
- data/registry/test/components/previews/ui/card_preview/settings_form.html.erb +25 -0
- data/registry/test/components/previews/ui/card_preview/with_footer.html.erb +13 -0
- data/registry/test/components/previews/ui/card_preview/with_header.html.erb +11 -0
- data/registry/test/components/previews/ui/card_preview.rb +44 -0
- data/registry/test/components/previews/ui/checkbox_preview/in_form.html.erb +9 -0
- data/registry/test/components/previews/ui/checkbox_preview/states.html.erb +22 -0
- data/registry/test/components/previews/ui/checkbox_preview/with_label.html.erb +5 -0
- data/registry/test/components/previews/ui/checkbox_preview.rb +27 -0
- data/registry/test/components/previews/ui/data_grid_preview.rb +18 -0
- data/registry/test/components/previews/ui/date_picker_preview/default.html.erb +3 -0
- data/registry/test/components/previews/ui/date_picker_preview/states.html.erb +7 -0
- data/registry/test/components/previews/ui/date_picker_preview.rb +13 -0
- data/registry/test/components/previews/ui/dialog_preview/confirmation.html.erb +11 -0
- data/registry/test/components/previews/ui/dialog_preview/custom_trigger.html.erb +16 -0
- data/registry/test/components/previews/ui/dialog_preview/default.html.erb +15 -0
- data/registry/test/components/previews/ui/dialog_preview/long_content.html.erb +16 -0
- data/registry/test/components/previews/ui/dialog_preview/playground.html.erb +12 -0
- data/registry/test/components/previews/ui/dialog_preview/scrollable_body.html.erb +29 -0
- data/registry/test/components/previews/ui/dialog_preview/sizes.html.erb +46 -0
- data/registry/test/components/previews/ui/dialog_preview/without_close_button.html.erb +11 -0
- data/registry/test/components/previews/ui/dialog_preview/without_title.html.erb +13 -0
- data/registry/test/components/previews/ui/dialog_preview.rb +38 -0
- data/registry/test/components/previews/ui/divider_preview/horizontal.html.erb +5 -0
- data/registry/test/components/previews/ui/divider_preview/vertical.html.erb +9 -0
- data/registry/test/components/previews/ui/divider_preview/with_label.html.erb +5 -0
- data/registry/test/components/previews/ui/divider_preview.rb +19 -0
- data/registry/test/components/previews/ui/icon_preview/common.html.erb +8 -0
- data/registry/test/components/previews/ui/icon_preview/sizes.html.erb +7 -0
- data/registry/test/components/previews/ui/icon_preview.rb +20 -0
- data/registry/test/components/previews/ui/image_preview/radii.html.erb +8 -0
- data/registry/test/components/previews/ui/image_preview/sizing.html.erb +9 -0
- data/registry/test/components/previews/ui/image_preview.rb +16 -0
- data/registry/test/components/previews/ui/input_group_preview/addons.html.erb +29 -0
- data/registry/test/components/previews/ui/input_group_preview/playground.html.erb +12 -0
- data/registry/test/components/previews/ui/input_group_preview.rb +17 -0
- data/registry/test/components/previews/ui/input_preview/sizes.html.erb +5 -0
- data/registry/test/components/previews/ui/input_preview/states.html.erb +7 -0
- data/registry/test/components/previews/ui/input_preview/with_labels.html.erb +10 -0
- data/registry/test/components/previews/ui/input_preview.rb +33 -0
- data/registry/test/components/previews/ui/label_preview/sizes.html.erb +6 -0
- data/registry/test/components/previews/ui/label_preview/states.html.erb +6 -0
- data/registry/test/components/previews/ui/label_preview/weights.html.erb +5 -0
- data/registry/test/components/previews/ui/label_preview.rb +22 -0
- data/registry/test/components/previews/ui/link_preview/sizes.html.erb +5 -0
- data/registry/test/components/previews/ui/link_preview/variants.html.erb +8 -0
- data/registry/test/components/previews/ui/link_preview/with_icons.html.erb +11 -0
- data/registry/test/components/previews/ui/link_preview.rb +20 -0
- data/registry/test/components/previews/ui/menu_preview/positions.html.erb +122 -0
- data/registry/test/components/previews/ui/menu_preview/variants.html.erb +218 -0
- data/registry/test/components/previews/ui/menu_preview.rb +26 -0
- data/registry/test/components/previews/ui/native_select_preview/sizes.html.erb +6 -0
- data/registry/test/components/previews/ui/native_select_preview/states.html.erb +6 -0
- data/registry/test/components/previews/ui/native_select_preview.rb +23 -0
- data/registry/test/components/previews/ui/pagination_preview/states.html.erb +15 -0
- data/registry/test/components/previews/ui/pagination_preview.rb +15 -0
- data/registry/test/components/previews/ui/password_input_preview/states.html.erb +19 -0
- data/registry/test/components/previews/ui/password_input_preview.rb +21 -0
- data/registry/test/components/previews/ui/popover_preview/default.html.erb +7 -0
- data/registry/test/components/previews/ui/popover_preview/positions.html.erb +30 -0
- data/registry/test/components/previews/ui/popover_preview/with_close_button.html.erb +8 -0
- data/registry/test/components/previews/ui/popover_preview/with_rich_content.html.erb +17 -0
- data/registry/test/components/previews/ui/popover_preview/without_title.html.erb +9 -0
- data/registry/test/components/previews/ui/popover_preview.rb +32 -0
- data/registry/test/components/previews/ui/radio_group_preview/default.html.erb +10 -0
- data/registry/test/components/previews/ui/radio_group_preview/disabled.html.erb +17 -0
- data/registry/test/components/previews/ui/radio_group_preview/with_required.html.erb +10 -0
- data/registry/test/components/previews/ui/radio_group_preview.rb +25 -0
- data/registry/test/components/previews/ui/select_preview/default.html.erb +4 -0
- data/registry/test/components/previews/ui/select_preview/long_list.html.erb +5 -0
- data/registry/test/components/previews/ui/select_preview/multiple.html.erb +6 -0
- data/registry/test/components/previews/ui/select_preview/sizes.html.erb +5 -0
- data/registry/test/components/previews/ui/select_preview/states.html.erb +6 -0
- data/registry/test/components/previews/ui/select_preview.rb +45 -0
- data/registry/test/components/previews/ui/sheet_preview/bottom.html.erb +12 -0
- data/registry/test/components/previews/ui/sheet_preview/left.html.erb +10 -0
- data/registry/test/components/previews/ui/sheet_preview/playground.html.erb +15 -0
- data/registry/test/components/previews/ui/sheet_preview/right.html.erb +11 -0
- data/registry/test/components/previews/ui/sheet_preview/top.html.erb +8 -0
- data/registry/test/components/previews/ui/sheet_preview.rb +22 -0
- data/registry/test/components/previews/ui/sidebar_preview/_brand.html.erb +14 -0
- data/registry/test/components/previews/ui/sidebar_preview/_shell.html.erb +60 -0
- data/registry/test/components/previews/ui/sidebar_preview/collapsible.html.erb +55 -0
- data/registry/test/components/previews/ui/sidebar_preview/default.html.erb +17 -0
- data/registry/test/components/previews/ui/sidebar_preview/with_dropdown_header.html.erb +33 -0
- data/registry/test/components/previews/ui/sidebar_preview/with_groups.html.erb +22 -0
- data/registry/test/components/previews/ui/sidebar_preview.rb +15 -0
- data/registry/test/components/previews/ui/spinner_preview/in_buttons.html.erb +7 -0
- data/registry/test/components/previews/ui/spinner_preview/sizes.html.erb +7 -0
- data/registry/test/components/previews/ui/spinner_preview.rb +19 -0
- data/registry/test/components/previews/ui/switch_preview/default.html.erb +4 -0
- data/registry/test/components/previews/ui/switch_preview/sizes.html.erb +5 -0
- data/registry/test/components/previews/ui/switch_preview/states.html.erb +7 -0
- data/registry/test/components/previews/ui/switch_preview.rb +26 -0
- data/registry/test/components/previews/ui/table_preview/customers.html.erb +15 -0
- data/registry/test/components/previews/ui/table_preview/empty.html.erb +8 -0
- data/registry/test/components/previews/ui/table_preview/with_caption.html.erb +14 -0
- data/registry/test/components/previews/ui/table_preview.rb +12 -0
- data/registry/test/components/previews/ui/tabs_preview/default.html.erb +39 -0
- data/registry/test/components/previews/ui/tabs_preview/pill_variant.html.erb +18 -0
- data/registry/test/components/previews/ui/tabs_preview/settings_form.html.erb +42 -0
- data/registry/test/components/previews/ui/tabs_preview/with_icons.html.erb +34 -0
- data/registry/test/components/previews/ui/tabs_preview.rb +33 -0
- data/registry/test/components/previews/ui/text_preview/sizes.html.erb +10 -0
- data/registry/test/components/previews/ui/text_preview/tones.html.erb +5 -0
- data/registry/test/components/previews/ui/text_preview/weights.html.erb +6 -0
- data/registry/test/components/previews/ui/text_preview.rb +26 -0
- data/registry/test/components/previews/ui/theme_toggle_preview/in_a_header.html.erb +14 -0
- data/registry/test/components/previews/ui/theme_toggle_preview/palette.html.erb +47 -0
- data/registry/test/components/previews/ui/theme_toggle_preview.rb +15 -0
- data/registry/test/components/previews/ui/tooltip_preview/default.html.erb +8 -0
- data/registry/test/components/previews/ui/tooltip_preview/positions.html.erb +34 -0
- data/registry/test/components/previews/ui/tooltip_preview/with_button.html.erb +8 -0
- data/registry/test/components/previews/ui/tooltip_preview/with_icon.html.erb +10 -0
- data/registry/test/components/previews/ui/tooltip_preview.rb +29 -0
- data/registry/test/components/previews/ui/typography_preview/article.html.erb +11 -0
- data/registry/test/components/previews/ui/typography_preview/code_and_quotes.html.erb +6 -0
- data/registry/test/components/previews/ui/typography_preview/headings.html.erb +6 -0
- data/registry/test/components/previews/ui/typography_preview/text_styles.html.erb +7 -0
- data/registry/test/components/previews/ui/typography_preview.rb +23 -0
- data/registry/test/components/ui/accordion/content_test.rb +64 -0
- data/registry/test/components/ui/accordion/item_test.rb +61 -0
- data/registry/test/components/ui/accordion/trigger_test.rb +80 -0
- data/registry/test/components/ui/accordion_test.rb +96 -0
- data/registry/test/components/ui/alert/description_test.rb +37 -0
- data/registry/test/components/ui/alert/title_test.rb +38 -0
- data/registry/test/components/ui/alert_test.rb +184 -0
- data/registry/test/components/ui/avatar_group_test.rb +79 -0
- data/registry/test/components/ui/avatar_test.rb +129 -0
- data/registry/test/components/ui/badge_test.rb +112 -0
- data/registry/test/components/ui/banner_test.rb +116 -0
- data/registry/test/components/ui/base_test.rb +98 -0
- data/registry/test/components/ui/breadcrumb/ellipsis_test.rb +51 -0
- data/registry/test/components/ui/breadcrumb/item_test.rb +39 -0
- data/registry/test/components/ui/breadcrumb/list_test.rb +34 -0
- data/registry/test/components/ui/breadcrumb/separator_test.rb +36 -0
- data/registry/test/components/ui/breadcrumb_test.rb +276 -0
- data/registry/test/components/ui/button_test.rb +276 -0
- data/registry/test/components/ui/button_to_test.rb +74 -0
- data/registry/test/components/ui/card/content_test.rb +41 -0
- data/registry/test/components/ui/card/description_test.rb +32 -0
- data/registry/test/components/ui/card/footer_test.rb +34 -0
- data/registry/test/components/ui/card/header_test.rb +57 -0
- data/registry/test/components/ui/card/title_test.rb +34 -0
- data/registry/test/components/ui/card_test.rb +67 -0
- data/registry/test/components/ui/checkbox_test.rb +236 -0
- data/registry/test/components/ui/data_grid_test.rb +88 -0
- data/registry/test/components/ui/date_picker_test.rb +168 -0
- data/registry/test/components/ui/dialog/content_test.rb +156 -0
- data/registry/test/components/ui/dialog/trigger_test.rb +74 -0
- data/registry/test/components/ui/dialog_test.rb +54 -0
- data/registry/test/components/ui/divider_test.rb +69 -0
- data/registry/test/components/ui/icon_test.rb +82 -0
- data/registry/test/components/ui/image_test.rb +74 -0
- data/registry/test/components/ui/input_group_test.rb +143 -0
- data/registry/test/components/ui/input_test.rb +251 -0
- data/registry/test/components/ui/label_test.rb +96 -0
- data/registry/test/components/ui/link_test.rb +95 -0
- data/registry/test/components/ui/menu/content_test.rb +233 -0
- data/registry/test/components/ui/menu/group_test.rb +24 -0
- data/registry/test/components/ui/menu/item_test.rb +76 -0
- data/registry/test/components/ui/menu/label_test.rb +43 -0
- data/registry/test/components/ui/menu/separator_test.rb +32 -0
- data/registry/test/components/ui/menu/trigger_test.rb +109 -0
- data/registry/test/components/ui/menu_test.rb +152 -0
- data/registry/test/components/ui/native_select_test.rb +118 -0
- data/registry/test/components/ui/pagination_test.rb +92 -0
- data/registry/test/components/ui/password_input_test.rb +98 -0
- data/registry/test/components/ui/popover/content_test.rb +226 -0
- data/registry/test/components/ui/popover/trigger_test.rb +83 -0
- data/registry/test/components/ui/popover_test.rb +101 -0
- data/registry/test/components/ui/radio_group/item_test.rb +14 -0
- data/registry/test/components/ui/radio_group_test.rb +139 -0
- data/registry/test/components/ui/select_test.rb +181 -0
- data/registry/test/components/ui/sheet/content_test.rb +135 -0
- data/registry/test/components/ui/sheet/trigger_test.rb +23 -0
- data/registry/test/components/ui/sheet_test.rb +43 -0
- data/registry/test/components/ui/sidebar/menu_button_test.rb +43 -0
- data/registry/test/components/ui/sidebar/trigger_test.rb +17 -0
- data/registry/test/components/ui/sidebar/wrapper_test.rb +15 -0
- data/registry/test/components/ui/sidebar_test.rb +43 -0
- data/registry/test/components/ui/spinner_test.rb +63 -0
- data/registry/test/components/ui/switch_test.rb +206 -0
- data/registry/test/components/ui/table_test.rb +106 -0
- data/registry/test/components/ui/tabs/content_test.rb +93 -0
- data/registry/test/components/ui/tabs/list_test.rb +65 -0
- data/registry/test/components/ui/tabs/trigger_test.rb +159 -0
- data/registry/test/components/ui/tabs_test.rb +88 -0
- data/registry/test/components/ui/text_test.rb +84 -0
- data/registry/test/components/ui/theme_toggle_test.rb +88 -0
- data/registry/test/components/ui/tooltip/content_test.rb +135 -0
- data/registry/test/components/ui/tooltip/trigger_test.rb +52 -0
- data/registry/test/components/ui/tooltip_test.rb +97 -0
- data/registry/test/components/ui/typography/code_blockquote_test.rb +57 -0
- data/registry/test/components/ui/typography/heading_test.rb +71 -0
- data/registry/test/components/ui/typography/text_variants_test.rb +71 -0
- metadata +540 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::ButtonTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_default_variant_and_size
|
|
10
|
+
render_inline(UI::Button.new) { "Save" }
|
|
11
|
+
btn = page.find("button")
|
|
12
|
+
assert_equal "button", btn[:type]
|
|
13
|
+
assert_includes btn[:class], "bg-primary"
|
|
14
|
+
assert_includes btn[:class], "text-primary-foreground"
|
|
15
|
+
assert_includes btn[:class], "h-9"
|
|
16
|
+
assert_equal "Save", btn.text.strip
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_renders_destructive_variant
|
|
20
|
+
render_inline(UI::Button.new(variant: :destructive)) { "Delete" }
|
|
21
|
+
btn = page.find("button")
|
|
22
|
+
classes = btn[:class].split
|
|
23
|
+
assert_includes classes, "bg-destructive"
|
|
24
|
+
refute_includes classes, "bg-primary"
|
|
25
|
+
# destructive variant overrides the default focus ring color
|
|
26
|
+
assert_includes classes, "focus:ring-destructive"
|
|
27
|
+
refute_includes classes, "focus:ring-primary"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_renders_outline_variant
|
|
31
|
+
render_inline(UI::Button.new(variant: :outline)) { "Cancel" }
|
|
32
|
+
btn = page.find("button")
|
|
33
|
+
assert_includes btn[:class], "border-input"
|
|
34
|
+
assert_includes btn[:class], "bg-background"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_renders_secondary_variant
|
|
38
|
+
render_inline(UI::Button.new(variant: :secondary)) { "Secondary" }
|
|
39
|
+
assert_selector "button.bg-secondary", text: "Secondary"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_renders_ghost_variant
|
|
43
|
+
render_inline(UI::Button.new(variant: :ghost)) { "Ghost" }
|
|
44
|
+
btn = page.find("button")
|
|
45
|
+
assert_includes btn[:class], "hover:bg-accent"
|
|
46
|
+
refute_includes btn[:class], "bg-primary"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_renders_link_variant
|
|
50
|
+
render_inline(UI::Button.new(variant: :link)) { "Link" }
|
|
51
|
+
btn = page.find("button")
|
|
52
|
+
assert_includes btn[:class], "text-primary"
|
|
53
|
+
assert_includes btn[:class], "underline-offset-4"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_size_sm
|
|
57
|
+
render_inline(UI::Button.new(size: :sm)) { "Small" }
|
|
58
|
+
assert_selector "button.h-8", text: "Small"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_size_lg
|
|
62
|
+
render_inline(UI::Button.new(size: :lg)) { "Large" }
|
|
63
|
+
assert_selector "button.h-10", text: "Large"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_size_icon
|
|
67
|
+
render_inline(UI::Button.new(size: :icon)) { "" }
|
|
68
|
+
btn = page.find("button")
|
|
69
|
+
assert_includes btn[:class], "h-9"
|
|
70
|
+
assert_includes btn[:class], "w-9"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_size_icon_sm
|
|
74
|
+
render_inline(UI::Button.new(size: :icon_sm)) { "" }
|
|
75
|
+
btn = page.find("button")
|
|
76
|
+
classes = btn[:class].split
|
|
77
|
+
assert_includes classes, "h-7"
|
|
78
|
+
assert_includes classes, "w-7"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_full_width_adds_w_full
|
|
82
|
+
render_inline(UI::Button.new(full_width: true)) { "Wide" }
|
|
83
|
+
assert_selector "button.w-full"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def test_loading_state_marks_cursor
|
|
87
|
+
render_inline(UI::Button.new(loading: true)) { "Loading" }
|
|
88
|
+
btn = page.find("button")
|
|
89
|
+
assert_includes btn[:class].split, "disabled:cursor-not-allowed"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_loading_disables_the_button
|
|
93
|
+
render_inline(UI::Button.new(loading: true)) { "Loading" }
|
|
94
|
+
btn = page.find("button[disabled]")
|
|
95
|
+
assert btn.disabled?, "button should be disabled while loading"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_disabled_param_disables_the_button
|
|
99
|
+
render_inline(UI::Button.new(disabled: true)) { "Off" }
|
|
100
|
+
btn = page.find("button[disabled]")
|
|
101
|
+
assert btn.disabled?, "button should be disabled when disabled: true"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def test_disabled_emits_disabled_grayscale_classes
|
|
105
|
+
render_inline(UI::Button.new(disabled: true)) { "Off" }
|
|
106
|
+
classes = page.find("button[disabled]")[:class].split
|
|
107
|
+
refute_includes classes, "disabled:opacity-50"
|
|
108
|
+
assert_includes classes, "disabled:bg-muted!"
|
|
109
|
+
assert_includes classes, "disabled:text-muted-foreground!"
|
|
110
|
+
assert_includes classes, "disabled:pointer-events-none"
|
|
111
|
+
assert_includes classes, "disabled:cursor-not-allowed"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_disabled_outline_variant_uses_muted_border
|
|
115
|
+
render_inline(UI::Button.new(variant: :outline, disabled: true)) { "Off" }
|
|
116
|
+
classes = page.find("button[disabled]")[:class].split
|
|
117
|
+
assert_includes classes, "disabled:bg-muted!"
|
|
118
|
+
assert_includes classes, "disabled:text-muted-foreground!"
|
|
119
|
+
assert_includes classes, "disabled:border-input!"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_disabled_ghost_variant_keeps_transparent_bg
|
|
123
|
+
render_inline(UI::Button.new(variant: :ghost, disabled: true)) { "Off" }
|
|
124
|
+
classes = page.find("button[disabled]")[:class].split
|
|
125
|
+
assert_includes classes, "disabled:bg-transparent!"
|
|
126
|
+
assert_includes classes, "disabled:text-muted-foreground!"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def test_disabled_link_variant_drops_underline
|
|
130
|
+
render_inline(UI::Button.new(variant: :link, disabled: true)) { "Off" }
|
|
131
|
+
classes = page.find("button[disabled]")[:class].split
|
|
132
|
+
assert_includes classes, "disabled:text-muted-foreground!"
|
|
133
|
+
assert_includes classes, "disabled:no-underline!"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def test_default_button_is_not_disabled
|
|
137
|
+
render_inline(UI::Button.new) { "Active" }
|
|
138
|
+
btn = page.find("button")
|
|
139
|
+
refute btn.disabled?, "button should not be disabled by default"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_disabled_and_loading_both_disable
|
|
143
|
+
render_inline(UI::Button.new(disabled: true, loading: true)) { "Both" }
|
|
144
|
+
btn = page.find("button[disabled]")
|
|
145
|
+
assert btn.disabled?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def test_type_attribute_can_be_overridden
|
|
149
|
+
render_inline(UI::Button.new(type: :submit)) { "Submit" }
|
|
150
|
+
assert_selector "button[type='submit']", text: "Submit"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def test_user_class_overrides_variant_default
|
|
154
|
+
render_inline(UI::Button.new(class: "bg-red-500")) { "Custom" }
|
|
155
|
+
btn = page.find("button")
|
|
156
|
+
classes = btn[:class].split
|
|
157
|
+
refute_includes classes, "bg-primary"
|
|
158
|
+
assert_includes classes, "bg-red-500"
|
|
159
|
+
assert_includes classes, "text-primary-foreground"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_arbitrary_html_attributes_pass_through
|
|
163
|
+
render_inline(UI::Button.new(data: { test_id: "save-btn" }, id: "primary-cta")) { "Save" }
|
|
164
|
+
assert_selector "button#primary-cta[data-test-id='save-btn']", text: "Save"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def test_as_child_param_accepted_without_error
|
|
168
|
+
assert_nothing_raised do
|
|
169
|
+
render_inline(UI::Button.new(as_child: true)) { "Future" }
|
|
170
|
+
end
|
|
171
|
+
assert_selector "button", text: "Future"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# ── Icon slots ──────────────────────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
def test_leading_icon_renders_before_content
|
|
177
|
+
render_inline(UI::Button.new) do |btn|
|
|
178
|
+
btn.with_leading_icon(name: "arrow-right")
|
|
179
|
+
"Continue"
|
|
180
|
+
end
|
|
181
|
+
btn = page.find("button")
|
|
182
|
+
icons = btn.all("i", visible: :all)
|
|
183
|
+
assert_equal 1, icons.size
|
|
184
|
+
assert_equal "arrow-right", icons.first["data-lucide"]
|
|
185
|
+
# icon precedes text in DOM order
|
|
186
|
+
assert_match(/<i[^>]*data-lucide="arrow-right".*Continue/m, btn.native.to_html)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def test_trailing_icon_renders_after_content
|
|
190
|
+
render_inline(UI::Button.new) do |btn|
|
|
191
|
+
btn.with_trailing_icon(name: "arrow-right")
|
|
192
|
+
"Next"
|
|
193
|
+
end
|
|
194
|
+
btn = page.find("button")
|
|
195
|
+
assert_match(/Next.*<i[^>]*data-lucide="arrow-right"/m, btn.native.to_html)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def test_both_leading_and_trailing_icons
|
|
199
|
+
render_inline(UI::Button.new) do |btn|
|
|
200
|
+
btn.with_leading_icon(name: "lock")
|
|
201
|
+
btn.with_trailing_icon(name: "arrow-right")
|
|
202
|
+
"Sign in"
|
|
203
|
+
end
|
|
204
|
+
btn = page.find("button")
|
|
205
|
+
icons = btn.all("i", visible: :all).map { |i| i["data-lucide"] }
|
|
206
|
+
assert_equal [ "lock", "arrow-right" ], icons
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def test_icon_only_button_renders_icon_without_text_slot
|
|
210
|
+
render_inline(UI::Button.new(size: :icon)) do |btn|
|
|
211
|
+
btn.with_leading_icon(name: "menu")
|
|
212
|
+
end
|
|
213
|
+
btn = page.find("button")
|
|
214
|
+
classes = btn[:class].split
|
|
215
|
+
assert_includes classes, "h-9"
|
|
216
|
+
assert_includes classes, "w-9"
|
|
217
|
+
assert_equal "menu", btn.find("i", visible: :all)["data-lucide"]
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def test_loading_replaces_leading_icon_with_animated_loader
|
|
221
|
+
render_inline(UI::Button.new(loading: true)) do |btn|
|
|
222
|
+
btn.with_leading_icon(name: "lock")
|
|
223
|
+
"Saving"
|
|
224
|
+
end
|
|
225
|
+
btn = page.find("button")
|
|
226
|
+
icons = btn.all("i", visible: :all)
|
|
227
|
+
assert_equal 1, icons.size
|
|
228
|
+
loader = icons.first
|
|
229
|
+
assert_equal "loader", loader["data-lucide"]
|
|
230
|
+
assert_includes loader[:class].split, "animate-spin"
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def test_loading_hides_trailing_icon
|
|
234
|
+
render_inline(UI::Button.new(loading: true)) do |btn|
|
|
235
|
+
btn.with_trailing_icon(name: "arrow-right")
|
|
236
|
+
"Saving"
|
|
237
|
+
end
|
|
238
|
+
btn = page.find("button")
|
|
239
|
+
# only the loader is rendered; trailing icon dropped
|
|
240
|
+
icons = btn.all("i", visible: :all).map { |i| i["data-lucide"] }
|
|
241
|
+
assert_equal [ "loader" ], icons
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def test_icon_slot_auto_sizes_to_button_size_sm
|
|
245
|
+
render_inline(UI::Button.new(size: :sm)) do |btn|
|
|
246
|
+
btn.with_leading_icon(name: "lock")
|
|
247
|
+
"Auth"
|
|
248
|
+
end
|
|
249
|
+
icon = page.find("button i", visible: :all)
|
|
250
|
+
classes = icon[:class].split
|
|
251
|
+
assert_includes classes, "w-3"
|
|
252
|
+
assert_includes classes, "h-3"
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def test_icon_slot_auto_sizes_to_button_size_lg
|
|
256
|
+
render_inline(UI::Button.new(size: :lg)) do |btn|
|
|
257
|
+
btn.with_leading_icon(name: "lock")
|
|
258
|
+
"Auth"
|
|
259
|
+
end
|
|
260
|
+
icon = page.find("button i", visible: :all)
|
|
261
|
+
classes = icon[:class].split
|
|
262
|
+
assert_includes classes, "w-5"
|
|
263
|
+
assert_includes classes, "h-5"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def test_icon_slot_explicit_size_overrides_auto
|
|
267
|
+
render_inline(UI::Button.new(size: :sm)) do |btn|
|
|
268
|
+
btn.with_leading_icon(name: "lock", size: :xl)
|
|
269
|
+
"Big"
|
|
270
|
+
end
|
|
271
|
+
icon = page.find("button i", visible: :all)
|
|
272
|
+
classes = icon[:class].split
|
|
273
|
+
assert_includes classes, "w-8"
|
|
274
|
+
assert_includes classes, "h-8"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::ButtonToTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_a_post_form_with_a_submit_button
|
|
10
|
+
render_inline(UI::ButtonTo.new("/session")) { "Continue" }
|
|
11
|
+
assert_selector "form[method='post'][action='/session']"
|
|
12
|
+
assert_selector "button[type='submit']", text: "Continue"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_inherits_button_variant_classes
|
|
16
|
+
render_inline(UI::ButtonTo.new("/session", variant: :outline)) { "Continue" }
|
|
17
|
+
classes = page.find("button")[:class].split
|
|
18
|
+
assert_includes classes, "border"
|
|
19
|
+
assert_includes classes, "border-input"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_full_width
|
|
23
|
+
render_inline(UI::ButtonTo.new("/session", full_width: true)) { "Continue" }
|
|
24
|
+
assert_includes page.find("button")[:class].split, "w-full"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_form_class_lands_on_the_form_not_the_button
|
|
28
|
+
render_inline(UI::ButtonTo.new("/session", form_class: "w-full")) { "Continue" }
|
|
29
|
+
assert_includes page.find("form")[:class].split, "w-full"
|
|
30
|
+
refute_includes page.find("button")[:class].split, "form-class"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Velvet::ButtonTo inherited these slots but its template never rendered them.
|
|
34
|
+
def test_renders_leading_icon_slot
|
|
35
|
+
render_inline(UI::ButtonTo.new("/session")) do |button|
|
|
36
|
+
button.with_leading_icon(name: "mail")
|
|
37
|
+
"Continue"
|
|
38
|
+
end
|
|
39
|
+
assert_selector "button i[data-lucide='mail']"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_renders_trailing_icon_slot
|
|
43
|
+
render_inline(UI::ButtonTo.new("/session")) do |button|
|
|
44
|
+
button.with_trailing_icon(name: "arrow-right")
|
|
45
|
+
"Continue"
|
|
46
|
+
end
|
|
47
|
+
assert_selector "button i[data-lucide='arrow-right']"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_loading_state_shows_spinner_and_disables
|
|
51
|
+
render_inline(UI::ButtonTo.new("/session", loading: true)) { "Continue" }
|
|
52
|
+
button = page.find("button")
|
|
53
|
+
assert_equal "true", button[:"aria-busy"]
|
|
54
|
+
assert button[:disabled].present?
|
|
55
|
+
assert_selector "button .sr-only", text: "Loading, please wait"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_disabled
|
|
59
|
+
render_inline(UI::ButtonTo.new("/session", disabled: true)) { "Continue" }
|
|
60
|
+
assert page.find("button")[:disabled].present?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_user_class_override_via_tailwind_merge
|
|
64
|
+
render_inline(UI::ButtonTo.new("/session", class: "bg-red-500")) { "Continue" }
|
|
65
|
+
classes = page.find("button")[:class].split
|
|
66
|
+
assert_includes classes, "bg-red-500"
|
|
67
|
+
refute_includes classes, "bg-primary"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_html_attrs_passthrough
|
|
71
|
+
render_inline(UI::ButtonTo.new("/session", data: { turbo: false })) { "Continue" }
|
|
72
|
+
assert_selector "button[data-turbo='false']"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Card::ContentTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_div
|
|
10
|
+
render_inline(UI::Card::Content.new) { "Content" }
|
|
11
|
+
assert_selector "div", text: "Content"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_default_classes
|
|
15
|
+
render_inline(UI::Card::Content.new) { "x" }
|
|
16
|
+
classes = page.find("div")[:class].split
|
|
17
|
+
assert_includes classes, "p-6"
|
|
18
|
+
assert_includes classes, "pt-0"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_user_class_override
|
|
22
|
+
render_inline(UI::Card::Content.new(class: "p-4")) { "x" }
|
|
23
|
+
classes = page.find("div")[:class].split
|
|
24
|
+
refute_includes classes, "p-6"
|
|
25
|
+
assert_includes classes, "p-4"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_html_attrs_passthrough
|
|
29
|
+
render_inline(UI::Card::Content.new(id: "my-content", data: { test_id: "c" })) { "x" }
|
|
30
|
+
assert_selector "div#my-content[data-test-id='c']"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Content sits flush under a header, but needs its own top padding when it
|
|
34
|
+
# is the first thing in the card.
|
|
35
|
+
def test_content_first_in_a_card_gets_top_padding
|
|
36
|
+
render_inline(UI::Card::Content.new) { "Body" }
|
|
37
|
+
classes = page.find("div")[:class].split
|
|
38
|
+
assert_includes classes, "pt-0"
|
|
39
|
+
assert_includes classes, "first:pt-6"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Card::DescriptionTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_p
|
|
10
|
+
render_inline(UI::Card::Description.new) { "Description" }
|
|
11
|
+
assert_selector "p", text: "Description"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_default_classes
|
|
15
|
+
render_inline(UI::Card::Description.new) { "x" }
|
|
16
|
+
classes = page.find("p")[:class].split
|
|
17
|
+
assert_includes classes, "text-sm"
|
|
18
|
+
assert_includes classes, "text-muted-foreground"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_user_class_override
|
|
22
|
+
render_inline(UI::Card::Description.new(class: "text-xs")) { "x" }
|
|
23
|
+
classes = page.find("p")[:class].split
|
|
24
|
+
refute_includes classes, "text-sm"
|
|
25
|
+
assert_includes classes, "text-xs"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_html_attrs_passthrough
|
|
29
|
+
render_inline(UI::Card::Description.new(id: "my-desc", data: { test_id: "d" })) { "x" }
|
|
30
|
+
assert_selector "p#my-desc[data-test-id='d']"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Card::FooterTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_div
|
|
10
|
+
render_inline(UI::Card::Footer.new) { "Footer" }
|
|
11
|
+
assert_selector "div", text: "Footer"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_default_classes
|
|
15
|
+
render_inline(UI::Card::Footer.new) { "x" }
|
|
16
|
+
classes = page.find("div")[:class].split
|
|
17
|
+
assert_includes classes, "flex"
|
|
18
|
+
assert_includes classes, "items-center"
|
|
19
|
+
assert_includes classes, "p-6"
|
|
20
|
+
assert_includes classes, "pt-0"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_user_class_override
|
|
24
|
+
render_inline(UI::Card::Footer.new(class: "p-4")) { "x" }
|
|
25
|
+
classes = page.find("div")[:class].split
|
|
26
|
+
refute_includes classes, "p-6"
|
|
27
|
+
assert_includes classes, "p-4"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_html_attrs_passthrough
|
|
31
|
+
render_inline(UI::Card::Footer.new(id: "my-footer", data: { test_id: "f" })) { "x" }
|
|
32
|
+
assert_selector "div#my-footer[data-test-id='f']"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Card::HeaderTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_div
|
|
10
|
+
render_inline(UI::Card::Header.new) { "Header" }
|
|
11
|
+
assert_selector "div", text: "Header"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_default_classes
|
|
15
|
+
render_inline(UI::Card::Header.new) { "x" }
|
|
16
|
+
classes = page.find("div")[:class].split
|
|
17
|
+
assert_includes classes, "flex"
|
|
18
|
+
assert_includes classes, "flex-col"
|
|
19
|
+
assert_includes classes, "gap-1.5"
|
|
20
|
+
assert_includes classes, "p-6"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_renders_with_title_slot
|
|
24
|
+
render_inline(UI::Card::Header.new) do |header|
|
|
25
|
+
header.with_title { "Title" }
|
|
26
|
+
end
|
|
27
|
+
assert_selector "h3", text: "Title"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_renders_with_description_slot
|
|
31
|
+
render_inline(UI::Card::Header.new) do |header|
|
|
32
|
+
header.with_description { "Description" }
|
|
33
|
+
end
|
|
34
|
+
assert_selector "p", text: "Description"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_renders_title_and_description_together
|
|
38
|
+
render_inline(UI::Card::Header.new) do |header|
|
|
39
|
+
header.with_title { "Title" }
|
|
40
|
+
header.with_description { "Description" }
|
|
41
|
+
end
|
|
42
|
+
header_el = page.find("div")
|
|
43
|
+
assert_equal "TitleDescription", header_el.text.gsub(/\s+/, "")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_user_class_override
|
|
47
|
+
render_inline(UI::Card::Header.new(class: "p-4")) { "x" }
|
|
48
|
+
classes = page.find("div")[:class].split
|
|
49
|
+
refute_includes classes, "p-6"
|
|
50
|
+
assert_includes classes, "p-4"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_html_attrs_passthrough
|
|
54
|
+
render_inline(UI::Card::Header.new(id: "my-header", data: { test_id: "hdr" })) { "x" }
|
|
55
|
+
assert_selector "div#my-header[data-test-id='hdr']"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Card::TitleTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_h3
|
|
10
|
+
render_inline(UI::Card::Title.new) { "Title" }
|
|
11
|
+
assert_selector "h3", text: "Title"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_default_classes
|
|
15
|
+
render_inline(UI::Card::Title.new) { "x" }
|
|
16
|
+
classes = page.find("h3")[:class].split
|
|
17
|
+
assert_includes classes, "text-lg"
|
|
18
|
+
assert_includes classes, "font-semibold"
|
|
19
|
+
assert_includes classes, "leading-none"
|
|
20
|
+
assert_includes classes, "tracking-tight"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_user_class_override
|
|
24
|
+
render_inline(UI::Card::Title.new(class: "text-xl")) { "x" }
|
|
25
|
+
classes = page.find("h3")[:class].split
|
|
26
|
+
refute_includes classes, "text-lg"
|
|
27
|
+
assert_includes classes, "text-xl"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_html_attrs_passthrough
|
|
31
|
+
render_inline(UI::Card::Title.new(id: "my-title", data: { test_id: "t" })) { "x" }
|
|
32
|
+
assert_selector "h3#my-title[data-test-id='t']"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::CardTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_default_card
|
|
10
|
+
render_inline(UI::Card.new) { "Card content" }
|
|
11
|
+
assert_selector "div", text: "Card content"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_root_classes
|
|
15
|
+
render_inline(UI::Card.new) { "x" }
|
|
16
|
+
classes = page.find("div")[:class].split
|
|
17
|
+
assert_includes classes, "rounded-xl"
|
|
18
|
+
assert_includes classes, "border"
|
|
19
|
+
assert_includes classes, "bg-card"
|
|
20
|
+
assert_includes classes, "text-card-foreground"
|
|
21
|
+
assert_includes classes, "shadow"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_renders_with_header_slot
|
|
25
|
+
render_inline(UI::Card.new) do |card|
|
|
26
|
+
card.with_header { "Header" }
|
|
27
|
+
"Body"
|
|
28
|
+
end
|
|
29
|
+
assert_selector "div div", text: "Header"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_renders_with_content_slot
|
|
33
|
+
render_inline(UI::Card.new) do |card|
|
|
34
|
+
card.with_content { "Content" }
|
|
35
|
+
end
|
|
36
|
+
assert_selector "div div", text: "Content"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_renders_with_footer_slot
|
|
40
|
+
render_inline(UI::Card.new) do |card|
|
|
41
|
+
card.with_footer { "Footer" }
|
|
42
|
+
end
|
|
43
|
+
assert_selector "div div", text: "Footer"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_renders_all_slots_together
|
|
47
|
+
render_inline(UI::Card.new(id: "all-slots")) do |card|
|
|
48
|
+
card.with_header { "Header" }
|
|
49
|
+
card.with_content { "Content" }
|
|
50
|
+
card.with_footer { "Footer" }
|
|
51
|
+
end
|
|
52
|
+
card_el = page.find("div#all-slots")
|
|
53
|
+
assert_equal "HeaderContentFooter", card_el.text.gsub(/\s+/, "")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_user_class_override_via_tailwind_merge
|
|
57
|
+
render_inline(UI::Card.new(class: "bg-red-500")) { "x" }
|
|
58
|
+
classes = page.find("div")[:class].split
|
|
59
|
+
refute_includes classes, "bg-card"
|
|
60
|
+
assert_includes classes, "bg-red-500"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_html_attrs_passthrough
|
|
64
|
+
render_inline(UI::Card.new(id: "my-card", data: { test_id: "card-x" })) { "x" }
|
|
65
|
+
assert_selector "div#my-card[data-test-id='card-x']"
|
|
66
|
+
end
|
|
67
|
+
end
|