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,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::TabsTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def render_tabs(default_value: "a", variant: :line)
|
|
10
|
+
render_inline(UI::Tabs.new(default_value: default_value, variant: variant)) do |tabs|
|
|
11
|
+
tabs.with_list do |list|
|
|
12
|
+
list.with_trigger(value: "a") { "A" }
|
|
13
|
+
list.with_trigger(value: "b") { "B" }
|
|
14
|
+
end
|
|
15
|
+
tabs.with_panel(value: "a") { "panel-a" }
|
|
16
|
+
tabs.with_panel(value: "b") { "panel-b" }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_root_carries_controller
|
|
21
|
+
render_tabs
|
|
22
|
+
root = page.find("[data-controller~='ui--tabs']")
|
|
23
|
+
assert_equal "a", root["data-ui--tabs-active-value"]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_default_value_selects_active_tab
|
|
27
|
+
render_tabs(default_value: "b")
|
|
28
|
+
root = page.find("[data-controller~='ui--tabs']")
|
|
29
|
+
assert_equal "b", root["data-ui--tabs-active-value"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_inactive_panel_is_hidden
|
|
33
|
+
render_tabs(default_value: "a")
|
|
34
|
+
assert_selector "[role='tabpanel'][data-value='b'][hidden]", visible: :all
|
|
35
|
+
assert_no_selector "[role='tabpanel'][data-value='a'][hidden]", visible: :all
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_active_panel_not_hidden
|
|
39
|
+
render_tabs(default_value: "a")
|
|
40
|
+
panel = page.find("[role='tabpanel'][data-value='a']")
|
|
41
|
+
refute panel[:hidden].present?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_root_has_auto_generated_id
|
|
45
|
+
render_tabs
|
|
46
|
+
root = page.find("[data-controller~='ui--tabs']")
|
|
47
|
+
assert root[:id].present?
|
|
48
|
+
assert root[:id].start_with?("ui-tabs-")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_custom_id_preserved
|
|
52
|
+
render_inline(UI::Tabs.new(default_value: "a", id: "my-tabs")) do |tabs|
|
|
53
|
+
tabs.with_list do |list|
|
|
54
|
+
list.with_trigger(value: "a") { "A" }
|
|
55
|
+
end
|
|
56
|
+
tabs.with_panel(value: "a") { "panel-a" }
|
|
57
|
+
end
|
|
58
|
+
assert_selector "[data-controller~='ui--tabs']#my-tabs"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_user_class_merge
|
|
62
|
+
render_inline(UI::Tabs.new(default_value: "a", class: "my-custom-class")) do |tabs|
|
|
63
|
+
tabs.with_list do |list|
|
|
64
|
+
list.with_trigger(value: "a") { "A" }
|
|
65
|
+
end
|
|
66
|
+
tabs.with_panel(value: "a") { "panel-a" }
|
|
67
|
+
end
|
|
68
|
+
classes = page.find("[data-controller~='ui--tabs']")[:class].split
|
|
69
|
+
assert_includes classes, "my-custom-class"
|
|
70
|
+
assert_includes classes, "w-full"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_html_attrs_passthrough
|
|
74
|
+
render_inline(UI::Tabs.new(default_value: "a", data: { test_id: "tabs-x" })) do |tabs|
|
|
75
|
+
tabs.with_list do |list|
|
|
76
|
+
list.with_trigger(value: "a") { "A" }
|
|
77
|
+
end
|
|
78
|
+
tabs.with_panel(value: "a") { "panel-a" }
|
|
79
|
+
end
|
|
80
|
+
assert_selector "[data-controller~='ui--tabs'][data-test-id='tabs-x']"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_panels_rendered_at_root_level
|
|
84
|
+
render_tabs
|
|
85
|
+
panels = page.all("[role='tabpanel']", visible: :all)
|
|
86
|
+
assert_equal 2, panels.size
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::TextTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_paragraph_by_default
|
|
10
|
+
render_inline(UI::Text.new) { "Hello world" }
|
|
11
|
+
assert_selector "p", text: "Hello world"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_renders_as_span
|
|
15
|
+
render_inline(UI::Text.new(as: :span)) { "Inline text" }
|
|
16
|
+
assert_selector "span", text: "Inline text"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_renders_as_div
|
|
20
|
+
render_inline(UI::Text.new(as: :div)) { "Block text" }
|
|
21
|
+
assert_selector "div", text: "Block text"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_default_classes
|
|
25
|
+
render_inline(UI::Text.new) { "x" }
|
|
26
|
+
classes = page.find("p")[:class].split
|
|
27
|
+
assert_includes classes, "text-base"
|
|
28
|
+
assert_includes classes, "font-normal"
|
|
29
|
+
assert_includes classes, "text-foreground"
|
|
30
|
+
# Note: leading-normal is in base but tailwind_merge may remove it
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_size_variants
|
|
34
|
+
render_inline(UI::Text.new(size: :sm)) { "Small" }
|
|
35
|
+
classes = page.find("p")[:class].split
|
|
36
|
+
assert_includes classes, "text-sm"
|
|
37
|
+
refute_includes classes, "text-base"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_weight_variants
|
|
41
|
+
render_inline(UI::Text.new(weight: :bold)) { "Bold" }
|
|
42
|
+
classes = page.find("p")[:class].split
|
|
43
|
+
assert_includes classes, "font-bold"
|
|
44
|
+
refute_includes classes, "font-normal"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_tone_variants
|
|
48
|
+
render_inline(UI::Text.new(tone: :muted)) { "Muted" }
|
|
49
|
+
classes = page.find("p")[:class].split
|
|
50
|
+
assert_includes classes, "text-muted-foreground"
|
|
51
|
+
refute_includes classes, "text-foreground"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_destructive_tone
|
|
55
|
+
render_inline(UI::Text.new(tone: :destructive)) { "Error" }
|
|
56
|
+
classes = page.find("p")[:class].split
|
|
57
|
+
assert_includes classes, "text-destructive"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_user_class_merge
|
|
61
|
+
render_inline(UI::Text.new(class: "text-center")) { "Centered" }
|
|
62
|
+
classes = page.find("p")[:class].split
|
|
63
|
+
assert_includes classes, "text-center"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_user_class_overrides_defaults
|
|
67
|
+
render_inline(UI::Text.new(class: "font-light")) { "Light" }
|
|
68
|
+
classes = page.find("p")[:class].split
|
|
69
|
+
refute_includes classes, "font-normal"
|
|
70
|
+
assert_includes classes, "font-light"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_html_attrs_passthrough
|
|
74
|
+
render_inline(UI::Text.new(id: "my-text", data: { test: "x" })) { "y" }
|
|
75
|
+
assert_selector "p#my-text[data-test='x']"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_large_heading_size
|
|
79
|
+
render_inline(UI::Text.new(size: :"4xl", weight: :bold)) { "Hero" }
|
|
80
|
+
classes = page.find("p")[:class].split
|
|
81
|
+
assert_includes classes, "text-4xl"
|
|
82
|
+
assert_includes classes, "font-bold"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::ThemeToggleTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_wires_the_theme_controller
|
|
10
|
+
render_inline(UI::ThemeToggle.new)
|
|
11
|
+
assert_selector "[data-controller='ui--theme']"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_trigger_has_an_accessible_name
|
|
15
|
+
render_inline(UI::ThemeToggle.new)
|
|
16
|
+
assert_equal "Change theme", page.find("button[aria-haspopup]")[:"aria-label"]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_custom_label
|
|
20
|
+
render_inline(UI::ThemeToggle.new(label: "Appearance"))
|
|
21
|
+
assert_equal "Appearance", page.find("button[aria-haspopup]")[:"aria-label"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_offers_all_three_preferences
|
|
25
|
+
render_inline(UI::ThemeToggle.new)
|
|
26
|
+
themes = page.all("[data-ui--theme-target='option']", visible: :all).map { |o| o[:"data-theme"] }
|
|
27
|
+
assert_equal %w[light dark system], themes
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_options_wire_the_select_action
|
|
31
|
+
render_inline(UI::ThemeToggle.new)
|
|
32
|
+
page.all("[data-ui--theme-target='option']", visible: :all).each do |option|
|
|
33
|
+
assert_includes option[:"data-action"], "ui--theme#select"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# aria-checked is only valid on a radio/checkbox role, so the options must
|
|
38
|
+
# not fall back to UI::Menu::Item's default role="menuitem".
|
|
39
|
+
def test_options_use_the_radio_role_for_aria_checked
|
|
40
|
+
render_inline(UI::ThemeToggle.new)
|
|
41
|
+
options = page.all("[data-ui--theme-target='option']", visible: :all)
|
|
42
|
+
assert_equal 3, options.size
|
|
43
|
+
options.each do |option|
|
|
44
|
+
assert_equal "menuitemradio", option[:role]
|
|
45
|
+
assert_equal "false", option[:"aria-checked"]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# lucide swaps each <i data-lucide> for an <svg> on first render, so the
|
|
50
|
+
# element is gone afterwards and the icon cannot be changed by attribute.
|
|
51
|
+
# All three are rendered and shown by the preference on <html data-theme>:
|
|
52
|
+
# the sun for light, which is the default (and before any script runs).
|
|
53
|
+
def test_trigger_icon_follows_the_preference_with_light_by_default
|
|
54
|
+
render_inline(UI::ThemeToggle.new)
|
|
55
|
+
trigger = page.find("button[aria-haspopup]")
|
|
56
|
+
icon = ->(name) { trigger.find("i[data-lucide='#{name}']", visible: :all)[:class].split }
|
|
57
|
+
sun = icon.("sun")
|
|
58
|
+
assert_includes sun, "block"
|
|
59
|
+
assert_includes sun, "in-data-[theme=dark]:hidden"
|
|
60
|
+
assert_includes sun, "in-data-[theme=system]:hidden"
|
|
61
|
+
assert_includes icon.("moon"), "in-data-[theme=dark]:block"
|
|
62
|
+
assert_includes icon.("monitor"), "in-data-[theme=system]:block"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_html_attrs_passthrough
|
|
66
|
+
render_inline(UI::ThemeToggle.new(id: "theme", data: { test_id: "tt" }))
|
|
67
|
+
assert_selector "#theme[data-test-id='tt']"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# The checked option needs a persistent background, not just a focus ring —
|
|
71
|
+
# otherwise nothing shows which theme is active once focus moves.
|
|
72
|
+
def test_options_carry_the_checked_state_styling
|
|
73
|
+
render_inline(UI::ThemeToggle.new)
|
|
74
|
+
option = page.all("[data-ui--theme-target='option']", visible: :all).first
|
|
75
|
+
classes = option[:class].split
|
|
76
|
+
assert_includes classes, "aria-checked:bg-accent"
|
|
77
|
+
assert_includes classes, "aria-checked:font-medium"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_each_option_has_a_check_indicator_shown_only_when_checked
|
|
81
|
+
render_inline(UI::ThemeToggle.new)
|
|
82
|
+
page.all("[data-ui--theme-target='option']", visible: :all).each do |option|
|
|
83
|
+
check = option.find("i[data-lucide='check']", visible: :all)
|
|
84
|
+
assert_includes check[:class].split, "hidden"
|
|
85
|
+
assert_includes check[:class].split, "group-aria-checked:block"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Tooltip::ContentTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_content
|
|
10
|
+
result = render_inline(UI::Tooltip.new) do |tooltip|
|
|
11
|
+
tooltip.with_trigger { "Trigger" }
|
|
12
|
+
tooltip.with_content { "Tooltip content" }
|
|
13
|
+
end
|
|
14
|
+
# Tooltip content is hidden by default, check it's in the HTML
|
|
15
|
+
assert result.to_html.include?("Tooltip content")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_has_role_tooltip
|
|
19
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
20
|
+
tooltip.with_trigger { "Trigger" }
|
|
21
|
+
tooltip.with_content { "Content" }
|
|
22
|
+
end
|
|
23
|
+
assert_selector "[role='tooltip']", visible: false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_is_initially_hidden
|
|
27
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
28
|
+
tooltip.with_trigger { "Trigger" }
|
|
29
|
+
tooltip.with_content { "Content" }
|
|
30
|
+
end
|
|
31
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
32
|
+
assert content[:hidden].present?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_has_data_target
|
|
36
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
37
|
+
tooltip.with_trigger { "Trigger" }
|
|
38
|
+
tooltip.with_content { "Content" }
|
|
39
|
+
end
|
|
40
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
41
|
+
assert_equal "content", content[:"data-ui--tooltip-target"]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_default_side_top
|
|
45
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
46
|
+
tooltip.with_trigger { "Trigger" }
|
|
47
|
+
tooltip.with_content { "Content" }
|
|
48
|
+
end
|
|
49
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
50
|
+
assert_equal "top", content[:"data-side"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_custom_side
|
|
54
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
55
|
+
tooltip.with_trigger { "Trigger" }
|
|
56
|
+
tooltip.with_content(side: :right) { "Content" }
|
|
57
|
+
end
|
|
58
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
59
|
+
assert_equal "right", content[:"data-side"]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_custom_align
|
|
63
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
64
|
+
tooltip.with_trigger { "Trigger" }
|
|
65
|
+
tooltip.with_content(align: :end) { "Content" }
|
|
66
|
+
end
|
|
67
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
68
|
+
assert_equal "end", content[:"data-align"]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_has_animation_classes
|
|
72
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
73
|
+
tooltip.with_trigger { "Trigger" }
|
|
74
|
+
tooltip.with_content { "Content" }
|
|
75
|
+
end
|
|
76
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
77
|
+
assert content[:class].include?("animate-in")
|
|
78
|
+
assert content[:class].include?("fade-in-0")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_custom_class_merge
|
|
82
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
83
|
+
tooltip.with_trigger { "Trigger" }
|
|
84
|
+
tooltip.with_content(class: "custom-content") { "Content" }
|
|
85
|
+
end
|
|
86
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
87
|
+
assert_includes content[:class].split, "custom-content"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Both tokens invert together, so the tooltip stays readable in either theme.
|
|
91
|
+
# A pinned near-white (text-slate-50) sat on a near-white bg-foreground in
|
|
92
|
+
# dark mode and was unreadable.
|
|
93
|
+
def test_uses_inverted_surface_tokens
|
|
94
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
95
|
+
tooltip.with_trigger { "Trigger" }
|
|
96
|
+
tooltip.with_content { "Content" }
|
|
97
|
+
end
|
|
98
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
99
|
+
classes = content[:class].split
|
|
100
|
+
assert_includes classes, "bg-foreground"
|
|
101
|
+
assert_includes classes, "text-background"
|
|
102
|
+
refute_includes classes, "text-slate-50"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_does_not_clip_overflow
|
|
106
|
+
# Floating UI positions the arrow partially outside the content box
|
|
107
|
+
# via negative staticSide offset; overflow-hidden would clip it.
|
|
108
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
109
|
+
tooltip.with_trigger { "Trigger" }
|
|
110
|
+
tooltip.with_content { "Content" }
|
|
111
|
+
end
|
|
112
|
+
classes = page.find("[role='tooltip']", visible: false)[:class].split
|
|
113
|
+
refute_includes classes, "overflow-hidden"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_has_arrow_element
|
|
117
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
118
|
+
tooltip.with_trigger { "Trigger" }
|
|
119
|
+
tooltip.with_content { "Content" }
|
|
120
|
+
end
|
|
121
|
+
assert_selector "[data-ui--tooltip-target='arrow']", visible: false
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def test_arrow_has_matching_background_and_rotation
|
|
125
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
126
|
+
tooltip.with_trigger { "Trigger" }
|
|
127
|
+
tooltip.with_content { "Content" }
|
|
128
|
+
end
|
|
129
|
+
arrow = page.find("[data-ui--tooltip-target='arrow']", visible: false)
|
|
130
|
+
classes = arrow[:class].split
|
|
131
|
+
assert_includes classes, "bg-foreground"
|
|
132
|
+
assert_includes classes, "rotate-45"
|
|
133
|
+
assert_includes classes, "absolute"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Tooltip::TriggerTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_content
|
|
10
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
11
|
+
tooltip.with_trigger { "Trigger text" }
|
|
12
|
+
tooltip.with_content { "Content" }
|
|
13
|
+
end
|
|
14
|
+
assert_text "Trigger text"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_has_aria_describedby
|
|
18
|
+
render_inline(UI::Tooltip.new(id: "test-id")) do |tooltip|
|
|
19
|
+
tooltip.with_trigger { "Trigger" }
|
|
20
|
+
tooltip.with_content { "Content" }
|
|
21
|
+
end
|
|
22
|
+
trigger = page.find("[data-ui--tooltip-target='trigger']")
|
|
23
|
+
assert_equal "ui-tooltip-content-test-id", trigger[:"aria-describedby"]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_has_data_target
|
|
27
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
28
|
+
tooltip.with_trigger { "Trigger" }
|
|
29
|
+
tooltip.with_content { "Content" }
|
|
30
|
+
end
|
|
31
|
+
assert_selector "[data-ui--tooltip-target='trigger']"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_has_interaction_actions
|
|
35
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
36
|
+
tooltip.with_trigger { "Trigger" }
|
|
37
|
+
tooltip.with_content { "Content" }
|
|
38
|
+
end
|
|
39
|
+
trigger = page.find("[data-ui--tooltip-target='trigger']")
|
|
40
|
+
assert trigger[:"data-action"].include?("mouseenter->ui--tooltip#show")
|
|
41
|
+
assert trigger[:"data-action"].include?("mouseleave->ui--tooltip#hide")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_custom_class_merge
|
|
45
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
46
|
+
tooltip.with_trigger(class: "custom-trigger") { "Trigger" }
|
|
47
|
+
tooltip.with_content { "Content" }
|
|
48
|
+
end
|
|
49
|
+
trigger = page.find("[data-ui--tooltip-target='trigger']")
|
|
50
|
+
assert_includes trigger[:class].split, "custom-trigger"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::TooltipTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def render_tooltip
|
|
10
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
11
|
+
tooltip.with_trigger { "Hover me" }
|
|
12
|
+
tooltip.with_content { "Tooltip text" }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_root_renders_trigger_and_content
|
|
17
|
+
result = render_tooltip
|
|
18
|
+
assert_text "Hover me"
|
|
19
|
+
# Tooltip content is hidden by default, check it's in the HTML
|
|
20
|
+
assert result.to_html.include?("Tooltip text")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_trigger_has_aria_describedby
|
|
24
|
+
render_tooltip
|
|
25
|
+
trigger = page.find("[data-ui--tooltip-target='trigger']")
|
|
26
|
+
assert trigger[:"aria-describedby"].present?
|
|
27
|
+
assert trigger[:"aria-describedby"].start_with?("ui-tooltip-content-")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_trigger_has_interaction_actions
|
|
31
|
+
render_tooltip
|
|
32
|
+
trigger = page.find("[data-ui--tooltip-target='trigger']")
|
|
33
|
+
assert trigger[:"data-action"].include?("mouseenter->ui--tooltip#show")
|
|
34
|
+
assert trigger[:"data-action"].include?("mouseleave->ui--tooltip#hide")
|
|
35
|
+
assert trigger[:"data-action"].include?("focus->ui--tooltip#show")
|
|
36
|
+
assert trigger[:"data-action"].include?("blur->ui--tooltip#hide")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_content_has_role_tooltip
|
|
40
|
+
render_tooltip
|
|
41
|
+
assert_selector "[role='tooltip']", visible: false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_content_is_initially_hidden
|
|
45
|
+
render_tooltip
|
|
46
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
47
|
+
assert content[:hidden].present?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_content_has_data_targets
|
|
51
|
+
render_tooltip
|
|
52
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
53
|
+
assert_equal "content", content[:"data-ui--tooltip-target"]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_default_side_is_top
|
|
57
|
+
render_tooltip
|
|
58
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
59
|
+
assert_equal "top", content[:"data-side"]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_custom_side
|
|
63
|
+
render_inline(UI::Tooltip.new) do |tooltip|
|
|
64
|
+
tooltip.with_trigger { "Hover me" }
|
|
65
|
+
tooltip.with_content(side: :bottom) { "Tooltip text" }
|
|
66
|
+
end
|
|
67
|
+
content = page.find("[role='tooltip']", visible: false)
|
|
68
|
+
assert_equal "bottom", content[:"data-side"]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_custom_id_preserved
|
|
72
|
+
render_inline(UI::Tooltip.new(id: "my-tooltip")) do |tooltip|
|
|
73
|
+
tooltip.with_trigger { "Hover me" }
|
|
74
|
+
tooltip.with_content { "Tooltip text" }
|
|
75
|
+
end
|
|
76
|
+
assert_selector "#my-tooltip"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_user_class_merge
|
|
80
|
+
render_inline(UI::Tooltip.new(class: "my-custom-class")) do |tooltip|
|
|
81
|
+
tooltip.with_trigger { "Hover me" }
|
|
82
|
+
tooltip.with_content { "Tooltip text" }
|
|
83
|
+
end
|
|
84
|
+
root = page.find("[data-controller='ui--tooltip']")
|
|
85
|
+
classes = root[:class].split
|
|
86
|
+
assert_includes classes, "my-custom-class"
|
|
87
|
+
assert_includes classes, "inline-block"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_html_attrs_passthrough
|
|
91
|
+
render_inline(UI::Tooltip.new(data: { test_id: "tooltip-x" })) do |tooltip|
|
|
92
|
+
tooltip.with_trigger { "Hover me" }
|
|
93
|
+
tooltip.with_content { "Tooltip text" }
|
|
94
|
+
end
|
|
95
|
+
assert_selector "[data-controller='ui--tooltip'][data-test-id='tooltip-x']"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Typography::CodeTest < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_code_tag
|
|
10
|
+
render_inline(UI::Typography::Code.new) { "npm install" }
|
|
11
|
+
assert_selector "code", text: "npm install"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_has_mono_font_and_background
|
|
15
|
+
render_inline(UI::Typography::Code.new) { "x" }
|
|
16
|
+
classes = page.find("code")[:class].split
|
|
17
|
+
assert_includes classes, "font-mono"
|
|
18
|
+
assert_includes classes, "bg-muted"
|
|
19
|
+
assert_includes classes, "rounded"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_size_variants
|
|
23
|
+
render_inline(UI::Typography::Code.new(size: :sm)) { "small" }
|
|
24
|
+
classes = page.find("code")[:class].split
|
|
25
|
+
assert_includes classes, "text-xs"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_user_class_merge
|
|
29
|
+
render_inline(UI::Typography::Code.new(class: "text-destructive")) { "x" }
|
|
30
|
+
classes = page.find("code")[:class].split
|
|
31
|
+
assert_includes classes, "text-destructive"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class UI::Typography::BlockquoteTest < ViewComponent::TestCase
|
|
36
|
+
def setup_fixtures(*); end
|
|
37
|
+
def teardown_fixtures(*); end
|
|
38
|
+
|
|
39
|
+
def test_renders_blockquote_tag
|
|
40
|
+
render_inline(UI::Typography::Blockquote.new) { "A famous quote" }
|
|
41
|
+
assert_selector "blockquote", text: "A famous quote"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_has_left_border_and_italic
|
|
45
|
+
render_inline(UI::Typography::Blockquote.new) { "x" }
|
|
46
|
+
classes = page.find("blockquote")[:class].split
|
|
47
|
+
assert_includes classes, "border-l-2"
|
|
48
|
+
assert_includes classes, "italic"
|
|
49
|
+
assert_includes classes, "pl-6"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_user_class_merge
|
|
53
|
+
render_inline(UI::Typography::Blockquote.new(class: "mt-8")) { "x" }
|
|
54
|
+
classes = page.find("blockquote")[:class].split
|
|
55
|
+
assert_includes classes, "mt-8"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class UI::Typography::H1Test < ViewComponent::TestCase
|
|
6
|
+
def setup_fixtures(*); end
|
|
7
|
+
def teardown_fixtures(*); end
|
|
8
|
+
|
|
9
|
+
def test_renders_h1_tag
|
|
10
|
+
render_inline(UI::Typography::H1.new) { "Heading 1" }
|
|
11
|
+
assert_selector "h1", text: "Heading 1"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_has_correct_classes
|
|
15
|
+
render_inline(UI::Typography::H1.new) { "x" }
|
|
16
|
+
classes = page.find("h1")[:class].split
|
|
17
|
+
assert_includes classes, "text-4xl"
|
|
18
|
+
assert_includes classes, "font-bold"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class UI::Typography::H2Test < ViewComponent::TestCase
|
|
23
|
+
def setup_fixtures(*); end
|
|
24
|
+
def teardown_fixtures(*); end
|
|
25
|
+
|
|
26
|
+
def test_renders_h2_tag
|
|
27
|
+
render_inline(UI::Typography::H2.new) { "Heading 2" }
|
|
28
|
+
assert_selector "h2", text: "Heading 2"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_has_correct_classes
|
|
32
|
+
render_inline(UI::Typography::H2.new) { "x" }
|
|
33
|
+
classes = page.find("h2")[:class].split
|
|
34
|
+
assert_includes classes, "text-3xl"
|
|
35
|
+
assert_includes classes, "font-semibold"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class UI::Typography::H3Test < ViewComponent::TestCase
|
|
40
|
+
def setup_fixtures(*); end
|
|
41
|
+
def teardown_fixtures(*); end
|
|
42
|
+
|
|
43
|
+
def test_renders_h3_tag
|
|
44
|
+
render_inline(UI::Typography::H3.new) { "Heading 3" }
|
|
45
|
+
assert_selector "h3", text: "Heading 3"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_has_correct_classes
|
|
49
|
+
render_inline(UI::Typography::H3.new) { "x" }
|
|
50
|
+
classes = page.find("h3")[:class].split
|
|
51
|
+
assert_includes classes, "text-2xl"
|
|
52
|
+
assert_includes classes, "font-semibold"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class UI::Typography::H4Test < ViewComponent::TestCase
|
|
57
|
+
def setup_fixtures(*); end
|
|
58
|
+
def teardown_fixtures(*); end
|
|
59
|
+
|
|
60
|
+
def test_renders_h4_tag
|
|
61
|
+
render_inline(UI::Typography::H4.new) { "Heading 4" }
|
|
62
|
+
assert_selector "h4", text: "Heading 4"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_has_correct_classes
|
|
66
|
+
render_inline(UI::Typography::H4.new) { "x" }
|
|
67
|
+
classes = page.find("h4")[:class].split
|
|
68
|
+
assert_includes classes, "text-xl"
|
|
69
|
+
assert_includes classes, "font-semibold"
|
|
70
|
+
end
|
|
71
|
+
end
|