phlex_kit 0.2.0
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/MIT-LICENSE +21 -0
- data/README.md +135 -0
- data/app/assets/stylesheets/phlex_kit/_tokens.css +91 -0
- data/app/assets/stylesheets/phlex_kit/phlex_kit.css +82 -0
- data/app/components/phlex_kit/accordion/accordion.css +14 -0
- data/app/components/phlex_kit/accordion/accordion.rb +10 -0
- data/app/components/phlex_kit/accordion/accordion_content.rb +8 -0
- data/app/components/phlex_kit/accordion/accordion_default_content.rb +6 -0
- data/app/components/phlex_kit/accordion/accordion_default_trigger.rb +12 -0
- data/app/components/phlex_kit/accordion/accordion_icon.rb +16 -0
- data/app/components/phlex_kit/accordion/accordion_item.rb +12 -0
- data/app/components/phlex_kit/accordion/accordion_trigger.rb +8 -0
- data/app/components/phlex_kit/alert/alert.css +32 -0
- data/app/components/phlex_kit/alert/alert.rb +37 -0
- data/app/components/phlex_kit/alert/alert_description.rb +12 -0
- data/app/components/phlex_kit/alert/alert_title.rb +12 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog.css +37 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog.rb +20 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_action.rb +14 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_cancel.rb +13 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_content.rb +19 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_description.rb +12 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_footer.rb +12 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_header.rb +12 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_title.rb +12 -0
- data/app/components/phlex_kit/alert_dialog/alert_dialog_trigger.rb +12 -0
- data/app/components/phlex_kit/aspect_ratio/aspect_ratio.css +12 -0
- data/app/components/phlex_kit/aspect_ratio/aspect_ratio.rb +27 -0
- data/app/components/phlex_kit/attachment/attachment.css +62 -0
- data/app/components/phlex_kit/attachment/attachment.rb +16 -0
- data/app/components/phlex_kit/attachment/attachment_action.rb +24 -0
- data/app/components/phlex_kit/attachment/attachment_actions.rb +7 -0
- data/app/components/phlex_kit/attachment/attachment_content.rb +7 -0
- data/app/components/phlex_kit/attachment/attachment_description.rb +7 -0
- data/app/components/phlex_kit/attachment/attachment_media.rb +8 -0
- data/app/components/phlex_kit/attachment/attachment_title.rb +7 -0
- data/app/components/phlex_kit/avatar/avatar.css +35 -0
- data/app/components/phlex_kit/avatar/avatar.rb +25 -0
- data/app/components/phlex_kit/avatar/avatar_fallback.rb +13 -0
- data/app/components/phlex_kit/avatar/avatar_group.rb +7 -0
- data/app/components/phlex_kit/avatar/avatar_image.rb +24 -0
- data/app/components/phlex_kit/badge/badge.css +50 -0
- data/app/components/phlex_kit/badge/badge.rb +39 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb.css +18 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb.rb +8 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb_ellipsis.rb +15 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb_item.rb +6 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb_link.rb +9 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb_list.rb +6 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb_page.rb +8 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb_separator.rb +10 -0
- data/app/components/phlex_kit/bubble/bubble.css +32 -0
- data/app/components/phlex_kit/bubble/bubble.rb +17 -0
- data/app/components/phlex_kit/bubble/bubble_content.rb +11 -0
- data/app/components/phlex_kit/bubble/bubble_group.rb +6 -0
- data/app/components/phlex_kit/bubble/bubble_reactions.rb +12 -0
- data/app/components/phlex_kit/button/button.css +72 -0
- data/app/components/phlex_kit/button/button.rb +51 -0
- data/app/components/phlex_kit/button_group/button_group.css +8 -0
- data/app/components/phlex_kit/button_group/button_group.rb +14 -0
- data/app/components/phlex_kit/calendar/calendar.css +109 -0
- data/app/components/phlex_kit/calendar/calendar.rb +47 -0
- data/app/components/phlex_kit/calendar/calendar_body.rb +13 -0
- data/app/components/phlex_kit/calendar/calendar_days.rb +98 -0
- data/app/components/phlex_kit/calendar/calendar_header.rb +13 -0
- data/app/components/phlex_kit/calendar/calendar_next.rb +40 -0
- data/app/components/phlex_kit/calendar/calendar_prev.rb +40 -0
- data/app/components/phlex_kit/calendar/calendar_title.rb +19 -0
- data/app/components/phlex_kit/calendar/calendar_weekdays.rb +27 -0
- data/app/components/phlex_kit/card/card.css +15 -0
- data/app/components/phlex_kit/card/card.rb +29 -0
- data/app/components/phlex_kit/card/card_content.rb +12 -0
- data/app/components/phlex_kit/card/card_description.rb +12 -0
- data/app/components/phlex_kit/card/card_footer.rb +12 -0
- data/app/components/phlex_kit/card/card_header.rb +12 -0
- data/app/components/phlex_kit/card/card_title.rb +12 -0
- data/app/components/phlex_kit/carousel/carousel.css +41 -0
- data/app/components/phlex_kit/carousel/carousel.rb +37 -0
- data/app/components/phlex_kit/carousel/carousel_content.rb +16 -0
- data/app/components/phlex_kit/carousel/carousel_item.rb +17 -0
- data/app/components/phlex_kit/carousel/carousel_next.rb +39 -0
- data/app/components/phlex_kit/carousel/carousel_previous.rb +40 -0
- data/app/components/phlex_kit/chart/chart.css +9 -0
- data/app/components/phlex_kit/chart/chart.rb +31 -0
- data/app/components/phlex_kit/checkbox/checkbox.css +27 -0
- data/app/components/phlex_kit/checkbox/checkbox.rb +26 -0
- data/app/components/phlex_kit/clipboard/clipboard.css +8 -0
- data/app/components/phlex_kit/clipboard/clipboard.rb +19 -0
- data/app/components/phlex_kit/clipboard/clipboard_popover.rb +14 -0
- data/app/components/phlex_kit/clipboard/clipboard_source.rb +6 -0
- data/app/components/phlex_kit/clipboard/clipboard_trigger.rb +6 -0
- data/app/components/phlex_kit/codeblock/codeblock.css +7 -0
- data/app/components/phlex_kit/codeblock/codeblock.rb +23 -0
- data/app/components/phlex_kit/collapsible/collapsible.css +3 -0
- data/app/components/phlex_kit/collapsible/collapsible.rb +13 -0
- data/app/components/phlex_kit/collapsible/collapsible_content.rb +8 -0
- data/app/components/phlex_kit/collapsible/collapsible_trigger.rb +8 -0
- data/app/components/phlex_kit/combobox/combobox.css +310 -0
- data/app/components/phlex_kit/combobox/combobox.rb +33 -0
- data/app/components/phlex_kit/combobox/combobox_badge.rb +15 -0
- data/app/components/phlex_kit/combobox/combobox_badge_trigger.rb +55 -0
- data/app/components/phlex_kit/combobox/combobox_checkbox.rb +21 -0
- data/app/components/phlex_kit/combobox/combobox_clear_button.rb +39 -0
- data/app/components/phlex_kit/combobox/combobox_empty_state.rb +17 -0
- data/app/components/phlex_kit/combobox/combobox_input_trigger.rb +69 -0
- data/app/components/phlex_kit/combobox/combobox_item.rb +19 -0
- data/app/components/phlex_kit/combobox/combobox_item_indicator.rb +27 -0
- data/app/components/phlex_kit/combobox/combobox_list.rb +12 -0
- data/app/components/phlex_kit/combobox/combobox_list_group.rb +14 -0
- data/app/components/phlex_kit/combobox/combobox_popover.rb +27 -0
- data/app/components/phlex_kit/combobox/combobox_radio.rb +26 -0
- data/app/components/phlex_kit/combobox/combobox_search_input.rb +49 -0
- data/app/components/phlex_kit/combobox/combobox_toggle_all_checkbox.rb +21 -0
- data/app/components/phlex_kit/combobox/combobox_trigger.rb +48 -0
- data/app/components/phlex_kit/command/command.css +104 -0
- data/app/components/phlex_kit/command/command.rb +18 -0
- data/app/components/phlex_kit/command/command_dialog.rb +19 -0
- data/app/components/phlex_kit/command/command_dialog_content.rb +37 -0
- data/app/components/phlex_kit/command/command_dialog_trigger.rb +22 -0
- data/app/components/phlex_kit/command/command_empty.rb +17 -0
- data/app/components/phlex_kit/command/command_group.rb +32 -0
- data/app/components/phlex_kit/command/command_input.rb +56 -0
- data/app/components/phlex_kit/command/command_item.rb +22 -0
- data/app/components/phlex_kit/command/command_list.rb +12 -0
- data/app/components/phlex_kit/context_menu/context_menu.css +19 -0
- data/app/components/phlex_kit/context_menu/context_menu.rb +11 -0
- data/app/components/phlex_kit/context_menu/context_menu_content.rb +8 -0
- data/app/components/phlex_kit/context_menu/context_menu_item.rb +25 -0
- data/app/components/phlex_kit/context_menu/context_menu_label.rb +11 -0
- data/app/components/phlex_kit/context_menu/context_menu_separator.rb +8 -0
- data/app/components/phlex_kit/context_menu/context_menu_trigger.rb +8 -0
- data/app/components/phlex_kit/data_table/data_table.css +110 -0
- data/app/components/phlex_kit/data_table/data_table.rb +25 -0
- data/app/components/phlex_kit/data_table/data_table_bulk_actions.rb +15 -0
- data/app/components/phlex_kit/data_table/data_table_column_toggle.rb +61 -0
- data/app/components/phlex_kit/data_table/data_table_expand_toggle.rb +40 -0
- data/app/components/phlex_kit/data_table/data_table_form.rb +36 -0
- data/app/components/phlex_kit/data_table/data_table_kaminari_adapter.rb +17 -0
- data/app/components/phlex_kit/data_table/data_table_manual_adapter.rb +18 -0
- data/app/components/phlex_kit/data_table/data_table_pagination.rb +98 -0
- data/app/components/phlex_kit/data_table/data_table_pagination_bar.rb +13 -0
- data/app/components/phlex_kit/data_table/data_table_pagy_adapter.rb +17 -0
- data/app/components/phlex_kit/data_table/data_table_per_page_select.rb +29 -0
- data/app/components/phlex_kit/data_table/data_table_row_checkbox.rb +24 -0
- data/app/components/phlex_kit/data_table/data_table_search.rb +51 -0
- data/app/components/phlex_kit/data_table/data_table_select_all_checkbox.rb +19 -0
- data/app/components/phlex_kit/data_table/data_table_selection_summary.rb +19 -0
- data/app/components/phlex_kit/data_table/data_table_sort_head.rb +82 -0
- data/app/components/phlex_kit/data_table/data_table_toolbar.rb +13 -0
- data/app/components/phlex_kit/date_picker/date_picker.css +28 -0
- data/app/components/phlex_kit/date_picker/date_picker.rb +71 -0
- data/app/components/phlex_kit/dialog/dialog.css +32 -0
- data/app/components/phlex_kit/dialog/dialog.rb +14 -0
- data/app/components/phlex_kit/dialog/dialog_content.rb +21 -0
- data/app/components/phlex_kit/dialog/dialog_description.rb +6 -0
- data/app/components/phlex_kit/dialog/dialog_footer.rb +6 -0
- data/app/components/phlex_kit/dialog/dialog_header.rb +6 -0
- data/app/components/phlex_kit/dialog/dialog_middle.rb +6 -0
- data/app/components/phlex_kit/dialog/dialog_title.rb +6 -0
- data/app/components/phlex_kit/dialog/dialog_trigger.rb +8 -0
- data/app/components/phlex_kit/drawer/drawer.css +54 -0
- data/app/components/phlex_kit/drawer/drawer.rb +18 -0
- data/app/components/phlex_kit/drawer/drawer_close.rb +9 -0
- data/app/components/phlex_kit/drawer/drawer_content.rb +21 -0
- data/app/components/phlex_kit/drawer/drawer_description.rb +7 -0
- data/app/components/phlex_kit/drawer/drawer_footer.rb +7 -0
- data/app/components/phlex_kit/drawer/drawer_header.rb +7 -0
- data/app/components/phlex_kit/drawer/drawer_title.rb +7 -0
- data/app/components/phlex_kit/drawer/drawer_trigger.rb +9 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu.css +38 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu.rb +22 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu_content.rb +23 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu_item.rb +22 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu_label.rb +12 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu_separator.rb +12 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu_trigger.rb +15 -0
- data/app/components/phlex_kit/empty/empty.css +25 -0
- data/app/components/phlex_kit/empty/empty.rb +6 -0
- data/app/components/phlex_kit/empty/empty_content.rb +6 -0
- data/app/components/phlex_kit/empty/empty_description.rb +6 -0
- data/app/components/phlex_kit/empty/empty_header.rb +6 -0
- data/app/components/phlex_kit/empty/empty_media.rb +14 -0
- data/app/components/phlex_kit/empty/empty_title.rb +6 -0
- data/app/components/phlex_kit/form/form.css +15 -0
- data/app/components/phlex_kit/form/form.rb +27 -0
- data/app/components/phlex_kit/form_field/form_field.css +31 -0
- data/app/components/phlex_kit/form_field/form_field.rb +31 -0
- data/app/components/phlex_kit/form_field/form_field_error.rb +19 -0
- data/app/components/phlex_kit/form_field/form_field_hint.rb +13 -0
- data/app/components/phlex_kit/form_field/form_field_label.rb +13 -0
- data/app/components/phlex_kit/hover_card/hover_card.css +8 -0
- data/app/components/phlex_kit/hover_card/hover_card.rb +10 -0
- data/app/components/phlex_kit/hover_card/hover_card_content.rb +8 -0
- data/app/components/phlex_kit/hover_card/hover_card_trigger.rb +6 -0
- data/app/components/phlex_kit/input/input.css +29 -0
- data/app/components/phlex_kit/input/input.rb +34 -0
- data/app/components/phlex_kit/input_group/input_group.css +35 -0
- data/app/components/phlex_kit/input_group/input_group.rb +15 -0
- data/app/components/phlex_kit/input_group/input_group_addon.rb +16 -0
- data/app/components/phlex_kit/input_group/input_group_text.rb +7 -0
- data/app/components/phlex_kit/input_otp/input_otp.css +32 -0
- data/app/components/phlex_kit/input_otp/input_otp.rb +29 -0
- data/app/components/phlex_kit/input_otp/input_otp_group.rb +7 -0
- data/app/components/phlex_kit/input_otp/input_otp_separator.rb +7 -0
- data/app/components/phlex_kit/input_otp/input_otp_slot.rb +27 -0
- data/app/components/phlex_kit/item/item.css +32 -0
- data/app/components/phlex_kit/item/item.rb +18 -0
- data/app/components/phlex_kit/item/item_actions.rb +7 -0
- data/app/components/phlex_kit/item/item_content.rb +7 -0
- data/app/components/phlex_kit/item/item_description.rb +7 -0
- data/app/components/phlex_kit/item/item_group.rb +7 -0
- data/app/components/phlex_kit/item/item_media.rb +7 -0
- data/app/components/phlex_kit/item/item_title.rb +7 -0
- data/app/components/phlex_kit/kbd/kbd.css +17 -0
- data/app/components/phlex_kit/kbd/kbd.rb +14 -0
- data/app/components/phlex_kit/kbd/kbd_group.rb +12 -0
- data/app/components/phlex_kit/label/label.css +12 -0
- data/app/components/phlex_kit/label/label.rb +14 -0
- data/app/components/phlex_kit/link/link.css +6 -0
- data/app/components/phlex_kit/link/link.rb +47 -0
- data/app/components/phlex_kit/masked_input/masked_input.rb +12 -0
- data/app/components/phlex_kit/menubar/menubar.css +66 -0
- data/app/components/phlex_kit/menubar/menubar.rb +24 -0
- data/app/components/phlex_kit/menubar/menubar_content.rb +9 -0
- data/app/components/phlex_kit/menubar/menubar_item.rb +26 -0
- data/app/components/phlex_kit/menubar/menubar_menu.rb +9 -0
- data/app/components/phlex_kit/menubar/menubar_separator.rb +7 -0
- data/app/components/phlex_kit/menubar/menubar_trigger.rb +14 -0
- data/app/components/phlex_kit/message/message.css +20 -0
- data/app/components/phlex_kit/message/message.rb +14 -0
- data/app/components/phlex_kit/message/message_avatar.rb +6 -0
- data/app/components/phlex_kit/message/message_content.rb +6 -0
- data/app/components/phlex_kit/message/message_footer.rb +6 -0
- data/app/components/phlex_kit/message/message_group.rb +6 -0
- data/app/components/phlex_kit/message/message_header.rb +6 -0
- data/app/components/phlex_kit/message_scroller/message_scroller.css +2 -0
- data/app/components/phlex_kit/message_scroller/message_scroller.rb +11 -0
- data/app/components/phlex_kit/native_select/native_select.css +51 -0
- data/app/components/phlex_kit/native_select/native_select.rb +48 -0
- data/app/components/phlex_kit/native_select/native_select_group.rb +13 -0
- data/app/components/phlex_kit/native_select/native_select_icon.rb +32 -0
- data/app/components/phlex_kit/native_select/native_select_option.rb +14 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu.css +67 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu.rb +23 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu_content.rb +9 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu_item.rb +9 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu_link.rb +13 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu_list.rb +7 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu_trigger.rb +27 -0
- data/app/components/phlex_kit/pagination/pagination.css +5 -0
- data/app/components/phlex_kit/pagination/pagination.rb +10 -0
- data/app/components/phlex_kit/pagination/pagination_content.rb +6 -0
- data/app/components/phlex_kit/pagination/pagination_ellipsis.rb +17 -0
- data/app/components/phlex_kit/pagination/pagination_item.rb +14 -0
- data/app/components/phlex_kit/popover/popover.css +9 -0
- data/app/components/phlex_kit/popover/popover.rb +11 -0
- data/app/components/phlex_kit/popover/popover_content.rb +8 -0
- data/app/components/phlex_kit/popover/popover_trigger.rb +8 -0
- data/app/components/phlex_kit/progress/progress.css +17 -0
- data/app/components/phlex_kit/progress/progress.rb +25 -0
- data/app/components/phlex_kit/radio_button/radio_button.css +9 -0
- data/app/components/phlex_kit/radio_button/radio_button.rb +19 -0
- data/app/components/phlex_kit/radio_group/radio_group.css +3 -0
- data/app/components/phlex_kit/radio_group/radio_group.rb +14 -0
- data/app/components/phlex_kit/resizable/resizable.css +23 -0
- data/app/components/phlex_kit/resizable/resizable_handle.rb +21 -0
- data/app/components/phlex_kit/resizable/resizable_panel.rb +19 -0
- data/app/components/phlex_kit/resizable/resizable_panel_group.rb +26 -0
- data/app/components/phlex_kit/scroll_area/scroll_area.css +21 -0
- data/app/components/phlex_kit/scroll_area/scroll_area.rb +15 -0
- data/app/components/phlex_kit/select/select.css +80 -0
- data/app/components/phlex_kit/select/select.rb +43 -0
- data/app/components/phlex_kit/select/select_content.rb +24 -0
- data/app/components/phlex_kit/select/select_group.rb +13 -0
- data/app/components/phlex_kit/select/select_input.rb +23 -0
- data/app/components/phlex_kit/select/select_item.rb +52 -0
- data/app/components/phlex_kit/select/select_label.rb +13 -0
- data/app/components/phlex_kit/select/select_trigger.rb +42 -0
- data/app/components/phlex_kit/select/select_value.rb +21 -0
- data/app/components/phlex_kit/separator/separator.css +6 -0
- data/app/components/phlex_kit/separator/separator.rb +30 -0
- data/app/components/phlex_kit/sheet/sheet.css +17 -0
- data/app/components/phlex_kit/sheet/sheet.rb +14 -0
- data/app/components/phlex_kit/sheet/sheet_content.rb +25 -0
- data/app/components/phlex_kit/sheet/sheet_description.rb +6 -0
- data/app/components/phlex_kit/sheet/sheet_footer.rb +6 -0
- data/app/components/phlex_kit/sheet/sheet_header.rb +6 -0
- data/app/components/phlex_kit/sheet/sheet_middle.rb +6 -0
- data/app/components/phlex_kit/sheet/sheet_title.rb +6 -0
- data/app/components/phlex_kit/sheet/sheet_trigger.rb +6 -0
- data/app/components/phlex_kit/shortcut_key/shortcut_key.css +17 -0
- data/app/components/phlex_kit/shortcut_key/shortcut_key.rb +9 -0
- data/app/components/phlex_kit/sidebar/sidebar.css +42 -0
- data/app/components/phlex_kit/sidebar/sidebar.rb +19 -0
- data/app/components/phlex_kit/sidebar/sidebar_content.rb +12 -0
- data/app/components/phlex_kit/sidebar/sidebar_footer.rb +12 -0
- data/app/components/phlex_kit/sidebar/sidebar_group.rb +12 -0
- data/app/components/phlex_kit/sidebar/sidebar_header.rb +12 -0
- data/app/components/phlex_kit/sidebar/sidebar_inset.rb +14 -0
- data/app/components/phlex_kit/sidebar/sidebar_menu.rb +12 -0
- data/app/components/phlex_kit/sidebar/sidebar_menu_button.rb +17 -0
- data/app/components/phlex_kit/sidebar/sidebar_menu_item.rb +12 -0
- data/app/components/phlex_kit/sidebar/sidebar_wrapper.rb +13 -0
- data/app/components/phlex_kit/skeleton/skeleton.css +7 -0
- data/app/components/phlex_kit/skeleton/skeleton.rb +9 -0
- data/app/components/phlex_kit/slider/slider.css +52 -0
- data/app/components/phlex_kit/slider/slider.rb +39 -0
- data/app/components/phlex_kit/spinner/spinner.css +5 -0
- data/app/components/phlex_kit/spinner/spinner.rb +27 -0
- data/app/components/phlex_kit/stars/stars.css +4 -0
- data/app/components/phlex_kit/stars/stars.rb +19 -0
- data/app/components/phlex_kit/switch/switch.css +28 -0
- data/app/components/phlex_kit/switch/switch.rb +21 -0
- data/app/components/phlex_kit/table/table.css +24 -0
- data/app/components/phlex_kit/table/table.rb +35 -0
- data/app/components/phlex_kit/table/table_body.rb +12 -0
- data/app/components/phlex_kit/table/table_caption.rb +12 -0
- data/app/components/phlex_kit/table/table_cell.rb +12 -0
- data/app/components/phlex_kit/table/table_footer.rb +12 -0
- data/app/components/phlex_kit/table/table_head.rb +12 -0
- data/app/components/phlex_kit/table/table_header.rb +12 -0
- data/app/components/phlex_kit/table/table_row.rb +12 -0
- data/app/components/phlex_kit/tabs/tabs.css +13 -0
- data/app/components/phlex_kit/tabs/tabs.rb +13 -0
- data/app/components/phlex_kit/tabs/tabs_content.rb +11 -0
- data/app/components/phlex_kit/tabs/tabs_list.rb +6 -0
- data/app/components/phlex_kit/tabs/tabs_trigger.rb +17 -0
- data/app/components/phlex_kit/textarea/textarea.css +27 -0
- data/app/components/phlex_kit/textarea/textarea.rb +24 -0
- data/app/components/phlex_kit/theme_toggle/theme_toggle.rb +15 -0
- data/app/components/phlex_kit/toast/toast.css +163 -0
- data/app/components/phlex_kit/toast/toast.rb +21 -0
- data/app/components/phlex_kit/toast/toast_action.rb +19 -0
- data/app/components/phlex_kit/toast/toast_cancel.rb +18 -0
- data/app/components/phlex_kit/toast/toast_close.rb +35 -0
- data/app/components/phlex_kit/toast/toast_description.rb +13 -0
- data/app/components/phlex_kit/toast/toast_icon.rb +63 -0
- data/app/components/phlex_kit/toast/toast_item.rb +70 -0
- data/app/components/phlex_kit/toast/toast_region.rb +121 -0
- data/app/components/phlex_kit/toast/toast_title.rb +13 -0
- data/app/components/phlex_kit/toggle/toggle.css +16 -0
- data/app/components/phlex_kit/toggle/toggle.rb +59 -0
- data/app/components/phlex_kit/toggle_group/toggle_group.css +10 -0
- data/app/components/phlex_kit/toggle_group/toggle_group.rb +65 -0
- data/app/components/phlex_kit/toggle_group/toggle_group_item.rb +37 -0
- data/app/components/phlex_kit/tooltip/tooltip.css +28 -0
- data/app/components/phlex_kit/tooltip/tooltip.rb +15 -0
- data/app/components/phlex_kit/tooltip/tooltip_content.rb +12 -0
- data/app/components/phlex_kit/tooltip/tooltip_trigger.rb +13 -0
- data/app/components/phlex_kit/typography/blockquote.rb +12 -0
- data/app/components/phlex_kit/typography/heading.rb +38 -0
- data/app/components/phlex_kit/typography/inline_code.rb +13 -0
- data/app/components/phlex_kit/typography/inline_link.rb +15 -0
- data/app/components/phlex_kit/typography/text.rb +48 -0
- data/app/components/phlex_kit/typography/typography.css +50 -0
- data/app/javascript/phlex_kit/controllers/accordion_controller.js +59 -0
- data/app/javascript/phlex_kit/controllers/alert_dialog_controller.js +24 -0
- data/app/javascript/phlex_kit/controllers/avatar_controller.js +30 -0
- data/app/javascript/phlex_kit/controllers/calendar_controller.js +316 -0
- data/app/javascript/phlex_kit/controllers/calendar_input_controller.js +10 -0
- data/app/javascript/phlex_kit/controllers/carousel_controller.js +189 -0
- data/app/javascript/phlex_kit/controllers/chart_controller.js +135 -0
- data/app/javascript/phlex_kit/controllers/clipboard_controller.js +30 -0
- data/app/javascript/phlex_kit/controllers/collapsible_controller.js +14 -0
- data/app/javascript/phlex_kit/controllers/combobox_controller.js +303 -0
- data/app/javascript/phlex_kit/controllers/command_controller.js +161 -0
- data/app/javascript/phlex_kit/controllers/command_dialog_controller.js +37 -0
- data/app/javascript/phlex_kit/controllers/context_menu_controller.js +28 -0
- data/app/javascript/phlex_kit/controllers/data_table_column_visibility_controller.js +18 -0
- data/app/javascript/phlex_kit/controllers/data_table_controller.js +61 -0
- data/app/javascript/phlex_kit/controllers/data_table_search_controller.js +67 -0
- data/app/javascript/phlex_kit/controllers/dialog_controller.js +20 -0
- data/app/javascript/phlex_kit/controllers/dropdown_menu_controller.js +106 -0
- data/app/javascript/phlex_kit/controllers/form_field_controller.js +69 -0
- data/app/javascript/phlex_kit/controllers/hover_card_controller.js +11 -0
- data/app/javascript/phlex_kit/controllers/index.js +87 -0
- data/app/javascript/phlex_kit/controllers/input_otp_controller.js +66 -0
- data/app/javascript/phlex_kit/controllers/masked_input_controller.js +26 -0
- data/app/javascript/phlex_kit/controllers/menubar_controller.js +43 -0
- data/app/javascript/phlex_kit/controllers/message_scroller_controller.js +335 -0
- data/app/javascript/phlex_kit/controllers/popover_controller.js +12 -0
- data/app/javascript/phlex_kit/controllers/resizable_controller.js +42 -0
- data/app/javascript/phlex_kit/controllers/select_controller.js +141 -0
- data/app/javascript/phlex_kit/controllers/select_item_controller.js +14 -0
- data/app/javascript/phlex_kit/controllers/sheet_content_controller.js +6 -0
- data/app/javascript/phlex_kit/controllers/sheet_controller.js +10 -0
- data/app/javascript/phlex_kit/controllers/slider_controller.js +19 -0
- data/app/javascript/phlex_kit/controllers/tabs_controller.js +28 -0
- data/app/javascript/phlex_kit/controllers/theme_toggle_controller.js +22 -0
- data/app/javascript/phlex_kit/controllers/toast_controller.js +153 -0
- data/app/javascript/phlex_kit/controllers/toaster_controller.js +321 -0
- data/app/javascript/phlex_kit/controllers/toggle_controller.js +25 -0
- data/app/javascript/phlex_kit/controllers/toggle_group_controller.js +91 -0
- data/config/importmap.rb +7 -0
- data/lib/generators/phlex_kit/component/component_generator.rb +41 -0
- data/lib/generators/phlex_kit/install/install_generator.rb +51 -0
- data/lib/generators/phlex_kit/install/templates/phlex_kit.rb +11 -0
- data/lib/phlex_kit/base_component.rb +22 -0
- data/lib/phlex_kit/configuration.rb +46 -0
- data/lib/phlex_kit/engine.rb +50 -0
- data/lib/phlex_kit/propshaft_skip_source.rb +22 -0
- data/lib/phlex_kit/version.rb +5 -0
- data/lib/phlex_kit.rb +21 -0
- metadata +545 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# See navigation_menu.rb.
|
|
3
|
+
class NavigationMenuTrigger < BaseComponent
|
|
4
|
+
def initialize(**attrs) = (@attrs = attrs)
|
|
5
|
+
def view_template(&block)
|
|
6
|
+
button(**mix({
|
|
7
|
+
type: :button,
|
|
8
|
+
class: "pk-navigation-menu-trigger",
|
|
9
|
+
aria: { haspopup: "menu", expanded: "false" },
|
|
10
|
+
data: { action: "click->phlex-kit--menubar#toggle mouseenter->phlex-kit--menubar#switch" }
|
|
11
|
+
}, @attrs)) do
|
|
12
|
+
block&.call
|
|
13
|
+
chevron
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def chevron
|
|
20
|
+
svg(xmlns: "http://www.w3.org/2000/svg", viewbox: "0 0 24 24", fill: "none",
|
|
21
|
+
stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round",
|
|
22
|
+
"stroke-linejoin": "round", class: "pk-navigation-menu-chevron", "aria-hidden": "true") do |s|
|
|
23
|
+
s.path(d: "m6 9 6 6 6-6")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/* Co-located with pagination.rb. Items reuse .pk-button. Tokens global. */
|
|
2
|
+
.pk-pagination { margin-inline: auto; display: flex; width: 100%; justify-content: center; }
|
|
3
|
+
.pk-pagination-content { display: flex; flex-direction: row; align-items: center; gap: .25rem; list-style: none; margin: 0; padding: 0; }
|
|
4
|
+
.pk-pagination-ellipsis { display: flex; height: 2.25rem; width: 2.25rem; align-items: center; justify-content: center; }
|
|
5
|
+
.pk-pagination-ellipsis > svg { width: 1rem; height: 1rem; }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Page navigation. Ported from ruby_ui's RubyUI::Pagination. Compose Pagination >
|
|
3
|
+
# PaginationContent > PaginationItem(href:, active:) / PaginationEllipsis.
|
|
4
|
+
class Pagination < BaseComponent
|
|
5
|
+
def initialize(**attrs) = (@attrs = attrs)
|
|
6
|
+
def view_template(&)
|
|
7
|
+
nav(**mix({ class: "pk-pagination", role: "navigation", aria: { label: "pagination" } }, @attrs), &)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
class PaginationEllipsis < BaseComponent
|
|
3
|
+
def initialize(**attrs) = (@attrs = attrs)
|
|
4
|
+
def view_template
|
|
5
|
+
li do
|
|
6
|
+
span(**mix({ class: "pk-pagination-ellipsis", aria: { hidden: true } }, @attrs)) do
|
|
7
|
+
svg(xmlns: "http://www.w3.org/2000/svg", viewbox: "0 0 24 24", fill: "none", stroke: "currentColor", stroke_width: "2", stroke_linecap: "round", stroke_linejoin: "round") do |s|
|
|
8
|
+
s.circle(cx: "12", cy: "12", r: "1")
|
|
9
|
+
s.circle(cx: "19", cy: "12", r: "1")
|
|
10
|
+
s.circle(cx: "5", cy: "12", r: "1")
|
|
11
|
+
end
|
|
12
|
+
span(class: "pk-sr-only") { "More pages" }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
class PaginationItem < BaseComponent
|
|
3
|
+
def initialize(href: "#", active: false, **attrs)
|
|
4
|
+
@href = href
|
|
5
|
+
@active = active
|
|
6
|
+
@attrs = attrs
|
|
7
|
+
end
|
|
8
|
+
def view_template(&block)
|
|
9
|
+
li do
|
|
10
|
+
a(**mix({ href: @href, class: "pk-button #{@active ? "outline" : "ghost"}", aria: { current: (@active ? "page" : nil) } }, @attrs), &block)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* Co-located with popover.rb. CSS-positioned panel. Tokens from the global stylesheet. */
|
|
2
|
+
.pk-popover { position: relative; display: inline-block; }
|
|
3
|
+
.pk-popover-trigger { display: inline-block; }
|
|
4
|
+
.pk-popover-content {
|
|
5
|
+
position: absolute; z-index: 50; top: calc(100% + .5rem); left: 0;
|
|
6
|
+
min-width: 12rem; border: 1px solid var(--pk-border); border-radius: calc(var(--pk-radius) - 2px);
|
|
7
|
+
background: var(--pk-surface); color: var(--pk-text); padding: .75rem;
|
|
8
|
+
box-shadow: 0 8px 24px rgb(0 0 0 / .3); outline: none;
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Click-triggered floating panel, positioned with CSS (no @floating-ui). Ported
|
|
3
|
+
# from ruby_ui's RubyUI::Popover. Compose Popover > (PopoverTrigger +
|
|
4
|
+
# PopoverContent). phlex-kit--popover.
|
|
5
|
+
class Popover < BaseComponent
|
|
6
|
+
def initialize(**attrs) = (@attrs = attrs)
|
|
7
|
+
def view_template(&)
|
|
8
|
+
div(**mix({ class: "pk-popover", data: { controller: "phlex-kit--popover" } }, @attrs), &)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
class PopoverContent < BaseComponent
|
|
3
|
+
def initialize(**attrs) = (@attrs = attrs)
|
|
4
|
+
def view_template(&)
|
|
5
|
+
div(**mix({ class: "pk-popover-content pk-hidden", data: { phlex_kit__popover_target: "content", state: "closed" } }, @attrs), &)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
class PopoverTrigger < BaseComponent
|
|
3
|
+
def initialize(**attrs) = (@attrs = attrs)
|
|
4
|
+
def view_template(&)
|
|
5
|
+
div(**mix({ class: "pk-popover-trigger", data: { phlex_kit__popover_target: "trigger", action: "click->phlex-kit--popover#toggle" } }, @attrs), &)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* Co-located with progress.rb — UI::Progress. ruby_ui's Tailwind (h-2 rounded-full
|
|
2
|
+
bg-primary/20, indicator bg-primary translated by value) as vanilla CSS on the
|
|
3
|
+
palette tokens. Theme tokens come from the global stylesheet. */
|
|
4
|
+
.pk-progress {
|
|
5
|
+
position: relative;
|
|
6
|
+
height: .5rem;
|
|
7
|
+
width: 100%;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
border-radius: 999px;
|
|
10
|
+
background: color-mix(in oklab, var(--pk-brand) 20%, transparent);
|
|
11
|
+
}
|
|
12
|
+
.pk-progress-indicator {
|
|
13
|
+
height: 100%;
|
|
14
|
+
width: 100%;
|
|
15
|
+
background: var(--pk-brand);
|
|
16
|
+
transition: transform .3s ease;
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Progress bar, ported from ruby_ui's RubyUI::Progress. `value:` (0–100,
|
|
3
|
+
# clamped) drives an inner indicator translated into view. Presentational, no
|
|
4
|
+
# JS; width comes from a caller `class:`/`style:`. Tailwind → vanilla
|
|
5
|
+
# `.pk-progress*` (progress.css).
|
|
6
|
+
class Progress < BaseComponent
|
|
7
|
+
def initialize(value: 0, **attrs)
|
|
8
|
+
@value = value.to_f.clamp(0.0, 100.0)
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template
|
|
13
|
+
div(**mix({
|
|
14
|
+
role: "progressbar",
|
|
15
|
+
"aria-valuenow": @value,
|
|
16
|
+
"aria-valuemin": 0,
|
|
17
|
+
"aria-valuemax": 100,
|
|
18
|
+
"aria-valuetext": "#{@value}%",
|
|
19
|
+
class: "pk-progress"
|
|
20
|
+
}, @attrs)) do
|
|
21
|
+
div(class: "pk-progress-indicator", style: "transform: translateX(-#{100 - @value}%)")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Single radio input. Ported from ruby_ui's RubyUI::RadioButton. Registers as
|
|
3
|
+
# a phlex-kit--form-field input target, so it live-validates inside a
|
|
4
|
+
# PhlexKit::FormField (Stimulus ignores the wiring otherwise).
|
|
5
|
+
class RadioButton < BaseComponent
|
|
6
|
+
def initialize(**attrs) = (@attrs = attrs)
|
|
7
|
+
|
|
8
|
+
def view_template
|
|
9
|
+
input(**mix({
|
|
10
|
+
type: "radio",
|
|
11
|
+
class: "pk-radio",
|
|
12
|
+
data: {
|
|
13
|
+
phlex_kit__form_field_target: "input",
|
|
14
|
+
action: "change->phlex-kit--form-field#onInput invalid->phlex-kit--form-field#onInvalid"
|
|
15
|
+
}
|
|
16
|
+
}, @attrs))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Radio list wrapper, ported from shadcn/ui's RadioGroup: a role=radiogroup
|
|
3
|
+
# grid of (RadioButton + Label) rows sharing a `name`. The kit's RadioButton
|
|
4
|
+
# is the item. `.pk-radio-group` (radio_group.css).
|
|
5
|
+
class RadioGroup < BaseComponent
|
|
6
|
+
def initialize(**attrs)
|
|
7
|
+
@attrs = attrs
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template(&)
|
|
11
|
+
div(**mix({ class: "pk-radio-group", role: "radiogroup" }, @attrs), &)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* Co-located with resizable_panel_group.rb — UI::Resizable, shadcn parity
|
|
2
|
+
(react-resizable-panels replaced by the phlex-kit--resizable controller). */
|
|
3
|
+
.pk-resizable-group { display: flex; width: 100%; height: 100%; }
|
|
4
|
+
.pk-resizable-group.vertical { flex-direction: column; }
|
|
5
|
+
.pk-resizable-panel { flex: 1 1 0; min-width: 0; min-height: 0; overflow: hidden; }
|
|
6
|
+
.pk-resizable-handle {
|
|
7
|
+
position: relative;
|
|
8
|
+
flex: none;
|
|
9
|
+
background: var(--pk-border);
|
|
10
|
+
}
|
|
11
|
+
.pk-resizable-group.horizontal > .pk-resizable-handle { width: 1px; cursor: col-resize; }
|
|
12
|
+
.pk-resizable-group.vertical > .pk-resizable-handle { height: 1px; cursor: row-resize; }
|
|
13
|
+
/* fat invisible hit area */
|
|
14
|
+
.pk-resizable-group.horizontal > .pk-resizable-handle::after {
|
|
15
|
+
content: ""; position: absolute; inset: 0 -4px;
|
|
16
|
+
}
|
|
17
|
+
.pk-resizable-group.vertical > .pk-resizable-handle::after {
|
|
18
|
+
content: ""; position: absolute; inset: -4px 0;
|
|
19
|
+
}
|
|
20
|
+
.pk-resizable-handle:focus-visible {
|
|
21
|
+
outline: none;
|
|
22
|
+
box-shadow: 0 0 0 2px color-mix(in oklab, var(--pk-ring) 50%, transparent);
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Drag handle between two ResizablePanels. See resizable_panel_group.rb.
|
|
3
|
+
class ResizableHandle < BaseComponent
|
|
4
|
+
def initialize(**attrs)
|
|
5
|
+
@attrs = attrs
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def view_template
|
|
9
|
+
div(**mix({
|
|
10
|
+
class: "pk-resizable-handle",
|
|
11
|
+
role: "separator",
|
|
12
|
+
tabindex: "0",
|
|
13
|
+
aria: { orientation: "vertical" },
|
|
14
|
+
data: {
|
|
15
|
+
phlex_kit__resizable_target: "handle",
|
|
16
|
+
action: "pointerdown->phlex-kit--resizable#start"
|
|
17
|
+
}
|
|
18
|
+
}, @attrs))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# One pane of a ResizablePanelGroup. `default_size:` is a percentage.
|
|
3
|
+
# See resizable_panel_group.rb.
|
|
4
|
+
class ResizablePanel < BaseComponent
|
|
5
|
+
def initialize(default_size: nil, **attrs)
|
|
6
|
+
@default_size = default_size
|
|
7
|
+
@attrs = attrs
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template(&)
|
|
11
|
+
style = @default_size ? "flex-grow: #{@default_size}" : nil
|
|
12
|
+
div(**mix({
|
|
13
|
+
class: "pk-resizable-panel",
|
|
14
|
+
style: style,
|
|
15
|
+
data: { phlex_kit__resizable_target: "panel" }
|
|
16
|
+
}.compact, @attrs), &)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Resizable split panels, ported from shadcn/ui's Resizable. The
|
|
3
|
+
# react-resizable-panels dependency is replaced by the phlex-kit--resizable
|
|
4
|
+
# controller: dragging a ResizableHandle rebalances the flex-grow of its
|
|
5
|
+
# neighbouring ResizablePanels. Compose ResizablePanelGroup(direction:) >
|
|
6
|
+
# ResizablePanel + ResizableHandle + ResizablePanel…
|
|
7
|
+
# `.pk-resizable*` (resizable.css).
|
|
8
|
+
class ResizablePanelGroup < BaseComponent
|
|
9
|
+
DIRECTIONS = { horizontal: "horizontal", vertical: "vertical" }.freeze
|
|
10
|
+
|
|
11
|
+
def initialize(direction: :horizontal, **attrs)
|
|
12
|
+
@direction = DIRECTIONS.fetch(direction.to_sym)
|
|
13
|
+
@attrs = attrs
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def view_template(&)
|
|
17
|
+
div(**mix({
|
|
18
|
+
class: "pk-resizable-group #{@direction}",
|
|
19
|
+
data: {
|
|
20
|
+
controller: "phlex-kit--resizable",
|
|
21
|
+
phlex_kit__resizable_direction_value: @direction
|
|
22
|
+
}
|
|
23
|
+
}, @attrs), &)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* Co-located with scroll_area.rb — UI::ScrollArea: native scrolling with
|
|
2
|
+
shadcn-look thin themed scrollbars (no Radix/JS). */
|
|
3
|
+
.pk-scroll-area {
|
|
4
|
+
position: relative;
|
|
5
|
+
overflow: auto;
|
|
6
|
+
border-radius: inherit;
|
|
7
|
+
scrollbar-width: thin;
|
|
8
|
+
scrollbar-color: var(--pk-border) transparent;
|
|
9
|
+
}
|
|
10
|
+
.pk-scroll-area:focus-visible {
|
|
11
|
+
outline: none;
|
|
12
|
+
box-shadow: 0 0 0 3px color-mix(in oklab, var(--pk-ring) 50%, transparent);
|
|
13
|
+
}
|
|
14
|
+
.pk-scroll-area::-webkit-scrollbar { width: .625rem; height: .625rem; }
|
|
15
|
+
.pk-scroll-area::-webkit-scrollbar-thumb {
|
|
16
|
+
background: var(--pk-border);
|
|
17
|
+
border-radius: 9999px;
|
|
18
|
+
border: 3px solid transparent;
|
|
19
|
+
background-clip: content-box;
|
|
20
|
+
}
|
|
21
|
+
.pk-scroll-area::-webkit-scrollbar-track { background: transparent; }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Styled scroll container, ported from shadcn/ui's ScrollArea. Radix's custom
|
|
3
|
+
# scrollbars are replaced with native thin scrollbars themed via CSS — no JS.
|
|
4
|
+
# Constrain it with a height/width from the caller. `.pk-scroll-area`
|
|
5
|
+
# (scroll_area.css).
|
|
6
|
+
class ScrollArea < BaseComponent
|
|
7
|
+
def initialize(**attrs)
|
|
8
|
+
@attrs = attrs
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def view_template(&)
|
|
12
|
+
div(**mix({ class: "pk-scroll-area", tabindex: "0" }, @attrs), &)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Co-located with select.rb — UI::Select (the custom JS dropdown; NativeSelect
|
|
2
|
+
is the native one). ruby_ui's structure + Stimulus kept; Tailwind replaced with
|
|
3
|
+
our vanilla CSS on the palette tokens. Geometry from ruby_ui (h-9 trigger,
|
|
4
|
+
rounded-md, p-1 viewport, px-2 py-1.5 items, accent on hover/selected). The
|
|
5
|
+
panel is positioned with plain CSS (top:100%) since we dropped @floating-ui.
|
|
6
|
+
Theme tokens come from the global stylesheet. */
|
|
7
|
+
.pk-select { position: relative; width: 100%; }
|
|
8
|
+
|
|
9
|
+
/* Hidden input that carries the form value. */
|
|
10
|
+
.pk-select-input { display: none; }
|
|
11
|
+
|
|
12
|
+
/* Closed-state trigger button (mirrors .pk-input geometry). */
|
|
13
|
+
.pk-select-trigger {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 2rem;
|
|
19
|
+
white-space: nowrap;
|
|
20
|
+
border-radius: var(--pk-radius);
|
|
21
|
+
border: 1px solid var(--pk-input);
|
|
22
|
+
background: transparent;
|
|
23
|
+
color: var(--pk-text);
|
|
24
|
+
padding: .25rem .75rem;
|
|
25
|
+
font: inherit;
|
|
26
|
+
font-size: .875rem;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
transition: border-color .15s ease, box-shadow .15s ease;
|
|
29
|
+
}
|
|
30
|
+
.pk-select-trigger:focus-visible {
|
|
31
|
+
outline: none;
|
|
32
|
+
border-color: var(--pk-brand);
|
|
33
|
+
box-shadow: 0 0 0 3px color-mix(in oklab, var(--pk-ring) 50%, transparent);
|
|
34
|
+
}
|
|
35
|
+
.pk-select-trigger:disabled { cursor: not-allowed; opacity: .5; }
|
|
36
|
+
.pk-select-trigger-icon { flex: none; width: 1rem; height: 1rem; margin-left: .5rem; opacity: .5; }
|
|
37
|
+
.pk-select-value { overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
|
|
38
|
+
|
|
39
|
+
/* Dropdown panel — opens directly below the trigger (no floating-ui). */
|
|
40
|
+
.pk-select-content {
|
|
41
|
+
position: absolute;
|
|
42
|
+
top: 100%;
|
|
43
|
+
left: 0;
|
|
44
|
+
z-index: 50;
|
|
45
|
+
width: 100%;
|
|
46
|
+
margin-top: .25rem;
|
|
47
|
+
}
|
|
48
|
+
.pk-select-content.hidden { display: none; }
|
|
49
|
+
.pk-select-viewport {
|
|
50
|
+
max-height: 24rem;
|
|
51
|
+
overflow: auto;
|
|
52
|
+
border-radius: calc(var(--pk-radius) - 2px);
|
|
53
|
+
border: 1px solid var(--pk-border);
|
|
54
|
+
background: var(--pk-surface);
|
|
55
|
+
color: var(--pk-text);
|
|
56
|
+
padding: .25rem;
|
|
57
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, .4);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.pk-select-label { margin: 0; padding: .375rem .5rem; font-size: .875rem; font-weight: 600; }
|
|
61
|
+
|
|
62
|
+
.pk-select-item {
|
|
63
|
+
position: relative;
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
user-select: none;
|
|
68
|
+
border-radius: calc(var(--pk-radius) - 4px);
|
|
69
|
+
padding: .375rem .5rem;
|
|
70
|
+
font-size: .875rem;
|
|
71
|
+
color: var(--pk-text);
|
|
72
|
+
outline: none;
|
|
73
|
+
transition: background-color .12s ease, color .12s ease;
|
|
74
|
+
}
|
|
75
|
+
.pk-select-item:hover,
|
|
76
|
+
.pk-select-item:focus,
|
|
77
|
+
.pk-select-item[aria-current="true"],
|
|
78
|
+
.pk-select-item[aria-selected="true"] { background: var(--pk-accent); }
|
|
79
|
+
.pk-select-item-check { visibility: hidden; flex: none; width: 1rem; height: 1rem; margin-right: .5rem; }
|
|
80
|
+
.pk-select-item[aria-selected="true"] .pk-select-item-check { visibility: visible; }
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Custom dropdown select, ported from ruby_ui's RubyUI::Select — the styled
|
|
3
|
+
# popover (Image #2), NOT the native <select> (that's PhlexKit::NativeSelect). Unlike
|
|
4
|
+
# the rest of the kit this component IS JS-driven: it keeps ruby_ui's Stimulus
|
|
5
|
+
# wiring (`phlex-kit--select` / `phlex-kit--select-item`, in
|
|
6
|
+
# app/javascript/controllers/ruby_ui/), since the open/close, selection, and
|
|
7
|
+
# keyboard nav are the point. The one change from upstream: the controller drops
|
|
8
|
+
# the `@floating-ui/dom` dependency and positions the panel with plain CSS
|
|
9
|
+
# (opens directly below the trigger). Tailwind → vanilla `.pk-select-*` (select.css).
|
|
10
|
+
#
|
|
11
|
+
# Multi-part. The hidden SelectInput carries the form value/name; SelectTrigger +
|
|
12
|
+
# SelectValue are the closed-state button; SelectContent > SelectGroup >
|
|
13
|
+
# (SelectLabel +) SelectItem are the panel:
|
|
14
|
+
#
|
|
15
|
+
# render PhlexKit::Select.new do
|
|
16
|
+
# render PhlexKit::SelectInput.new(name: "user[role]", id: "user_role", value: @user.role)
|
|
17
|
+
# render PhlexKit::SelectTrigger.new do
|
|
18
|
+
# render PhlexKit::SelectValue.new(placeholder: "Select a role") { @user.role&.capitalize }
|
|
19
|
+
# end
|
|
20
|
+
# render PhlexKit::SelectContent.new do
|
|
21
|
+
# render PhlexKit::SelectGroup.new do
|
|
22
|
+
# render PhlexKit::SelectItem.new(value: "admin", "aria-selected": "true") { "Admin" }
|
|
23
|
+
# end
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
class Select < BaseComponent
|
|
27
|
+
def initialize(**attrs)
|
|
28
|
+
@attrs = attrs
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def view_template(&block)
|
|
32
|
+
div(**mix({
|
|
33
|
+
class: "pk-select",
|
|
34
|
+
data: {
|
|
35
|
+
controller: "phlex-kit--select",
|
|
36
|
+
phlex_kit__select_open_value: "false",
|
|
37
|
+
action: "click@window->phlex-kit--select#clickOutside",
|
|
38
|
+
phlex_kit__select_phlex_kit__select_item_outlet: ".pk-select-item"
|
|
39
|
+
}
|
|
40
|
+
}, @attrs), &block)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# The dropdown panel for PhlexKit::Select — hidden until the trigger opens it (the
|
|
3
|
+
# controller toggles the `hidden` class). Outer div is the positioned/targeted
|
|
4
|
+
# layer; the inner `.pk-select-viewport` is the bordered, scrollable box.
|
|
5
|
+
# Holds SelectGroup / SelectLabel / SelectItem children. See select.rb.
|
|
6
|
+
class SelectContent < BaseComponent
|
|
7
|
+
def initialize(**attrs)
|
|
8
|
+
@id = "pk-select-content-#{SecureRandom.hex(4)}"
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template(&block)
|
|
13
|
+
div(**mix({
|
|
14
|
+
id: @id,
|
|
15
|
+
role: "listbox",
|
|
16
|
+
tabindex: "-1",
|
|
17
|
+
class: "pk-select-content hidden",
|
|
18
|
+
data: { phlex_kit__select_target: "content" }
|
|
19
|
+
}, @attrs)) do
|
|
20
|
+
div(class: "pk-select-viewport", &block)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# Groups a set of SelectItems (optionally under a SelectLabel) inside a
|
|
3
|
+
# PhlexKit::SelectContent. Plain pass-through wrapper. See select.rb.
|
|
4
|
+
class SelectGroup < BaseComponent
|
|
5
|
+
def initialize(**attrs)
|
|
6
|
+
@attrs = attrs
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def view_template(&block)
|
|
10
|
+
div(**mix({ class: "pk-select-group" }, @attrs), &block)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# The hidden input that actually carries PhlexKit::Select's value into the form — the
|
|
3
|
+
# Stimulus controller writes the chosen item's value here and dispatches a
|
|
4
|
+
# `change` (which also feeds phlex-kit--form-field validation when the select
|
|
5
|
+
# sits inside a PhlexKit::FormField). Pass `name:`/`id:`/`value:` like any
|
|
6
|
+
# input; it's display:none. See select.rb.
|
|
7
|
+
class SelectInput < BaseComponent
|
|
8
|
+
def initialize(**attrs)
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template
|
|
13
|
+
input(**mix({
|
|
14
|
+
class: "pk-select-input",
|
|
15
|
+
data: {
|
|
16
|
+
phlex_kit__select_target: "input",
|
|
17
|
+
phlex_kit__form_field_target: "input",
|
|
18
|
+
action: "change->phlex-kit--form-field#onChange invalid->phlex-kit--form-field#onInvalid"
|
|
19
|
+
}
|
|
20
|
+
}, @attrs))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# A selectable row in a PhlexKit::Select panel. Carries its `value:` in data-value; on
|
|
3
|
+
# click/enter the controller copies it into the hidden SelectInput, updates the
|
|
4
|
+
# SelectValue text, and flips `aria-selected` (which reveals the checkmark).
|
|
5
|
+
# Pass `selected: true` to mark the initially-chosen item server-side — it's a
|
|
6
|
+
# named kwarg (not an `"aria-selected":` attr) because `mix` would *merge* a
|
|
7
|
+
# repeated attribute rather than override it.
|
|
8
|
+
# See select.rb.
|
|
9
|
+
class SelectItem < BaseComponent
|
|
10
|
+
def initialize(value: nil, selected: false, **attrs)
|
|
11
|
+
@value = value
|
|
12
|
+
@selected = selected
|
|
13
|
+
@attrs = attrs
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def view_template(&block)
|
|
17
|
+
div(**mix({
|
|
18
|
+
role: "option",
|
|
19
|
+
tabindex: "0",
|
|
20
|
+
class: "pk-select-item",
|
|
21
|
+
"aria-selected": (@selected ? "true" : "false"),
|
|
22
|
+
data: {
|
|
23
|
+
value: @value,
|
|
24
|
+
controller: "phlex-kit--select-item",
|
|
25
|
+
action: "click->phlex-kit--select#selectItem keydown.enter->phlex-kit--select#selectItem " \
|
|
26
|
+
"keydown.down->phlex-kit--select#handleKeyDown keydown.up->phlex-kit--select#handleKeyUp " \
|
|
27
|
+
"keydown.esc->phlex-kit--select#handleEsc",
|
|
28
|
+
phlex_kit__select_target: "item"
|
|
29
|
+
}
|
|
30
|
+
}, @attrs)) do
|
|
31
|
+
check_icon
|
|
32
|
+
block&.call
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def check_icon
|
|
39
|
+
svg(
|
|
40
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
41
|
+
viewbox: "0 0 24 24",
|
|
42
|
+
fill: "none",
|
|
43
|
+
stroke: "currentColor",
|
|
44
|
+
"stroke-width": "2",
|
|
45
|
+
"stroke-linecap": "round",
|
|
46
|
+
"stroke-linejoin": "round",
|
|
47
|
+
class: "pk-select-item-check",
|
|
48
|
+
"aria-hidden": "true"
|
|
49
|
+
) { |s| s.path(d: "M20 6 9 17l-5-5") }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# A heading labelling a SelectGroup inside PhlexKit::SelectContent (e.g. "Fruits").
|
|
3
|
+
# See select.rb.
|
|
4
|
+
class SelectLabel < BaseComponent
|
|
5
|
+
def initialize(**attrs)
|
|
6
|
+
@attrs = attrs
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def view_template(&block)
|
|
10
|
+
h3(**mix({ class: "pk-select-label" }, @attrs), &block)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module PhlexKit
|
|
2
|
+
# The closed-state button for PhlexKit::Select — shows the current SelectValue and a
|
|
3
|
+
# up/down chevron, and opens the panel on click (`phlex-kit--select#onClick`).
|
|
4
|
+
# See select.rb.
|
|
5
|
+
class SelectTrigger < BaseComponent
|
|
6
|
+
def initialize(**attrs)
|
|
7
|
+
@attrs = attrs
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template(&block)
|
|
11
|
+
button(**mix({
|
|
12
|
+
type: :button,
|
|
13
|
+
role: "combobox",
|
|
14
|
+
class: "pk-select-trigger",
|
|
15
|
+
aria: { expanded: "false", haspopup: "listbox", autocomplete: "none" },
|
|
16
|
+
data: { action: "phlex-kit--select#onClick", phlex_kit__select_target: "trigger" }
|
|
17
|
+
}, @attrs)) do
|
|
18
|
+
block&.call
|
|
19
|
+
icon
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def icon
|
|
26
|
+
svg(
|
|
27
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
28
|
+
viewbox: "0 0 24 24",
|
|
29
|
+
fill: "none",
|
|
30
|
+
stroke: "currentColor",
|
|
31
|
+
"stroke-width": "2",
|
|
32
|
+
"stroke-linecap": "round",
|
|
33
|
+
"stroke-linejoin": "round",
|
|
34
|
+
class: "pk-select-trigger-icon",
|
|
35
|
+
"aria-hidden": "true"
|
|
36
|
+
) do |s|
|
|
37
|
+
s.path(d: "m7 15 5 5 5-5")
|
|
38
|
+
s.path(d: "m7 9 5-5 5 5")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|