poetry-ui 0.0.2
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/.gitattributes +6 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +87 -0
- data/THIRD_PARTY_NOTICES.md +201 -0
- data/app/components/poetry/ui/accordion/component.html.erb +3 -0
- data/app/components/poetry/ui/accordion/component.rb +197 -0
- data/app/components/poetry/ui/accordion/preview.rb +39 -0
- data/app/components/poetry/ui/accordion/style.rb +37 -0
- data/app/components/poetry/ui/alert/component.html.erb +6 -0
- data/app/components/poetry/ui/alert/component.rb +61 -0
- data/app/components/poetry/ui/alert/preview.rb +35 -0
- data/app/components/poetry/ui/alert/style.rb +24 -0
- data/app/components/poetry/ui/alert_dialog/component.html.erb +17 -0
- data/app/components/poetry/ui/alert_dialog/component.rb +208 -0
- data/app/components/poetry/ui/alert_dialog/preview.rb +48 -0
- data/app/components/poetry/ui/alert_dialog/style.rb +46 -0
- data/app/components/poetry/ui/aspect_ratio/component.rb +63 -0
- data/app/components/poetry/ui/aspect_ratio/preview.rb +29 -0
- data/app/components/poetry/ui/aspect_ratio/style.rb +13 -0
- data/app/components/poetry/ui/attachment/component.html.erb +13 -0
- data/app/components/poetry/ui/attachment/component.rb +139 -0
- data/app/components/poetry/ui/attachment/preview.rb +83 -0
- data/app/components/poetry/ui/attachment/style.rb +59 -0
- data/app/components/poetry/ui/autocomplete/component.html.erb +16 -0
- data/app/components/poetry/ui/autocomplete/component.rb +193 -0
- data/app/components/poetry/ui/autocomplete/preview.rb +39 -0
- data/app/components/poetry/ui/autocomplete/style.rb +18 -0
- data/app/components/poetry/ui/avatar/component.rb +103 -0
- data/app/components/poetry/ui/avatar/group_preview.html.erb +11 -0
- data/app/components/poetry/ui/avatar/preview.rb +50 -0
- data/app/components/poetry/ui/avatar/style.rb +34 -0
- data/app/components/poetry/ui/badge/component.rb +73 -0
- data/app/components/poetry/ui/badge/preview.rb +54 -0
- data/app/components/poetry/ui/badge/style.rb +35 -0
- data/app/components/poetry/ui/breadcrumb/component.html.erb +32 -0
- data/app/components/poetry/ui/breadcrumb/component.rb +102 -0
- data/app/components/poetry/ui/breadcrumb/dropdown_crumb_preview.html.erb +21 -0
- data/app/components/poetry/ui/breadcrumb/preview.rb +45 -0
- data/app/components/poetry/ui/breadcrumb/style.rb +25 -0
- data/app/components/poetry/ui/bubble/component.html.erb +4 -0
- data/app/components/poetry/ui/bubble/component.rb +106 -0
- data/app/components/poetry/ui/bubble/preview.rb +62 -0
- data/app/components/poetry/ui/bubble/style.rb +47 -0
- data/app/components/poetry/ui/button/component.html.erb +14 -0
- data/app/components/poetry/ui/button/component.rb +168 -0
- data/app/components/poetry/ui/button/preview.rb +94 -0
- data/app/components/poetry/ui/button/style.rb +41 -0
- data/app/components/poetry/ui/button_group/component.rb +70 -0
- data/app/components/poetry/ui/button_group/popup_triggers_preview.html.erb +21 -0
- data/app/components/poetry/ui/button_group/preview.rb +46 -0
- data/app/components/poetry/ui/button_group/style.rb +27 -0
- data/app/components/poetry/ui/button_group/text_prefix_preview.html.erb +7 -0
- data/app/components/poetry/ui/calendar/component.html.erb +72 -0
- data/app/components/poetry/ui/calendar/component.rb +366 -0
- data/app/components/poetry/ui/calendar/preview.rb +55 -0
- data/app/components/poetry/ui/calendar/style.rb +55 -0
- data/app/components/poetry/ui/card/component.html.erb +11 -0
- data/app/components/poetry/ui/card/component.rb +90 -0
- data/app/components/poetry/ui/card/preview.rb +29 -0
- data/app/components/poetry/ui/card/style.rb +23 -0
- data/app/components/poetry/ui/carousel/component.html.erb +17 -0
- data/app/components/poetry/ui/carousel/component.rb +179 -0
- data/app/components/poetry/ui/carousel/preview.rb +67 -0
- data/app/components/poetry/ui/carousel/style.rb +39 -0
- data/app/components/poetry/ui/checkbox/component.html.erb +22 -0
- data/app/components/poetry/ui/checkbox/component.rb +179 -0
- data/app/components/poetry/ui/checkbox/preview.rb +68 -0
- data/app/components/poetry/ui/checkbox/style.rb +28 -0
- data/app/components/poetry/ui/clipboard_text/component.html.erb +15 -0
- data/app/components/poetry/ui/clipboard_text/component.rb +154 -0
- data/app/components/poetry/ui/clipboard_text/preview.rb +24 -0
- data/app/components/poetry/ui/clipboard_text/style.rb +23 -0
- data/app/components/poetry/ui/code_block/component.html.erb +13 -0
- data/app/components/poetry/ui/code_block/component.rb +141 -0
- data/app/components/poetry/ui/code_block/preview.rb +40 -0
- data/app/components/poetry/ui/code_block/style.rb +38 -0
- data/app/components/poetry/ui/collapsible/component.html.erb +4 -0
- data/app/components/poetry/ui/collapsible/component.rb +134 -0
- data/app/components/poetry/ui/collapsible/preview.rb +24 -0
- data/app/components/poetry/ui/combobox/component.html.erb +49 -0
- data/app/components/poetry/ui/combobox/component.rb +1086 -0
- data/app/components/poetry/ui/combobox/preview.rb +164 -0
- data/app/components/poetry/ui/combobox/style.rb +148 -0
- data/app/components/poetry/ui/command/component.html.erb +20 -0
- data/app/components/poetry/ui/command/component.rb +526 -0
- data/app/components/poetry/ui/command/dialog_component.html.erb +14 -0
- data/app/components/poetry/ui/command/dialog_component.rb +206 -0
- data/app/components/poetry/ui/command/dialog_preview.rb +39 -0
- data/app/components/poetry/ui/command/preview.rb +121 -0
- data/app/components/poetry/ui/command/style.rb +78 -0
- data/app/components/poetry/ui/composable_trigger.rb +63 -0
- data/app/components/poetry/ui/context_menu/component.html.erb +6 -0
- data/app/components/poetry/ui/context_menu/component.rb +358 -0
- data/app/components/poetry/ui/context_menu/preview.rb +111 -0
- data/app/components/poetry/ui/context_menu/style.rb +59 -0
- data/app/components/poetry/ui/data_table/component.html.erb +78 -0
- data/app/components/poetry/ui/data_table/component.rb +277 -0
- data/app/components/poetry/ui/data_table/preview.rb +68 -0
- data/app/components/poetry/ui/data_table/state.rb +115 -0
- data/app/components/poetry/ui/data_table/style.rb +42 -0
- data/app/components/poetry/ui/date_field/component.html.erb +7 -0
- data/app/components/poetry/ui/date_field/component.rb +209 -0
- data/app/components/poetry/ui/date_field/preview.rb +42 -0
- data/app/components/poetry/ui/date_field/style.rb +35 -0
- data/app/components/poetry/ui/date_picker/component.html.erb +23 -0
- data/app/components/poetry/ui/date_picker/component.rb +242 -0
- data/app/components/poetry/ui/date_picker/preview.rb +31 -0
- data/app/components/poetry/ui/date_picker/style.rb +25 -0
- data/app/components/poetry/ui/deferred/component.html.erb +16 -0
- data/app/components/poetry/ui/deferred/component.rb +90 -0
- data/app/components/poetry/ui/deferred/preview.rb +24 -0
- data/app/components/poetry/ui/dialog/component.html.erb +21 -0
- data/app/components/poetry/ui/dialog/component.rb +194 -0
- data/app/components/poetry/ui/dialog/preview.rb +33 -0
- data/app/components/poetry/ui/dialog/style.rb +30 -0
- data/app/components/poetry/ui/drawer/component.html.erb +16 -0
- data/app/components/poetry/ui/drawer/component.rb +207 -0
- data/app/components/poetry/ui/drawer/preview.rb +69 -0
- data/app/components/poetry/ui/drawer/style.rb +105 -0
- data/app/components/poetry/ui/dropdown_menu/component.html.erb +6 -0
- data/app/components/poetry/ui/dropdown_menu/component.rb +350 -0
- data/app/components/poetry/ui/dropdown_menu/preview.rb +101 -0
- data/app/components/poetry/ui/dropdown_menu/style.rb +60 -0
- data/app/components/poetry/ui/empty/component.html.erb +10 -0
- data/app/components/poetry/ui/empty/component.rb +79 -0
- data/app/components/poetry/ui/empty/preview.rb +27 -0
- data/app/components/poetry/ui/empty/style.rb +27 -0
- data/app/components/poetry/ui/family_identity.rb +52 -0
- data/app/components/poetry/ui/field/component.html.erb +19 -0
- data/app/components/poetry/ui/field/component.rb +183 -0
- data/app/components/poetry/ui/field/preview.html.erb +30 -0
- data/app/components/poetry/ui/field/preview.rb +72 -0
- data/app/components/poetry/ui/field/style.rb +68 -0
- data/app/components/poetry/ui/field_group/component.rb +61 -0
- data/app/components/poetry/ui/field_group/preview.html.erb +30 -0
- data/app/components/poetry/ui/field_group/preview.rb +20 -0
- data/app/components/poetry/ui/field_group/style.rb +25 -0
- data/app/components/poetry/ui/field_separator/component.rb +70 -0
- data/app/components/poetry/ui/field_separator/preview.rb +18 -0
- data/app/components/poetry/ui/field_separator/style.rb +20 -0
- data/app/components/poetry/ui/fieldset/component.rb +90 -0
- data/app/components/poetry/ui/fieldset/preview.html.erb +22 -0
- data/app/components/poetry/ui/fieldset/preview.rb +25 -0
- data/app/components/poetry/ui/fieldset/style.rb +18 -0
- data/app/components/poetry/ui/file_input/component.html.erb +14 -0
- data/app/components/poetry/ui/file_input/component.rb +188 -0
- data/app/components/poetry/ui/file_input/preview.rb +30 -0
- data/app/components/poetry/ui/file_input/style.rb +35 -0
- data/app/components/poetry/ui/hover_card/component.html.erb +6 -0
- data/app/components/poetry/ui/hover_card/component.rb +201 -0
- data/app/components/poetry/ui/hover_card/preview.rb +60 -0
- data/app/components/poetry/ui/hover_card/style.rb +17 -0
- data/app/components/poetry/ui/icon/component.rb +127 -0
- data/app/components/poetry/ui/icon/preview.rb +21 -0
- data/app/components/poetry/ui/input/component.rb +80 -0
- data/app/components/poetry/ui/input/preview.rb +35 -0
- data/app/components/poetry/ui/input/style.rb +18 -0
- data/app/components/poetry/ui/input_group/button_preview.html.erb +12 -0
- data/app/components/poetry/ui/input_group/component.rb +69 -0
- data/app/components/poetry/ui/input_group/preview.rb +23 -0
- data/app/components/poetry/ui/input_group/search_preview.html.erb +13 -0
- data/app/components/poetry/ui/input_group/style.rb +40 -0
- data/app/components/poetry/ui/input_group/textarea_preview.html.erb +10 -0
- data/app/components/poetry/ui/input_group_field.rb +61 -0
- data/app/components/poetry/ui/input_otp/component.html.erb +25 -0
- data/app/components/poetry/ui/input_otp/component.rb +250 -0
- data/app/components/poetry/ui/input_otp/preview.rb +91 -0
- data/app/components/poetry/ui/input_otp/style.rb +36 -0
- data/app/components/poetry/ui/item/component.html.erb +13 -0
- data/app/components/poetry/ui/item/component.rb +99 -0
- data/app/components/poetry/ui/item/group_preview.html.erb +15 -0
- data/app/components/poetry/ui/item/preview.rb +52 -0
- data/app/components/poetry/ui/item/style.rb +45 -0
- data/app/components/poetry/ui/kbd/component.rb +47 -0
- data/app/components/poetry/ui/kbd/group_preview.html.erb +4 -0
- data/app/components/poetry/ui/kbd/preview.rb +23 -0
- data/app/components/poetry/ui/kbd/style.rb +13 -0
- data/app/components/poetry/ui/label/component.rb +46 -0
- data/app/components/poetry/ui/label/preview.html.erb +5 -0
- data/app/components/poetry/ui/label/preview.rb +16 -0
- data/app/components/poetry/ui/label/style.rb +13 -0
- data/app/components/poetry/ui/link/component.rb +62 -0
- data/app/components/poetry/ui/link/preview.rb +31 -0
- data/app/components/poetry/ui/link/style.rb +20 -0
- data/app/components/poetry/ui/marker/component.html.erb +4 -0
- data/app/components/poetry/ui/marker/component.rb +81 -0
- data/app/components/poetry/ui/marker/preview.rb +43 -0
- data/app/components/poetry/ui/marker/style.rb +24 -0
- data/app/components/poetry/ui/menubar/component.html.erb +3 -0
- data/app/components/poetry/ui/menubar/component.rb +493 -0
- data/app/components/poetry/ui/menubar/preview.rb +164 -0
- data/app/components/poetry/ui/menubar/style.rb +71 -0
- data/app/components/poetry/ui/menus.rb +386 -0
- data/app/components/poetry/ui/message/component.html.erb +8 -0
- data/app/components/poetry/ui/message/component.rb +64 -0
- data/app/components/poetry/ui/message/preview.rb +33 -0
- data/app/components/poetry/ui/message/style.rb +29 -0
- data/app/components/poetry/ui/message_scroller/component.html.erb +15 -0
- data/app/components/poetry/ui/message_scroller/component.rb +163 -0
- data/app/components/poetry/ui/message_scroller/preview.rb +33 -0
- data/app/components/poetry/ui/message_scroller/style.rb +39 -0
- data/app/components/poetry/ui/metadata_list/component.rb +88 -0
- data/app/components/poetry/ui/metadata_list/preview.rb +55 -0
- data/app/components/poetry/ui/metadata_list/style.rb +35 -0
- data/app/components/poetry/ui/meter/component.rb +117 -0
- data/app/components/poetry/ui/meter/preview.rb +28 -0
- data/app/components/poetry/ui/meter/style.rb +16 -0
- data/app/components/poetry/ui/native_select/component.rb +124 -0
- data/app/components/poetry/ui/native_select/labelled_preview.html.erb +7 -0
- data/app/components/poetry/ui/native_select/preview.rb +20 -0
- data/app/components/poetry/ui/native_select/style.rb +22 -0
- data/app/components/poetry/ui/navigation_menu/bar_preview.html.erb +14 -0
- data/app/components/poetry/ui/navigation_menu/component.html.erb +25 -0
- data/app/components/poetry/ui/navigation_menu/component.rb +254 -0
- data/app/components/poetry/ui/navigation_menu/preview.rb +20 -0
- data/app/components/poetry/ui/navigation_menu/style.rb +73 -0
- data/app/components/poetry/ui/navigation_menu/viewport_preview.html.erb +23 -0
- data/app/components/poetry/ui/number_field/component.html.erb +19 -0
- data/app/components/poetry/ui/number_field/component.rb +263 -0
- data/app/components/poetry/ui/number_field/preview.rb +66 -0
- data/app/components/poetry/ui/number_field/style.rb +14 -0
- data/app/components/poetry/ui/pagination/component.html.erb +40 -0
- data/app/components/poetry/ui/pagination/component.rb +182 -0
- data/app/components/poetry/ui/pagination/preview.rb +47 -0
- data/app/components/poetry/ui/pagination/style.rb +27 -0
- data/app/components/poetry/ui/popover/component.html.erb +17 -0
- data/app/components/poetry/ui/popover/component.rb +203 -0
- data/app/components/poetry/ui/popover/preview.html.erb +29 -0
- data/app/components/poetry/ui/popover/preview.rb +66 -0
- data/app/components/poetry/ui/popover/style.rb +26 -0
- data/app/components/poetry/ui/popper_consumer.rb +69 -0
- data/app/components/poetry/ui/progress/component.rb +95 -0
- data/app/components/poetry/ui/progress/preview.rb +22 -0
- data/app/components/poetry/ui/progress/style.rb +19 -0
- data/app/components/poetry/ui/questionnaire/component.html.erb +80 -0
- data/app/components/poetry/ui/questionnaire/component.rb +396 -0
- data/app/components/poetry/ui/questionnaire/preview.rb +99 -0
- data/app/components/poetry/ui/questionnaire/style.rb +53 -0
- data/app/components/poetry/ui/radio_group/component.html.erb +4 -0
- data/app/components/poetry/ui/radio_group/component.rb +323 -0
- data/app/components/poetry/ui/radio_group/preview.rb +109 -0
- data/app/components/poetry/ui/radio_group/style.rb +53 -0
- data/app/components/poetry/ui/resizable/component.html.erb +10 -0
- data/app/components/poetry/ui/resizable/component.rb +178 -0
- data/app/components/poetry/ui/resizable/preview.rb +42 -0
- data/app/components/poetry/ui/resizable/style.rb +30 -0
- data/app/components/poetry/ui/scroll_area/component.rb +76 -0
- data/app/components/poetry/ui/scroll_area/preview.rb +35 -0
- data/app/components/poetry/ui/scroll_area/style.rb +19 -0
- data/app/components/poetry/ui/search_field/component.html.erb +15 -0
- data/app/components/poetry/ui/search_field/component.rb +137 -0
- data/app/components/poetry/ui/search_field/preview.rb +23 -0
- data/app/components/poetry/ui/search_field/style.rb +18 -0
- data/app/components/poetry/ui/select/component.html.erb +15 -0
- data/app/components/poetry/ui/select/component.rb +639 -0
- data/app/components/poetry/ui/select/preview.rb +113 -0
- data/app/components/poetry/ui/select/style.rb +58 -0
- data/app/components/poetry/ui/sensitive_input/component.html.erb +29 -0
- data/app/components/poetry/ui/sensitive_input/component.rb +274 -0
- data/app/components/poetry/ui/sensitive_input/preview.rb +40 -0
- data/app/components/poetry/ui/sensitive_input/style.rb +49 -0
- data/app/components/poetry/ui/separator/component.rb +57 -0
- data/app/components/poetry/ui/separator/preview.rb +19 -0
- data/app/components/poetry/ui/separator/style.rb +15 -0
- data/app/components/poetry/ui/sheet/component.html.erb +21 -0
- data/app/components/poetry/ui/sheet/component.rb +97 -0
- data/app/components/poetry/ui/sheet/preview.rb +57 -0
- data/app/components/poetry/ui/sheet/style.rb +47 -0
- data/app/components/poetry/ui/sidebar/component.html.erb +20 -0
- data/app/components/poetry/ui/sidebar/component.rb +249 -0
- data/app/components/poetry/ui/sidebar/preview.rb +21 -0
- data/app/components/poetry/ui/sidebar/shell_preview.html.erb +47 -0
- data/app/components/poetry/ui/sidebar/style.rb +139 -0
- data/app/components/poetry/ui/skeleton/component.rb +39 -0
- data/app/components/poetry/ui/skeleton/preview.rb +22 -0
- data/app/components/poetry/ui/skeleton/style.rb +13 -0
- data/app/components/poetry/ui/slider/component.html.erb +13 -0
- data/app/components/poetry/ui/slider/component.rb +360 -0
- data/app/components/poetry/ui/slider/preview.rb +73 -0
- data/app/components/poetry/ui/slider/style.rb +55 -0
- data/app/components/poetry/ui/spinner/component.rb +58 -0
- data/app/components/poetry/ui/spinner/preview.rb +22 -0
- data/app/components/poetry/ui/spinner/style.rb +12 -0
- data/app/components/poetry/ui/stat/component.html.erb +13 -0
- data/app/components/poetry/ui/stat/component.rb +102 -0
- data/app/components/poetry/ui/stat/preview.rb +47 -0
- data/app/components/poetry/ui/stat/style.rb +29 -0
- data/app/components/poetry/ui/switch/component.html.erb +15 -0
- data/app/components/poetry/ui/switch/component.rb +136 -0
- data/app/components/poetry/ui/switch/preview.rb +66 -0
- data/app/components/poetry/ui/switch/style.rb +22 -0
- data/app/components/poetry/ui/table/component.html.erb +3 -0
- data/app/components/poetry/ui/table/component.rb +93 -0
- data/app/components/poetry/ui/table/preview.rb +96 -0
- data/app/components/poetry/ui/table/style.rb +26 -0
- data/app/components/poetry/ui/tabs/component.html.erb +10 -0
- data/app/components/poetry/ui/tabs/component.rb +253 -0
- data/app/components/poetry/ui/tabs/preview.rb +43 -0
- data/app/components/poetry/ui/tabs/style.rb +49 -0
- data/app/components/poetry/ui/tag_group/component.html.erb +8 -0
- data/app/components/poetry/ui/tag_group/component.rb +203 -0
- data/app/components/poetry/ui/tag_group/preview.rb +43 -0
- data/app/components/poetry/ui/tag_group/style.rb +29 -0
- data/app/components/poetry/ui/textarea/component.rb +64 -0
- data/app/components/poetry/ui/textarea/preview.rb +75 -0
- data/app/components/poetry/ui/textarea/style.rb +18 -0
- data/app/components/poetry/ui/time_field/component.html.erb +6 -0
- data/app/components/poetry/ui/time_field/component.rb +85 -0
- data/app/components/poetry/ui/time_field/preview.rb +40 -0
- data/app/components/poetry/ui/time_field/style.rb +30 -0
- data/app/components/poetry/ui/timeline/component.rb +134 -0
- data/app/components/poetry/ui/timeline/preview.rb +61 -0
- data/app/components/poetry/ui/timeline/style.rb +54 -0
- data/app/components/poetry/ui/toast/component.html.erb +24 -0
- data/app/components/poetry/ui/toast/component.rb +178 -0
- data/app/components/poetry/ui/toast/preview.rb +69 -0
- data/app/components/poetry/ui/toast/style.rb +33 -0
- data/app/components/poetry/ui/toast_trigger/addressed_preview.html.erb +12 -0
- data/app/components/poetry/ui/toast_trigger/component.html.erb +3 -0
- data/app/components/poetry/ui/toast_trigger/component.rb +82 -0
- data/app/components/poetry/ui/toast_trigger/default_preview.html.erb +11 -0
- data/app/components/poetry/ui/toast_trigger/preview.rb +19 -0
- data/app/components/poetry/ui/toaster/component.html.erb +1 -0
- data/app/components/poetry/ui/toaster/component.rb +99 -0
- data/app/components/poetry/ui/toaster/positions_preview.html.erb +24 -0
- data/app/components/poetry/ui/toaster/preview.rb +46 -0
- data/app/components/poetry/ui/toaster/stamp_preview.html.erb +15 -0
- data/app/components/poetry/ui/toaster/style.rb +26 -0
- data/app/components/poetry/ui/toggle/component.rb +120 -0
- data/app/components/poetry/ui/toggle/preview.rb +79 -0
- data/app/components/poetry/ui/toggle/style.rb +33 -0
- data/app/components/poetry/ui/toggle_group/component.html.erb +4 -0
- data/app/components/poetry/ui/toggle_group/component.rb +252 -0
- data/app/components/poetry/ui/toggle_group/preview.rb +143 -0
- data/app/components/poetry/ui/toggle_group/style.rb +33 -0
- data/app/components/poetry/ui/toolbar/component.rb +125 -0
- data/app/components/poetry/ui/toolbar/preview.rb +41 -0
- data/app/components/poetry/ui/toolbar/style.rb +20 -0
- data/app/components/poetry/ui/tooltip/component.html.erb +20 -0
- data/app/components/poetry/ui/tooltip/component.rb +185 -0
- data/app/components/poetry/ui/tooltip/preview.rb +74 -0
- data/app/components/poetry/ui/tooltip/previews/provider_row.html.erb +25 -0
- data/app/components/poetry/ui/tooltip/style.rb +24 -0
- data/app/components/poetry/ui/tree/component.html.erb +32 -0
- data/app/components/poetry/ui/tree/component.rb +233 -0
- data/app/components/poetry/ui/tree/preview.rb +55 -0
- data/app/components/poetry/ui/tree/style.rb +29 -0
- data/app/components/poetry/ui/typeset/component.rb +73 -0
- data/app/components/poetry/ui/typeset/preview.rb +45 -0
- data/app/components/poetry/ui/typeset/style.rb +15 -0
- data/app/controllers/poetry/ui/llms_controller.rb +28 -0
- data/app/helpers/poetry/ui/components_helper.rb +1794 -0
- data/app/helpers/poetry/ui/form_builder/type_inference.rb +117 -0
- data/app/helpers/poetry/ui/form_builder.rb +916 -0
- data/app/helpers/poetry/ui/optimistic_form_builder.rb +55 -0
- data/app/helpers/poetry/ui/toast_stream_actions.rb +27 -0
- data/config/component_descriptions.yml +96 -0
- data/config/component_registry.yml +12257 -0
- data/config/locales/en.yml +93 -0
- data/config/routes.rb +8 -0
- data/config/template_classes.txt +113 -0
- data/lib/generators/poetry/add/add_generator.rb +218 -0
- data/lib/generators/poetry/agent_rules/agent_rules_generator.rb +91 -0
- data/lib/generators/poetry/agents/agents_generator.rb +24 -0
- data/lib/generators/poetry/agents_section.rb +148 -0
- data/lib/generators/poetry/block/block_generator.rb +67 -0
- data/lib/generators/poetry/block/templates/action_bar.html.erb +45 -0
- data/lib/generators/poetry/block/templates/app_shell.html.erb +139 -0
- data/lib/generators/poetry/block/templates/data_index.html.erb +85 -0
- data/lib/generators/poetry/block/templates/destructive_panel.html.erb +26 -0
- data/lib/generators/poetry/block/templates/page_header.html.erb +25 -0
- data/lib/generators/poetry/block/templates/section_card.html.erb +42 -0
- data/lib/generators/poetry/block/templates/stepper.html.erb +79 -0
- data/lib/generators/poetry/block/templates/top_nav.html.erb +44 -0
- data/lib/generators/poetry/diff/diff_generator.rb +135 -0
- data/lib/generators/poetry/editor/editor_generator.rb +344 -0
- data/lib/generators/poetry/editor/templates/poetry-check-hook +81 -0
- data/lib/generators/poetry/install/install_generator.rb +364 -0
- data/lib/generators/poetry/pagination/pagination_generator.rb +76 -0
- data/lib/generators/poetry/pagination/templates/kaminari_paginator.html.erb +29 -0
- data/lib/generators/poetry/pagination/templates/poetry_link_renderer.rb +34 -0
- data/lib/generators/poetry/pagination/templates/poetry_pagy_helper.rb +28 -0
- data/lib/generators/poetry/recipes/agent_embed/app/javascript/controllers/agent_demo_controller.js +131 -0
- data/lib/generators/poetry/recipes/screen_data_index/app/controllers/orders_controller.rb +15 -0
- data/lib/generators/poetry/recipes/screen_data_index/app/views/orders/index.html.erb +7 -0
- data/lib/generators/poetry/recipes/screen_data_index/test/system/orders_index_test.rb +16 -0
- data/lib/generators/poetry/recipes/screen_settings/app/controllers/settings_controller.rb +14 -0
- data/lib/generators/poetry/recipes/screen_settings/app/views/settings/show.html.erb +9 -0
- data/lib/generators/poetry/recipes/screen_settings/test/system/settings_show_test.rb +16 -0
- data/lib/generators/poetry/scaffold_templates/scaffold_templates_generator.rb +60 -0
- data/lib/generators/poetry/scaffold_templates/templates/_form.html.erb.tt +77 -0
- data/lib/generators/poetry/scaffold_templates/templates/controller.rb.tt +78 -0
- data/lib/generators/poetry/scaffold_templates/templates/edit.html.erb.tt +14 -0
- data/lib/generators/poetry/scaffold_templates/templates/index.html.erb.tt +24 -0
- data/lib/generators/poetry/scaffold_templates/templates/new.html.erb.tt +11 -0
- data/lib/generators/poetry/scaffold_templates/templates/partial.html.erb.tt +13 -0
- data/lib/generators/poetry/scaffold_templates/templates/show.html.erb.tt +18 -0
- data/lib/generators/poetry/skill/skill_generator.rb +34 -0
- data/lib/generators/poetry/skill/templates/poetry-component/SKILL.md +58 -0
- data/lib/generators/poetry/skill/templates/poetry-component/references/anatomy.md +152 -0
- data/lib/generators/poetry/skill/templates/poetry-component/references/checklist.md +67 -0
- data/lib/generators/poetry/skill/templates/poetry-component/references/documentation.md +137 -0
- data/lib/generators/poetry/skill/templates/poetry-design/SKILL.md +56 -0
- data/lib/generators/poetry/skill/templates/poetry-design/references/audit.md +123 -0
- data/lib/generators/poetry/skill/templates/poetry-design/references/compose.md +73 -0
- data/lib/generators/poetry/skill/templates/poetry-design/references/figma.md +68 -0
- data/lib/generators/poetry/skill/templates/poetry-design/references/paper.md +56 -0
- data/lib/generators/poetry/skill/templates/poetry-design/references/study.md +47 -0
- data/lib/generators/poetry/skill/templates/poetry-design/references/theme.md +70 -0
- data/lib/generators/poetry/skills_section.rb +58 -0
- data/lib/poetry/ui/chat.rb +283 -0
- data/lib/poetry/ui/code_block_highlighter.rb +60 -0
- data/lib/poetry/ui/engine.rb +55 -0
- data/lib/poetry/ui/recipes.rb +157 -0
- data/lib/poetry/ui/testing/combobox.rb +167 -0
- data/lib/poetry/ui/testing/dialog.rb +73 -0
- data/lib/poetry/ui/testing/menu.rb +127 -0
- data/lib/poetry/ui/testing/registration.rb +58 -0
- data/lib/poetry/ui/testing/select.rb +147 -0
- data/lib/poetry/ui/testing/tester.rb +130 -0
- data/lib/poetry/ui/testing.rb +130 -0
- data/lib/poetry/ui/themes.rb +109 -0
- data/lib/poetry/ui/version.rb +8 -0
- data/lib/poetry/ui/webmcp.rb +91 -0
- data/lib/poetry/ui.rb +285 -0
- data/lib/poetry-ui.rb +5 -0
- data/lib/tasks/poetry/check.rake +73 -0
- data/lib/tasks/poetry/design.rake +293 -0
- data/lib/tasks/poetry/verify.rake +36 -0
- data/themes/default.css +1793 -0
- data/themes/luma.css +1764 -0
- data/themes/lyra.css +1768 -0
- data/themes/maia.css +1768 -0
- data/themes/mira.css +1760 -0
- data/themes/nova.css +1755 -0
- data/themes/rhea.css +1771 -0
- data/themes/sera.css +1757 -0
- data/themes/vega.css +1775 -0
- data/typeset/typeset.css +499 -0
- metadata +502 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# ContextMenu family: the right-click/long-press menu.
|
|
6
|
+
module ContextMenu
|
|
7
|
+
# Shared vocabularies, declared once at module level so the root
|
|
8
|
+
# Component and the nested menu-level classes read the same lists.
|
|
9
|
+
DIRS = %i[ltr rtl].freeze
|
|
10
|
+
# The closed vocabulary for the side axis.
|
|
11
|
+
SIDES = %i[top right bottom left].freeze
|
|
12
|
+
|
|
13
|
+
# The shared menus-family kernel wearing this family identity -
|
|
14
|
+
# SLOT_BUILDERS (reopened at the bottom, once the classes exist) keeps
|
|
15
|
+
# the registry recursion on the family classes.
|
|
16
|
+
#
|
|
17
|
+
# @api private
|
|
18
|
+
module ItemSlots
|
|
19
|
+
extend ActiveSupport::Concern
|
|
20
|
+
include Poetry::Ui::Menus::ItemSlots
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# A context menu: the same menu anatomy as DropdownMenu, opened by
|
|
24
|
+
# right-click or long-press on a SURFACE instead of a button. The
|
|
25
|
+
# surface is NOT a widget - no role, no aria-haspopup, not in the
|
|
26
|
+
# tab order (unless focusable_surface: opts in) - and with no JS
|
|
27
|
+
# the browser-native context menu appears untouched. The menu
|
|
28
|
+
# anchors at the pointer position; side: picks which side of the
|
|
29
|
+
# pointer it opens toward (default right), and collisions can
|
|
30
|
+
# still flip it.
|
|
31
|
+
#
|
|
32
|
+
# @example Right-click surface with actions
|
|
33
|
+
# render Poetry::Ui::ContextMenu::Component.new do |menu|
|
|
34
|
+
# menu.with_trigger(tag: :div) { "Right-click this card" }
|
|
35
|
+
# menu.with_item { "Rename" }
|
|
36
|
+
# menu.with_item(variant: :destructive) { "Delete" }
|
|
37
|
+
# end
|
|
38
|
+
class Component < Poetry::Core::Component
|
|
39
|
+
include ItemSlots
|
|
40
|
+
|
|
41
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
42
|
+
AGENT_RULES = [
|
|
43
|
+
"NEVER make a context menu the only path to an action - it is an invisible affordance; every " \
|
|
44
|
+
"item needs a visible equivalent (a '...' DropdownMenu button, a toolbar, a detail page).",
|
|
45
|
+
"Choose ContextMenu only for right-click-on-an-object semantics; a visible button opening a " \
|
|
46
|
+
"menu is DropdownMenu.",
|
|
47
|
+
"Do not add aria-haspopup or a role to the trigger surface; do not make it focusable except " \
|
|
48
|
+
"via focusable_surface: true.",
|
|
49
|
+
"side: picks which side of the pointer the menu opens toward (top/right/bottom/left, default " \
|
|
50
|
+
":right); align and offsets are not API - collisions still flip the side.",
|
|
51
|
+
"Wrap the whole logical object (row/card) as the trigger surface, not a fragment.",
|
|
52
|
+
"Destructive items use variant: :destructive AND still confirm irreversible actions via a dialog.",
|
|
53
|
+
"shortcut: is a visual hint only - it does NOT bind the key.",
|
|
54
|
+
"Do not nest a ContextMenu trigger surface inside another ContextMenu trigger surface."
|
|
55
|
+
].freeze
|
|
56
|
+
|
|
57
|
+
renders_one :trigger,
|
|
58
|
+
doc: "The right-click/long-press SURFACE: wraps arbitrary content (a card, a row, a region); " \
|
|
59
|
+
"polymorphic tag: (default :span, set tag: :div to wrap block content). NOT a button: no " \
|
|
60
|
+
"role, no aria-haspopup, no tabindex by default. The inline -webkit-touch-callout " \
|
|
61
|
+
"suppresses the iOS callout so long-press can run (iOS never fires contextmenu; the timer " \
|
|
62
|
+
"is the only touch path there).",
|
|
63
|
+
renders: lambda { |**options, &block|
|
|
64
|
+
tag_name = options.delete(:tag) || :span
|
|
65
|
+
attrs = {
|
|
66
|
+
"id" => trigger_id, "data-slot" => "context-menu-trigger",
|
|
67
|
+
"aria-controls" => content_id,
|
|
68
|
+
"style" => ["-webkit-touch-callout: none", options.delete(:style)].compact.join("; ")
|
|
69
|
+
}.merge(stimulus_attributes_for(:trigger))
|
|
70
|
+
# The surface state: bare data-popup-open while open, NO
|
|
71
|
+
# attribute while closed (absence IS the state).
|
|
72
|
+
attrs["data-popup-open"] = "" if open
|
|
73
|
+
attrs["data-disabled"] = "" if disabled
|
|
74
|
+
if focusable_surface
|
|
75
|
+
attrs["tabindex"] = "0"
|
|
76
|
+
attrs["aria-keyshortcuts"] = "Shift+F10"
|
|
77
|
+
end
|
|
78
|
+
content_tag(tag_name, Poetry::Core::HTML::Attributes.merged(attrs, options)) { capture(&block) }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
use_stimulus do
|
|
82
|
+
on :root do
|
|
83
|
+
controller :context_menu do
|
|
84
|
+
register
|
|
85
|
+
value :long_press_delay
|
|
86
|
+
value :disabled
|
|
87
|
+
end
|
|
88
|
+
controller :menu do
|
|
89
|
+
register
|
|
90
|
+
value :open
|
|
91
|
+
value :modal
|
|
92
|
+
value :loop
|
|
93
|
+
end
|
|
94
|
+
controller :popper do
|
|
95
|
+
register
|
|
96
|
+
# side: is the one placement knob; align start / side_offset
|
|
97
|
+
# 2 stay fixed; collisions still flip the side.
|
|
98
|
+
value :side
|
|
99
|
+
value :align, :start
|
|
100
|
+
value :side_offset, 2
|
|
101
|
+
value :avoid_collisions, true
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
# The surface's wiring: contextmenu + the long-press pointer set;
|
|
105
|
+
# popper's anchor target is the FALLBACK rect for positionless
|
|
106
|
+
# opens (the stored virtual anchor point wins).
|
|
107
|
+
on :trigger do
|
|
108
|
+
controller :context_menu do
|
|
109
|
+
action :open, on: :contextmenu
|
|
110
|
+
action :press_start, on: :pointerdown
|
|
111
|
+
action :press_cancel, on: %i[pointermove pointerup pointercancel]
|
|
112
|
+
end
|
|
113
|
+
controller(:popper) { target :anchor }
|
|
114
|
+
end
|
|
115
|
+
on :content do
|
|
116
|
+
controller(:popper) { target :content }
|
|
117
|
+
end
|
|
118
|
+
on :item do
|
|
119
|
+
controller(:menu) { action :activate, on: :click }
|
|
120
|
+
end
|
|
121
|
+
on :sub_trigger do
|
|
122
|
+
controller :menu do
|
|
123
|
+
action :sub_enter, on: :pointerenter
|
|
124
|
+
action :sub_leave, on: :pointerleave
|
|
125
|
+
action :open_sub, on: :click
|
|
126
|
+
end
|
|
127
|
+
controller(:popper) { target :anchor }
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
option :open, :boolean, default: false,
|
|
132
|
+
doc: "Server-renders the menu open (rare - context menus normally open from the " \
|
|
133
|
+
"gesture)."
|
|
134
|
+
option :modal, :boolean, default: true, doc: "Traps focus in the open menu; false keeps the page interactive."
|
|
135
|
+
option :loop, :boolean, default: false, doc: "Wraps arrow-key movement past either end of the menu."
|
|
136
|
+
option :long_press_delay, :integer, default: 700, doc: "Touch long-press duration in ms before the menu opens."
|
|
137
|
+
option :disabled, :boolean, default: false, doc: "Inerts the surface - no gesture opens the menu."
|
|
138
|
+
option :label, :string, doc: "The menu's accessible name (localized fallback when omitted)."
|
|
139
|
+
option :focusable_surface, :boolean, default: false,
|
|
140
|
+
doc: "Puts the surface in the tab order and advertises Shift+F10."
|
|
141
|
+
option :dir, :symbol, doc: "Writing-direction override (ltr/rtl) stamped on the root."
|
|
142
|
+
option :side, :symbol, default: :right,
|
|
143
|
+
doc: "Which side of the pointer the menu opens toward; collisions may still flip it."
|
|
144
|
+
|
|
145
|
+
validates :dir, inclusion: { in: DIRS }, allow_nil: true
|
|
146
|
+
validates :side, inclusion: { in: SIDES }
|
|
147
|
+
|
|
148
|
+
part "context-menu", "Root wrapper hosting the context-menu + menu + popper controllers " \
|
|
149
|
+
"around the surface and content"
|
|
150
|
+
part "context-menu-trigger", "The right-click/long-press SURFACE wrapping the logical object " \
|
|
151
|
+
"- not a widget: no role, no aria-haspopup",
|
|
152
|
+
states: {
|
|
153
|
+
"data-popup-open" => "the menu is open (absence is the closed state - no aria-expanded " \
|
|
154
|
+
"on a role-less surface)",
|
|
155
|
+
"data-disabled" => "the surface is inert (disabled: true)"
|
|
156
|
+
}
|
|
157
|
+
part "context-menu-content", "The role=menu popup panel - anchored at the pointer via popper's " \
|
|
158
|
+
"virtual-anchor mode; open state and animation ride here",
|
|
159
|
+
states: {
|
|
160
|
+
"data-open" => "menu is open (presence flips the pair at runtime)",
|
|
161
|
+
"data-closed" => "menu is closed or animating out (the server-rendered state)",
|
|
162
|
+
"data-side" => { condition: "the placement side (the side: option, default right; popper " \
|
|
163
|
+
"re-writes it after collision flips)",
|
|
164
|
+
values: %w[top right bottom left] },
|
|
165
|
+
"data-align" => { condition: "the alignment (forced start initially; popper re-resolves it)",
|
|
166
|
+
values: %w[start center end] }
|
|
167
|
+
},
|
|
168
|
+
vars: {
|
|
169
|
+
"--transform-origin" => "popper's anchor-facing animation origin",
|
|
170
|
+
"--available-width" => "popper: viewport space left for the panel (post-flip)",
|
|
171
|
+
"--available-height" => "popper: viewport space left for the panel (post-flip)",
|
|
172
|
+
"--anchor-width" => "popper: the anchor rect's measured width",
|
|
173
|
+
"--anchor-height" => "popper: the anchor rect's measured height"
|
|
174
|
+
}
|
|
175
|
+
part "context-menu-group", "role=group semantic grouping between separators"
|
|
176
|
+
part "context-menu-label", "Non-interactive heading for a run of items",
|
|
177
|
+
states: {
|
|
178
|
+
"data-inset" => "indented to align with checkbox/radio item text (inset: true)"
|
|
179
|
+
}
|
|
180
|
+
part "context-menu-item", "One role=menuitem action row",
|
|
181
|
+
states: {
|
|
182
|
+
"data-variant" => "default or destructive (the danger treatment)",
|
|
183
|
+
"data-inset" => "indented to align with checkbox/radio item text (inset: true)",
|
|
184
|
+
"data-disabled" => "item is disabled (always written together with aria-disabled)"
|
|
185
|
+
}
|
|
186
|
+
part "context-menu-checkbox-item", "A role=menuitemcheckbox toggle row",
|
|
187
|
+
states: {
|
|
188
|
+
"data-checked" => "checked (the controller re-writes the pair with aria-checked on " \
|
|
189
|
+
"activation)",
|
|
190
|
+
"data-unchecked" => "unchecked",
|
|
191
|
+
"data-disabled" => "item is disabled (always written together with aria-disabled)",
|
|
192
|
+
"data-close-on-select" => "per-item override of the menu's close-on-select default " \
|
|
193
|
+
"(\"false\" keeps the menu open)"
|
|
194
|
+
}
|
|
195
|
+
part "context-menu-radio-group", "role=group scoping one single-select value",
|
|
196
|
+
states: {
|
|
197
|
+
"data-value" => "the selected radio value (the controller re-writes it on change)"
|
|
198
|
+
}
|
|
199
|
+
part "context-menu-radio-item", "A role=menuitemradio row inside a radio group",
|
|
200
|
+
states: {
|
|
201
|
+
"data-checked" => "the selected radio (the controller re-writes the pair with aria-checked)",
|
|
202
|
+
"data-unchecked" => "not selected",
|
|
203
|
+
"data-value" => "the radio's value",
|
|
204
|
+
"data-disabled" => "item is disabled (always written together with aria-disabled)"
|
|
205
|
+
}
|
|
206
|
+
part "context-menu-checkbox-item-indicator",
|
|
207
|
+
"The check glyph inside checkbox items (aria-hidden; the item carries the checked state)"
|
|
208
|
+
part "context-menu-radio-item-indicator",
|
|
209
|
+
"The circle glyph inside radio items (aria-hidden; the item carries the checked state)"
|
|
210
|
+
part "context-menu-separator", "role=separator rule between groups"
|
|
211
|
+
part "context-menu-shortcut", "The trailing keybinding HINT - aria-hidden, never binds the key"
|
|
212
|
+
part "context-menu-sub", "A submenu scope - hosts its own popper around the sub trigger/" \
|
|
213
|
+
"content pair"
|
|
214
|
+
part "context-menu-sub-trigger", "The role=menuitem row opening its submenu",
|
|
215
|
+
states: {
|
|
216
|
+
"data-popup-open" => "its submenu is open (written with aria-expanded; absence is the " \
|
|
217
|
+
"closed state)",
|
|
218
|
+
"data-inset" => "indented to align with checkbox/radio item text (inset: true)"
|
|
219
|
+
}
|
|
220
|
+
part "context-menu-sub-content", "The nested role=menu panel - its own popper content on the " \
|
|
221
|
+
"same presence machinery",
|
|
222
|
+
states: {
|
|
223
|
+
"data-open" => "submenu is open (presence flips the pair at runtime)",
|
|
224
|
+
"data-closed" => "submenu is closed (the server-rendered state)",
|
|
225
|
+
"data-side" => { condition: "the placement side (right/left by direction; popper resolves " \
|
|
226
|
+
"it at runtime)",
|
|
227
|
+
values: %w[top right bottom left] },
|
|
228
|
+
"data-align" => { condition: "the alignment against the sub-trigger (popper resolves it " \
|
|
229
|
+
"at runtime)",
|
|
230
|
+
values: %w[start center end] }
|
|
231
|
+
},
|
|
232
|
+
vars: {
|
|
233
|
+
"--transform-origin" => "popper's anchor-facing animation origin",
|
|
234
|
+
"--available-width" => "popper: viewport space left for the panel (post-flip)",
|
|
235
|
+
"--available-height" => "popper: viewport space left for the panel (post-flip)",
|
|
236
|
+
"--anchor-width" => "popper: the sub-trigger's measured width",
|
|
237
|
+
"--anchor-height" => "popper: the sub-trigger's measured height"
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# Enforces the required surface and at least one item.
|
|
241
|
+
# @api private
|
|
242
|
+
def before_render
|
|
243
|
+
raise ArgumentError, "ContextMenu requires with_trigger (the right-click surface)" unless trigger?
|
|
244
|
+
raise ArgumentError, "ContextMenu requires at least one item" unless items?
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# The surface's id.
|
|
248
|
+
# @api private
|
|
249
|
+
def trigger_id
|
|
250
|
+
"#{instance_id}-trigger"
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# The menu panel's id - the surface's aria-controls target.
|
|
254
|
+
# @api private
|
|
255
|
+
def content_id
|
|
256
|
+
"#{instance_id}-content"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Attributes for the root wrapper.
|
|
260
|
+
# @api private
|
|
261
|
+
def root_attributes
|
|
262
|
+
root = { "data-slot" => "context-menu" }
|
|
263
|
+
root["dir"] = dir.to_s if dir
|
|
264
|
+
html_attributes.merge_if_not_set(
|
|
265
|
+
root.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
266
|
+
)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Attributes for the role=menu panel.
|
|
270
|
+
# @api private
|
|
271
|
+
def content_attributes
|
|
272
|
+
attrs = {
|
|
273
|
+
"id" => content_id, "role" => "menu", "aria-orientation" => "vertical",
|
|
274
|
+
# No aria-labelledby to the trigger (it is not a widget - the
|
|
275
|
+
# delta): the menu's name is label: -> the i18n fallback.
|
|
276
|
+
"aria-label" => label.presence || t("poetry.context_menu.menu_label_fallback"),
|
|
277
|
+
"tabindex" => "-1",
|
|
278
|
+
"data-slot" => "context-menu-content", (open ? "data-open" : "data-closed") => "",
|
|
279
|
+
# The initial placement (side: option; re-resolved live by popper).
|
|
280
|
+
"data-side" => side.to_s, "data-align" => "start",
|
|
281
|
+
"class" => css(:content)
|
|
282
|
+
}.merge(stimulus_attributes_for(:content))
|
|
283
|
+
attrs["hidden"] = true unless open
|
|
284
|
+
attrs
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
private
|
|
288
|
+
|
|
289
|
+
def menu_dir
|
|
290
|
+
dir
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Server-stable unique id pair (aria-controls is the controller's
|
|
294
|
+
# portal-safe trigger->content seam).
|
|
295
|
+
def instance_id
|
|
296
|
+
@instance_id ||= poetry_instance_id("poetry-context-menu")
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
private :trigger_id, :content_id, :root_attributes, :content_attributes
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# role=group semantic grouping between separators - the shared kernel
|
|
303
|
+
# anatomy wearing this family identity.
|
|
304
|
+
#
|
|
305
|
+
# @api private
|
|
306
|
+
class Group < Poetry::Ui::Menus::Group
|
|
307
|
+
include ItemSlots
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# role=group scoping the single-select value for its radio items -
|
|
311
|
+
# the shared kernel anatomy wearing this family identity.
|
|
312
|
+
#
|
|
313
|
+
# @api private
|
|
314
|
+
class RadioGroup < Poetry::Ui::Menus::RadioGroup
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# A submenu scope (recursive item union on its own popper) - the
|
|
318
|
+
# shared kernel anatomy wearing this family identity.
|
|
319
|
+
#
|
|
320
|
+
# @api private
|
|
321
|
+
class Sub < Poetry::Ui::Menus::Sub
|
|
322
|
+
include ItemSlots
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# The builder classes behind lambda-wrapped slot types: a
|
|
326
|
+
# lambda hides its return class from introspection, so the owner
|
|
327
|
+
# declares it and the registry walker recurses into the builder's own
|
|
328
|
+
# call surface (with_sub yields a Sub with its own items).
|
|
329
|
+
# REQUIRED_SLOTS states the same facts the before_render
|
|
330
|
+
# raises enforce, so static checks can flag omissions without
|
|
331
|
+
# rendering.
|
|
332
|
+
module ItemSlots
|
|
333
|
+
# Nested-slot recursion map for the registry projection.
|
|
334
|
+
SLOT_BUILDERS = { sub: Sub, group: Group, radio_group: RadioGroup }.freeze
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
class Component
|
|
338
|
+
# The required slots, stated statically for static checks.
|
|
339
|
+
REQUIRED_SLOTS = { trigger: "the right-click surface", item: "at least one item" }.freeze
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
class Group
|
|
343
|
+
# The required slots, stated statically for static checks.
|
|
344
|
+
REQUIRED_SLOTS = { item: "at least one item" }.freeze
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
class RadioGroup
|
|
348
|
+
# The required slots, stated statically for static checks.
|
|
349
|
+
REQUIRED_SLOTS = { radio_item: "at least one radio item" }.freeze
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
class Sub
|
|
353
|
+
# The required slots, stated statically for static checks.
|
|
354
|
+
REQUIRED_SLOTS = { trigger: "the sub-menu item", item: "at least one item" }.freeze
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module ContextMenu
|
|
6
|
+
# The ContextMenu preview matrix: the ported context-menu-demo port
|
|
7
|
+
# (items + shortcuts, a submenu, checkbox items, a radio group) on a
|
|
8
|
+
# right-click surface, plus inset/disabled items, the disabled
|
|
9
|
+
# surface (native menu returns), RTL, the focusable-surface keyboard
|
|
10
|
+
# mode, and the server-rendered open state. Long-press/pointer
|
|
11
|
+
# anchoring is runtime behavior - the browser pass drives it.
|
|
12
|
+
class Preview < Poetry::Core::Preview::Base
|
|
13
|
+
SURFACE_CLASSES = "flex h-[150px] w-[300px] items-center justify-center rounded-md " \
|
|
14
|
+
"border border-dashed text-sm select-none"
|
|
15
|
+
|
|
16
|
+
# The context-menu-demo port: right-click the dashed surface.
|
|
17
|
+
def default
|
|
18
|
+
render_component do |menu|
|
|
19
|
+
menu.with_trigger(tag: :div, class: SURFACE_CLASSES) { "Right-click here" }
|
|
20
|
+
menu.with_item(inset: true, shortcut: "⌘[") { "Back" }
|
|
21
|
+
menu.with_item(inset: true, disabled: true, shortcut: "⌘]") { "Forward" }
|
|
22
|
+
menu.with_item(inset: true, shortcut: "⌘R") { "Reload" }
|
|
23
|
+
menu.with_sub do |sub|
|
|
24
|
+
sub.with_trigger(inset: true) { "More Tools" }
|
|
25
|
+
sub.with_item(shortcut: "⇧⌘S") { "Save Page As..." }
|
|
26
|
+
sub.with_item { "Create Shortcut..." }
|
|
27
|
+
sub.with_item { "Name Window..." }
|
|
28
|
+
sub.with_separator
|
|
29
|
+
sub.with_item { "Developer Tools" }
|
|
30
|
+
end
|
|
31
|
+
menu.with_separator
|
|
32
|
+
menu.with_checkbox_item(checked: true, close_on_select: false, shortcut: "⌘⇧B") { "Show Bookmarks Bar" }
|
|
33
|
+
menu.with_checkbox_item(checked: false, close_on_select: false) { "Show Full URLs" }
|
|
34
|
+
menu.with_separator
|
|
35
|
+
menu.with_radio_group(value: "pedro") do |group|
|
|
36
|
+
group.with_radio_item(value: "pedro") { "Pedro Duarte" }
|
|
37
|
+
group.with_radio_item(value: "colm") { "Colm Tuite" }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# A destructive tail + a named menu (label: -> aria-label).
|
|
43
|
+
def destructive
|
|
44
|
+
render_component(label: "File actions") do |menu|
|
|
45
|
+
menu.with_trigger(tag: :div, class: SURFACE_CLASSES) { "quarterly-report.pdf" }
|
|
46
|
+
menu.with_item { "Open" }
|
|
47
|
+
menu.with_item { "Rename" }
|
|
48
|
+
menu.with_separator
|
|
49
|
+
menu.with_item(variant: :destructive, shortcut: "⌘⌫") { "Delete" }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# disabled: true stands the handlers down - right-click here shows
|
|
54
|
+
# the BROWSER-NATIVE context menu (never a dead surface).
|
|
55
|
+
def disabled_surface
|
|
56
|
+
render_component(disabled: true) do |menu|
|
|
57
|
+
menu.with_trigger(tag: :div, class: SURFACE_CLASSES) { "Native menu here (disabled)" }
|
|
58
|
+
menu.with_item { "Unreachable" }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# focusable_surface: true opts the surface into the tab order with
|
|
63
|
+
# the aria-keyshortcuts hint - Shift+F10 / the Menu key open it.
|
|
64
|
+
def focusable_surface
|
|
65
|
+
render_component(focusable_surface: true, label: "Row actions") do |menu|
|
|
66
|
+
menu.with_trigger(tag: :div, class: SURFACE_CLASSES) { "Focusable row (Shift+F10)" }
|
|
67
|
+
menu.with_item { "Rename" }
|
|
68
|
+
menu.with_item { "Duplicate" }
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# The submenu side flips under RTL.
|
|
73
|
+
def rtl
|
|
74
|
+
render_component(dir: :rtl) do |menu|
|
|
75
|
+
menu.with_trigger(tag: :div, class: SURFACE_CLASSES) { "انقر بزر الماوس الأيمن" }
|
|
76
|
+
menu.with_item { "فتح" }
|
|
77
|
+
menu.with_sub do |sub|
|
|
78
|
+
sub.with_trigger { "المزيد" }
|
|
79
|
+
sub.with_item { "استيراد" }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# A grouped run - the role=group wrapper between separators.
|
|
85
|
+
def grouped
|
|
86
|
+
render_component do |menu|
|
|
87
|
+
menu.with_trigger(tag: :div, class: SURFACE_CLASSES) { "Surface" }
|
|
88
|
+
menu.with_group do |group|
|
|
89
|
+
group.with_item { "Cut" }
|
|
90
|
+
group.with_item { "Copy" }
|
|
91
|
+
end
|
|
92
|
+
menu.with_separator
|
|
93
|
+
menu.with_checkbox_item(checked: true, disabled: true) { "Locked toggle" }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Server-rendered open state (controllable-state: the attributes
|
|
98
|
+
# are the store; positionless open anchors to the trigger rect).
|
|
99
|
+
def open
|
|
100
|
+
render_component(open: true) do |menu|
|
|
101
|
+
menu.with_trigger(tag: :div, class: SURFACE_CLASSES) { "Surface" }
|
|
102
|
+
menu.with_label { "Row" }
|
|
103
|
+
menu.with_item { "Rename" }
|
|
104
|
+
menu.with_separator
|
|
105
|
+
menu.with_item(variant: :destructive) { "Delete" }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module ContextMenu
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The family deltas
|
|
7
|
+
# vs DropdownMenu now read off the theme rules (context-menu label
|
|
8
|
+
# adds text-foreground, the sub-trigger omits gap-2, the sub chevron
|
|
9
|
+
# is a bare ml-auto); the trigger SURFACE still ships no classes.
|
|
10
|
+
class Style < Poetry::Core::Style
|
|
11
|
+
element :content, "cn-context-menu-content cn-menu-translucent z-50 max-h-(--available-height) " \
|
|
12
|
+
"origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none"
|
|
13
|
+
|
|
14
|
+
# group/context-menu-item: bare marker, no CSS - the vega theme's
|
|
15
|
+
# shortcut re-color (group-focus/context-menu-item) keys on it.
|
|
16
|
+
element :item, "cn-context-menu-item group/context-menu-item relative flex cursor-default " \
|
|
17
|
+
"items-center outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 " \
|
|
18
|
+
"data-disabled:opacity-50 data-disabled:pointer-events-none"
|
|
19
|
+
|
|
20
|
+
element :checkbox_item, "cn-context-menu-checkbox-item relative flex cursor-default items-center " \
|
|
21
|
+
"outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 " \
|
|
22
|
+
"data-disabled:opacity-50 data-disabled:pointer-events-none"
|
|
23
|
+
|
|
24
|
+
element :radio_item, "cn-context-menu-radio-item relative flex cursor-default items-center outline-hidden " \
|
|
25
|
+
"select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 data-disabled:opacity-50 " \
|
|
26
|
+
"data-disabled:pointer-events-none"
|
|
27
|
+
|
|
28
|
+
element :label, "cn-context-menu-label"
|
|
29
|
+
|
|
30
|
+
element :separator, "cn-context-menu-separator"
|
|
31
|
+
|
|
32
|
+
element :shortcut, "cn-context-menu-shortcut"
|
|
33
|
+
|
|
34
|
+
element :sub_trigger, "cn-context-menu-sub-trigger flex cursor-default items-center " \
|
|
35
|
+
"outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0"
|
|
36
|
+
|
|
37
|
+
element :sub_content, "cn-context-menu-sub-content z-50 " \
|
|
38
|
+
"origin-(--transform-origin) overflow-hidden"
|
|
39
|
+
|
|
40
|
+
# Source-exact wrapper span (anonymous in the ported source; poetry names
|
|
41
|
+
# it context-menu-item-indicator - the self-identification rule).
|
|
42
|
+
element :item_indicator, "cn-context-menu-item-indicator pointer-events-none absolute " \
|
|
43
|
+
"flex items-center justify-center"
|
|
44
|
+
|
|
45
|
+
# POETRY ADDITION (family convention): the indicator stays in the
|
|
46
|
+
# DOM; the parent item's data-checked/data-unchecked pair drives
|
|
47
|
+
# visibility.
|
|
48
|
+
element :item_indicator_state, "[[data-unchecked]>&]:hidden"
|
|
49
|
+
|
|
50
|
+
# The source's inline lucide icon classes, named per part. DELTA:
|
|
51
|
+
# the context sub chevron is a bare ml-auto (the item's [&_svg]
|
|
52
|
+
# rules provide size-4).
|
|
53
|
+
element :indicator_check, "size-4"
|
|
54
|
+
element :indicator_circle, "size-2 fill-current"
|
|
55
|
+
element :sub_indicator, "ml-auto"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<% surface = capture do %>
|
|
2
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
3
|
+
<% if filter %>
|
|
4
|
+
<div data-slot="data-table-toolbar" class="<%= css(:toolbar) %>">
|
|
5
|
+
<form method="get" action="<%= filter_form_action %>" role="search" aria-label="<%= filter_label %>" data-slot="data-table-filter">
|
|
6
|
+
<% state.filter_params.each do |name, value| %>
|
|
7
|
+
<input type="hidden" name="<%= name %>" value="<%= value %>">
|
|
8
|
+
<% end %>
|
|
9
|
+
<label for="<%= filter_id %>" class="sr-only"><%= filter_label %></label>
|
|
10
|
+
<%= render Poetry::Ui::Input::Component.new(id: filter_id, name: filter_name,
|
|
11
|
+
value: state.q, placeholder: filter_placeholder,
|
|
12
|
+
class: "max-w-sm") %>
|
|
13
|
+
</form>
|
|
14
|
+
</div>
|
|
15
|
+
<% end %>
|
|
16
|
+
<div class="<%= css(:container) %>">
|
|
17
|
+
<%= render Poetry::Ui::Table::Component.new(sticky_header: sticky_header, container_class: container_class,
|
|
18
|
+
scroll_label: scroll_label.presence || caption) do %>
|
|
19
|
+
<% if caption.present? %>
|
|
20
|
+
<caption data-slot="table-caption" class="<%= Poetry::Ui::Table::Style.css(:caption, class: css(:caption)) %>"><%= caption %></caption>
|
|
21
|
+
<% end %>
|
|
22
|
+
<thead data-slot="table-header" class="<%= Poetry::Ui::Table::Style.css(:header) %>">
|
|
23
|
+
<tr data-slot="table-row" class="<%= Poetry::Ui::Table::Style.css(:row) %>">
|
|
24
|
+
<% if selectable? %>
|
|
25
|
+
<th data-slot="table-head" class="<%= Poetry::Ui::Table::Style.css(:head) %> <%= css(:select_cell) %>">
|
|
26
|
+
<%= tag.input(**Poetry::Core::HTML::Attributes.new(select_all_attributes).to_attributes) %>
|
|
27
|
+
</th>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% column_defs.each do |column| %>
|
|
30
|
+
<%= content_tag(:th, head_attributes(column)) do %>
|
|
31
|
+
<% if column.sortable %>
|
|
32
|
+
<%= render Poetry::Ui::Button::Component.new(**sort_link_options(column)) do |button| %>
|
|
33
|
+
<% button.with_trailing { render Poetry::Ui::Icon::Component.new(name: sort_icon(column)) } %>
|
|
34
|
+
<%= column.label %>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% else %>
|
|
37
|
+
<%= column.label %>
|
|
38
|
+
<% end %>
|
|
39
|
+
<% end %>
|
|
40
|
+
<% end %>
|
|
41
|
+
</tr>
|
|
42
|
+
</thead>
|
|
43
|
+
<tbody data-slot="table-body" class="<%= Poetry::Ui::Table::Style.css(:body) %>">
|
|
44
|
+
<% if rows.any? %>
|
|
45
|
+
<% rows.each do |row| %>
|
|
46
|
+
<tr data-slot="table-row" class="<%= Poetry::Ui::Table::Style.css(:row) %>">
|
|
47
|
+
<% if selectable? %>
|
|
48
|
+
<td data-slot="table-cell" class="<%= Poetry::Ui::Table::Style.css(:cell) %> <%= css(:select_cell) %>">
|
|
49
|
+
<%= tag.input(**Poetry::Core::HTML::Attributes.new(select_row_attributes(row)).to_attributes) %>
|
|
50
|
+
</td>
|
|
51
|
+
<% end %>
|
|
52
|
+
<% column_defs.each do |column| %>
|
|
53
|
+
<%= content_tag(:td, column.cell.call(row), cell_attributes(column)) %>
|
|
54
|
+
<% end %>
|
|
55
|
+
</tr>
|
|
56
|
+
<% end %>
|
|
57
|
+
<% else %>
|
|
58
|
+
<tr data-slot="table-row" class="<%= Poetry::Ui::Table::Style.css(:row) %>">
|
|
59
|
+
<td data-slot="table-cell" colspan="<%= column_defs.size + (selectable? ? 1 : 0) %>"
|
|
60
|
+
class="<%= Poetry::Ui::Table::Style.css(:cell) %> <%= css(:empty) %>"><%= empty_text %></td>
|
|
61
|
+
</tr>
|
|
62
|
+
<% end %>
|
|
63
|
+
</tbody>
|
|
64
|
+
<% end %>
|
|
65
|
+
</div>
|
|
66
|
+
<% if pagination? %>
|
|
67
|
+
<div data-slot="data-table-footer" class="<%= css(:footer) %>">
|
|
68
|
+
<%= render Poetry::Ui::Pagination::Component.new(current: state.page, total: total,
|
|
69
|
+
path: ->(page) { path_for(state.page_params(page)) }) %>
|
|
70
|
+
</div>
|
|
71
|
+
<% end %>
|
|
72
|
+
<% end %>
|
|
73
|
+
<% end %>
|
|
74
|
+
<% if frame.present? %>
|
|
75
|
+
<turbo-frame id="<%= frame %>" data-turbo-action="advance"><%= surface %></turbo-frame>
|
|
76
|
+
<% else %>
|
|
77
|
+
<%= surface %>
|
|
78
|
+
<% end %>
|