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,493 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A desktop-style menu bar of drop-down menus.
|
|
6
|
+
module Menubar
|
|
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
|
+
|
|
11
|
+
# The shared menus-family helpers plus this family's fork: Menubar
|
|
12
|
+
# themes its checkbox and radio indicators separately (a per-kind
|
|
13
|
+
# class rides along).
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
16
|
+
module Helpers
|
|
17
|
+
include Poetry::Ui::Menus::Helpers
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def indicator_extra_class(kind)
|
|
22
|
+
"cn-menubar-#{kind}-item-indicator"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The shared menus-family item slots wearing this family's identity -
|
|
27
|
+
# SLOT_BUILDERS (reopened at the bottom, once the classes exist) keeps
|
|
28
|
+
# the registry recursion on the family classes.
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
31
|
+
module ItemSlots
|
|
32
|
+
extend ActiveSupport::Concern
|
|
33
|
+
include Poetry::Ui::Menus::ItemSlots
|
|
34
|
+
include Helpers
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# A desktop-app command bar: File / Edit / View menus on one
|
|
38
|
+
# role=menubar row. The bar is a single tab stop - arrow keys move
|
|
39
|
+
# between the top-level triggers - and each trigger opens a full
|
|
40
|
+
# drop-down menu (action items, checkbox and radio rows, submenus,
|
|
41
|
+
# separators, shortcut hints). Menus are non-modal, so once one is
|
|
42
|
+
# open, hovering a sibling trigger slides to its menu.
|
|
43
|
+
#
|
|
44
|
+
# label: (the bar's accessible name) and at least one with_menu are
|
|
45
|
+
# required. For site navigation use NavigationMenu; for a single
|
|
46
|
+
# actions menu use DropdownMenu.
|
|
47
|
+
#
|
|
48
|
+
# @example An application command bar
|
|
49
|
+
# render Poetry::Ui::Menubar::Component.new(label: "Application") do |bar|
|
|
50
|
+
# bar.with_menu do |menu|
|
|
51
|
+
# menu.with_trigger { "File" }
|
|
52
|
+
# menu.with_item(shortcut: "⌘N") { "New" }
|
|
53
|
+
# menu.with_separator
|
|
54
|
+
# menu.with_item { "Print..." }
|
|
55
|
+
# end
|
|
56
|
+
# end
|
|
57
|
+
class Component < Poetry::Core::Component
|
|
58
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
59
|
+
AGENT_RULES = [
|
|
60
|
+
"Use poetry_menubar for app-chrome command menus ONLY - site navigation is NavigationMenu " \
|
|
61
|
+
"(untrapped), a single actions menu is DropdownMenu.",
|
|
62
|
+
"label: is REQUIRED (the bar's accessible name).",
|
|
63
|
+
"Never put non-menuitem interactive elements directly in the bar (breaks roving focus + APG " \
|
|
64
|
+
"roles) - a Toolbar is the component for mixed controls.",
|
|
65
|
+
"shortcut: is a visual hint ONLY - it does not register a keybinding; wire real shortcuts " \
|
|
66
|
+
"separately.",
|
|
67
|
+
"Do not hand-wire hover-open-from-cold; hover only slides between menus once one is open " \
|
|
68
|
+
"(the gated-hover rule).",
|
|
69
|
+
"In-menu item rules (destructive variant, inset, checkbox/radio) follow the DropdownMenu " \
|
|
70
|
+
"family contract."
|
|
71
|
+
].freeze
|
|
72
|
+
|
|
73
|
+
renders_many :menus,
|
|
74
|
+
doc: "The top-level menus. Each takes with_trigger (the menu button) plus the family item " \
|
|
75
|
+
"slots (with_item, with_checkbox_item, with_radio_group, with_sub, with_separator, ...); " \
|
|
76
|
+
"value: defaults to the menu's position.",
|
|
77
|
+
renders: ->(**options) { Menu.new(bar: self, dir: dir, **options) }
|
|
78
|
+
|
|
79
|
+
use_stimulus do
|
|
80
|
+
on :root do
|
|
81
|
+
controller :menubar do
|
|
82
|
+
register
|
|
83
|
+
value :value, from: :value_string
|
|
84
|
+
value :loop
|
|
85
|
+
# The coordinator's two event seams: the family menu
|
|
86
|
+
# controller's edge-navigate (cross-menu arrows) and closed
|
|
87
|
+
# (value bookkeeping) - custom poetry:-namespaced events.
|
|
88
|
+
action :slide_adjacent, on: "poetry:menu:edge-navigate"
|
|
89
|
+
action :on_menu_closed, on: "poetry:menu:closed"
|
|
90
|
+
end
|
|
91
|
+
controller :roving_focus do
|
|
92
|
+
register
|
|
93
|
+
# The DELTA vs in-menu roving: horizontal, manageTabindex
|
|
94
|
+
# TRUE (one tab stop for the whole bar).
|
|
95
|
+
value :orientation, :horizontal
|
|
96
|
+
value :manage_tabindex, true
|
|
97
|
+
value :loop
|
|
98
|
+
action :keydown, on: :keydown
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
# Anatomy-rendered wiring (the Menu/Sub classes build via the
|
|
102
|
+
# escape hatch; declared here for the contract).
|
|
103
|
+
on :menu_wrapper do
|
|
104
|
+
controller :menu do
|
|
105
|
+
register
|
|
106
|
+
value :open
|
|
107
|
+
value :modal, false
|
|
108
|
+
end
|
|
109
|
+
controller :popper do
|
|
110
|
+
register
|
|
111
|
+
value :side, :bottom
|
|
112
|
+
value :align, :start
|
|
113
|
+
value :side_offset, 8
|
|
114
|
+
value :align_offset, -4
|
|
115
|
+
value :avoid_collisions, true
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
on :trigger do
|
|
119
|
+
controller :menubar do
|
|
120
|
+
action :toggle, on: :pointerdown
|
|
121
|
+
action :hover_slide, on: :pointerenter
|
|
122
|
+
action :trigger_keydown, on: :keydown
|
|
123
|
+
end
|
|
124
|
+
controller(:popper) { target :anchor }
|
|
125
|
+
end
|
|
126
|
+
on :content do
|
|
127
|
+
controller(:popper) { target :content }
|
|
128
|
+
end
|
|
129
|
+
on :item do
|
|
130
|
+
controller(:menu) { action :activate, on: :click }
|
|
131
|
+
end
|
|
132
|
+
on :sub_trigger do
|
|
133
|
+
controller :menu do
|
|
134
|
+
action :sub_enter, on: :pointerenter
|
|
135
|
+
action :sub_leave, on: :pointerleave
|
|
136
|
+
action :open_sub, on: :click
|
|
137
|
+
end
|
|
138
|
+
controller(:popper) { target :anchor }
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
option :label, :string, required: true,
|
|
143
|
+
doc: "The bar's accessible name - a page may hold more than one menubar."
|
|
144
|
+
option :loop, :boolean, default: false, doc: "Wraps arrow-key movement past either end of the bar."
|
|
145
|
+
option :value, :string,
|
|
146
|
+
doc: "Server-renders the menu with this value open (values default to \"menu-<position>\")."
|
|
147
|
+
option :dir, :symbol, doc: "The reading direction; :rtl flips arrow-key movement and submenu sides."
|
|
148
|
+
|
|
149
|
+
validates :dir, inclusion: { in: DIRS }, allow_nil: true
|
|
150
|
+
|
|
151
|
+
part "menubar", "The role=menubar bar - one horizontal roving tab stop across the triggers",
|
|
152
|
+
states: {
|
|
153
|
+
"data-open" => "some menu is open (value present; the coordinator flips the pair)",
|
|
154
|
+
"data-closed" => "no menu is open"
|
|
155
|
+
}
|
|
156
|
+
part "menubar-menu", "One logical menu - a display:contents wrapper hosting the trigger + " \
|
|
157
|
+
"content pair's menu and popper controllers"
|
|
158
|
+
part "menubar-trigger", "The top-level menu button - a role=menuitem INSIDE the bar",
|
|
159
|
+
states: {
|
|
160
|
+
"data-value" => "the menu's value - the coordinator's open/close key",
|
|
161
|
+
"data-popup-open" => "its menu is open (written with aria-expanded; absence is the " \
|
|
162
|
+
"closed state)",
|
|
163
|
+
"data-disabled" => "trigger is disabled (written together with the disabled property)"
|
|
164
|
+
}
|
|
165
|
+
part "menubar-content", "The role=menu popup panel - positioning, animation, and the open " \
|
|
166
|
+
"state ride here",
|
|
167
|
+
states: {
|
|
168
|
+
"data-open" => "menu is open (presence flips the pair at runtime)",
|
|
169
|
+
"data-closed" => "menu is closed or animating out (the server-rendered state)",
|
|
170
|
+
"data-side" => { condition: "the placement side (bottom initially; popper re-writes it " \
|
|
171
|
+
"after collision flips)",
|
|
172
|
+
values: %w[top right bottom left] },
|
|
173
|
+
"data-align" => { condition: "the alignment against the trigger (start initially; popper " \
|
|
174
|
+
"re-resolves it)",
|
|
175
|
+
values: %w[start center end] }
|
|
176
|
+
},
|
|
177
|
+
vars: {
|
|
178
|
+
"--transform-origin" => "popper's anchor-facing animation origin",
|
|
179
|
+
"--available-width" => "popper: viewport space left for the panel (post-flip)",
|
|
180
|
+
"--available-height" => "popper: viewport space left for the panel (post-flip)",
|
|
181
|
+
"--anchor-width" => "popper: the trigger's measured width",
|
|
182
|
+
"--anchor-height" => "popper: the trigger's measured height"
|
|
183
|
+
}
|
|
184
|
+
part "menubar-group", "role=group semantic grouping between separators"
|
|
185
|
+
part "menubar-label", "Non-interactive heading for a run of items",
|
|
186
|
+
states: {
|
|
187
|
+
"data-inset" => "indented to align with checkbox/radio item text (inset: true)"
|
|
188
|
+
}
|
|
189
|
+
part "menubar-item", "One role=menuitem action row",
|
|
190
|
+
states: {
|
|
191
|
+
"data-variant" => "default or destructive (the danger treatment)",
|
|
192
|
+
"data-inset" => "indented to align with checkbox/radio item text (inset: true)",
|
|
193
|
+
"data-disabled" => "item is disabled (always written together with aria-disabled)"
|
|
194
|
+
}
|
|
195
|
+
part "menubar-checkbox-item", "A role=menuitemcheckbox toggle row",
|
|
196
|
+
states: {
|
|
197
|
+
"data-checked" => "checked (the controller re-writes the pair with aria-checked on " \
|
|
198
|
+
"activation)",
|
|
199
|
+
"data-unchecked" => "unchecked",
|
|
200
|
+
"data-disabled" => "item is disabled (always written together with aria-disabled)",
|
|
201
|
+
"data-close-on-select" => "per-item override of the menu's close-on-select default " \
|
|
202
|
+
"(\"false\" keeps the menu open)"
|
|
203
|
+
}
|
|
204
|
+
part "menubar-radio-group", "role=group scoping one single-select value",
|
|
205
|
+
states: {
|
|
206
|
+
"data-value" => "the selected radio value (the controller re-writes it on change)"
|
|
207
|
+
}
|
|
208
|
+
part "menubar-radio-item", "A role=menuitemradio row inside a radio group",
|
|
209
|
+
states: {
|
|
210
|
+
"data-checked" => "the selected radio (the controller re-writes the pair with aria-checked)",
|
|
211
|
+
"data-unchecked" => "not selected",
|
|
212
|
+
"data-value" => "the radio's value",
|
|
213
|
+
"data-disabled" => "item is disabled (always written together with aria-disabled)"
|
|
214
|
+
}
|
|
215
|
+
part "menubar-checkbox-item-indicator", "The check glyph slot inside checkbox items - " \
|
|
216
|
+
"aria-hidden; the item's aria-checked/data-checked pair carries state"
|
|
217
|
+
part "menubar-radio-item-indicator", "The circle glyph slot inside radio items - aria-hidden; " \
|
|
218
|
+
"the item's aria-checked/data-checked pair carries state"
|
|
219
|
+
part "menubar-separator", "role=separator rule between groups"
|
|
220
|
+
part "menubar-shortcut", "The trailing keybinding HINT - aria-hidden, never binds the key"
|
|
221
|
+
part "menubar-sub", "A submenu scope - hosts its own popper around the sub trigger/content pair"
|
|
222
|
+
part "menubar-sub-trigger", "The role=menuitem row opening its submenu",
|
|
223
|
+
states: {
|
|
224
|
+
"data-popup-open" => "its submenu is open (written with aria-expanded; absence is the " \
|
|
225
|
+
"closed state)",
|
|
226
|
+
"data-inset" => "indented to align with checkbox/radio item text (inset: true)"
|
|
227
|
+
}
|
|
228
|
+
part "menubar-sub-content", "The nested role=menu panel - its own popper content on the same " \
|
|
229
|
+
"presence machinery",
|
|
230
|
+
states: {
|
|
231
|
+
"data-open" => "submenu is open (presence flips the pair at runtime)",
|
|
232
|
+
"data-closed" => "submenu is closed (the server-rendered state)",
|
|
233
|
+
"data-side" => { condition: "the placement side (right/left by direction; popper resolves " \
|
|
234
|
+
"it at runtime)",
|
|
235
|
+
values: %w[top right bottom left] },
|
|
236
|
+
"data-align" => { condition: "the alignment against the sub-trigger (popper resolves it " \
|
|
237
|
+
"at runtime)",
|
|
238
|
+
values: %w[start center end] }
|
|
239
|
+
},
|
|
240
|
+
vars: {
|
|
241
|
+
"--transform-origin" => "popper's anchor-facing animation origin",
|
|
242
|
+
"--available-width" => "popper: viewport space left for the panel (post-flip)",
|
|
243
|
+
"--available-height" => "popper: viewport space left for the panel (post-flip)",
|
|
244
|
+
"--anchor-width" => "popper: the sub-trigger's measured width",
|
|
245
|
+
"--anchor-height" => "popper: the sub-trigger's measured height"
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# Enforces the required label and menu slots.
|
|
249
|
+
# @api private
|
|
250
|
+
def before_render
|
|
251
|
+
# The bar's accessible name is not optional - a page may hold
|
|
252
|
+
# more than one menubar.
|
|
253
|
+
raise ArgumentError, "Menubar requires label: (the bar's accessible name)" if label.blank?
|
|
254
|
+
raise ArgumentError, "Menubar requires at least one with_menu" unless menus?
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# @api private
|
|
258
|
+
def value_string = value.to_s
|
|
259
|
+
|
|
260
|
+
# @api private
|
|
261
|
+
def root_attributes
|
|
262
|
+
root = {
|
|
263
|
+
"data-slot" => "menubar", "role" => "menubar", "aria-label" => label,
|
|
264
|
+
# The bar ROOT keeps the open/closed pair so themes can key
|
|
265
|
+
# on bar-wide state.
|
|
266
|
+
(value.present? ? "data-open" : "data-closed") => ""
|
|
267
|
+
}
|
|
268
|
+
root["dir"] = dir.to_s if dir
|
|
269
|
+
html_attributes.merge_if_not_set(
|
|
270
|
+
root.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
271
|
+
)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# The bar-level tab stop is server-rendered (exactly one tabindex=0
|
|
275
|
+
# before any JS): the open menu's trigger when value: matches,
|
|
276
|
+
# otherwise the first enabled trigger.
|
|
277
|
+
# @api private
|
|
278
|
+
def tab_stop?(menu)
|
|
279
|
+
tab_stop_menu.equal?(menu)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# @api private
|
|
283
|
+
def open_menu?(menu_value)
|
|
284
|
+
value.present? && value.to_s == menu_value
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Registers a Menu part and hands back its 1-based position (the
|
|
288
|
+
# default value: "menu-<position>").
|
|
289
|
+
# @api private
|
|
290
|
+
def register_menu(menu)
|
|
291
|
+
menu_parts << menu
|
|
292
|
+
menu_parts.size
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
private
|
|
296
|
+
|
|
297
|
+
def menu_parts
|
|
298
|
+
@menu_parts ||= []
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def tab_stop_menu
|
|
302
|
+
menu_parts.find { |menu| open_menu?(menu.value) && !menu.disabled } ||
|
|
303
|
+
menu_parts.find { |menu| !menu.disabled } || menu_parts.first
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
private :value_string, :root_attributes
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# One logical menu: the trigger + content pair, hosted on a
|
|
310
|
+
# display:contents wrapper that its behavior wiring rides - erased
|
|
311
|
+
# from the bar's flex layout AND the accessibility tree, so the
|
|
312
|
+
# rendered semantics stay a flat menubar. The nested parts are
|
|
313
|
+
# anatomy, not registry components.
|
|
314
|
+
#
|
|
315
|
+
# @api private
|
|
316
|
+
class Menu < Poetry::Core::Component
|
|
317
|
+
internal_component!
|
|
318
|
+
include ItemSlots
|
|
319
|
+
|
|
320
|
+
attr_reader :value, :disabled
|
|
321
|
+
|
|
322
|
+
renders_one :trigger,
|
|
323
|
+
doc: "The top-level menu button: a real button that is role=menuitem INSIDE role=menubar, wired " \
|
|
324
|
+
"to the bar coordinator (toggle / gated hover-slide / keyboard open).",
|
|
325
|
+
renders: lambda { |**options, &block|
|
|
326
|
+
attrs = {
|
|
327
|
+
"type" => "button", "id" => trigger_id, "data-slot" => "menubar-trigger",
|
|
328
|
+
"role" => "menuitem", "tabindex" => @bar.tab_stop?(self) ? "0" : "-1",
|
|
329
|
+
"data-poetry-collection-item" => "",
|
|
330
|
+
"aria-haspopup" => "menu", "aria-expanded" => open?.to_s, "aria-controls" => content_id,
|
|
331
|
+
"data-value" => value,
|
|
332
|
+
"class" => Style.css(:trigger, class: options.delete(:class))
|
|
333
|
+
}.merge(trigger_stimulus_attributes)
|
|
334
|
+
# Trigger open state: bare data-popup-open while open, NO
|
|
335
|
+
# attribute while closed (absence IS the state).
|
|
336
|
+
attrs["data-popup-open"] = "" if open?
|
|
337
|
+
if disabled
|
|
338
|
+
attrs["disabled"] = true
|
|
339
|
+
attrs["data-disabled"] = ""
|
|
340
|
+
end
|
|
341
|
+
content_tag(:button, Poetry::Core::HTML::Attributes.merged(attrs, options)) { capture(&block) }
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
def initialize(bar:, value: nil, disabled: false, dir: nil, **extra_attributes)
|
|
345
|
+
super(extra_attributes)
|
|
346
|
+
@bar = bar
|
|
347
|
+
@disabled = disabled
|
|
348
|
+
@dir = dir
|
|
349
|
+
position = @bar.register_menu(self)
|
|
350
|
+
@value = (value || "menu-#{position}").to_s
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def before_render
|
|
354
|
+
raise ArgumentError, "Menubar menu requires with_trigger (the top-level menu button)" unless trigger?
|
|
355
|
+
raise ArgumentError, "Menubar menu requires at least one item" unless items?
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def call
|
|
359
|
+
content_tag(:div, menu_attributes) { safe_join([trigger, menu_content]) }
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def open?
|
|
363
|
+
@bar.open_menu?(value)
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def trigger_id
|
|
367
|
+
"#{instance_id}-trigger"
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def content_id
|
|
371
|
+
"#{instance_id}-content"
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
private
|
|
375
|
+
|
|
376
|
+
def menu_dir
|
|
377
|
+
@dir
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def instance_id
|
|
381
|
+
@instance_id ||= poetry_instance_id("poetry-menubar")
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# The per-menu machinery scope: the family menu controller (modal
|
|
385
|
+
# FALSE - the bar's hover-slide needs sibling triggers pressable,
|
|
386
|
+
# so no body scrim / no trap) + its popper with the menubar
|
|
387
|
+
# positioning overrides (align start / alignOffset -4 / sideOffset 8).
|
|
388
|
+
def menu_attributes
|
|
389
|
+
wiring = stimulus_attributes(:menu, :popper) do |menu, popper|
|
|
390
|
+
menu.register_controller
|
|
391
|
+
menu.with_value(:open, open?)
|
|
392
|
+
menu.with_value(:modal, false)
|
|
393
|
+
popper.register_controller
|
|
394
|
+
popper.with_value(:side, :bottom)
|
|
395
|
+
popper.with_value(:align, :start)
|
|
396
|
+
popper.with_value(:side_offset, 8)
|
|
397
|
+
popper.with_value(:align_offset, -4)
|
|
398
|
+
popper.with_value(:avoid_collisions, true)
|
|
399
|
+
end
|
|
400
|
+
{ "data-slot" => "menubar-menu", "class" => Style.css(:menu) }
|
|
401
|
+
.merge(wiring).then { |w| Poetry::Core::HTML::Attributes.merged(w, html_attributes) }
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def trigger_stimulus_attributes
|
|
405
|
+
stimulus_attributes(:menubar, :popper) do |menubar, popper|
|
|
406
|
+
menubar.with_action(:toggle, on: :pointerdown)
|
|
407
|
+
menubar.with_action(:hover_slide, on: :pointerenter)
|
|
408
|
+
menubar.with_action(:trigger_keydown, on: :keydown)
|
|
409
|
+
popper.with_target(:anchor)
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# NOT named `content` - that would shadow ViewComponent's own slot
|
|
414
|
+
# content accessor and recurse through the slot machinery.
|
|
415
|
+
def menu_content
|
|
416
|
+
attrs = {
|
|
417
|
+
"id" => content_id, "role" => "menu", "aria-orientation" => "vertical",
|
|
418
|
+
"aria-labelledby" => trigger_id, "tabindex" => "-1",
|
|
419
|
+
"data-slot" => "menubar-content", (open? ? "data-open" : "data-closed") => "",
|
|
420
|
+
# Initial placement, re-resolved live by popper on open.
|
|
421
|
+
"data-side" => "bottom", "data-align" => "start",
|
|
422
|
+
"class" => Style.css(:content)
|
|
423
|
+
}.merge(stimulus_attributes(:popper) { |popper| popper.with_target(:content) })
|
|
424
|
+
attrs["hidden"] = true unless open?
|
|
425
|
+
content_tag(:div, attrs) { safe_join(items.map(&:to_s)) }
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# role=group semantic grouping between separators - the shared
|
|
430
|
+
# menus-family anatomy wearing this family's identity.
|
|
431
|
+
#
|
|
432
|
+
# @api private
|
|
433
|
+
class Group < Poetry::Ui::Menus::Group
|
|
434
|
+
include ItemSlots
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# role=group scoping the single-select value for its radio items -
|
|
438
|
+
# the shared menus-family anatomy wearing this family's identity.
|
|
439
|
+
#
|
|
440
|
+
# @api private
|
|
441
|
+
class RadioGroup < Poetry::Ui::Menus::RadioGroup
|
|
442
|
+
include Helpers
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# A submenu scope (the full item vocabulary again, on its own
|
|
446
|
+
# positioned panel) - the shared menus-family anatomy wearing this
|
|
447
|
+
# family's identity.
|
|
448
|
+
#
|
|
449
|
+
# @api private
|
|
450
|
+
class Sub < Poetry::Ui::Menus::Sub
|
|
451
|
+
include ItemSlots
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# The builder classes behind lambda-wrapped slots: a lambda
|
|
455
|
+
# hides its return class from introspection, so the owners declare
|
|
456
|
+
# them and the registry walker recurses into each builder's own call
|
|
457
|
+
# surface (with_menu yields a Menu; with_sub a Sub). REQUIRED_SLOTS
|
|
458
|
+
# states the same facts the before_render raises enforce, so static
|
|
459
|
+
# checks flag an omission without rendering.
|
|
460
|
+
class Component
|
|
461
|
+
# Maps slot names to the classes their builder lambdas return.
|
|
462
|
+
SLOT_BUILDERS = { menu: Menu }.freeze
|
|
463
|
+
# Slots the component cannot render without; static checks read this without rendering.
|
|
464
|
+
REQUIRED_SLOTS = { menu: "at least one menu" }.freeze
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
class Menu
|
|
468
|
+
# Slots this menu cannot render without.
|
|
469
|
+
REQUIRED_SLOTS = { trigger: "the top-level menu button", item: "at least one item" }.freeze
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
class Group
|
|
473
|
+
# Slots this group cannot render without.
|
|
474
|
+
REQUIRED_SLOTS = { item: "at least one item" }.freeze
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
class RadioGroup
|
|
478
|
+
# Slots this radio group cannot render without.
|
|
479
|
+
REQUIRED_SLOTS = { radio_item: "at least one radio item" }.freeze
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
class Sub
|
|
483
|
+
# Slots this submenu cannot render without.
|
|
484
|
+
REQUIRED_SLOTS = { trigger: "the sub-menu item", item: "at least one item" }.freeze
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
module ItemSlots
|
|
488
|
+
# Maps nested slot names to the classes their builder lambdas return.
|
|
489
|
+
SLOT_BUILDERS = { sub: Sub, group: Group, radio_group: RadioGroup }.freeze
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Menubar
|
|
6
|
+
# The Menubar preview matrix: the menubar-demo.tsx port (File / Edit /
|
|
7
|
+
# View / Profiles - shortcuts, a Share submenu, checkbox view
|
|
8
|
+
# toggles, a radio profile group), plus a disabled trigger, RTL, and
|
|
9
|
+
# the server-rendered open state. Hover-slide and the cross-menu
|
|
10
|
+
# arrows are runtime behavior - the browser pass drives them.
|
|
11
|
+
class Preview < Poetry::Core::Preview::Base
|
|
12
|
+
def default
|
|
13
|
+
render_component(label: "Application menu") do |bar|
|
|
14
|
+
file_menu(bar)
|
|
15
|
+
edit_menu(bar)
|
|
16
|
+
view_menu(bar)
|
|
17
|
+
profiles_menu(bar)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# A disabled top-level menu: skipped by roving focus and the
|
|
22
|
+
# cross-menu arrows; the bar keeps exactly one tab stop.
|
|
23
|
+
def disabled_menu
|
|
24
|
+
render_component(label: "Editor menu") do |bar|
|
|
25
|
+
bar.with_menu do |menu|
|
|
26
|
+
menu.with_trigger { "File" }
|
|
27
|
+
menu.with_item { "New" }
|
|
28
|
+
end
|
|
29
|
+
bar.with_menu(disabled: true) do |menu|
|
|
30
|
+
menu.with_trigger { "Team" }
|
|
31
|
+
menu.with_item { "Invite" }
|
|
32
|
+
end
|
|
33
|
+
bar.with_menu do |menu|
|
|
34
|
+
menu.with_trigger { "Help" }
|
|
35
|
+
menu.with_item { "About" }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Bar roving + the cross-menu edge moves flip under RTL; the
|
|
41
|
+
# submenu side flips with them.
|
|
42
|
+
def rtl
|
|
43
|
+
render_component(label: "قائمة التطبيق", dir: :rtl) do |bar|
|
|
44
|
+
bar.with_menu do |menu|
|
|
45
|
+
menu.with_trigger { "ملف" }
|
|
46
|
+
menu.with_item { "جديد" }
|
|
47
|
+
menu.with_sub do |sub|
|
|
48
|
+
sub.with_trigger { "مشاركة" }
|
|
49
|
+
sub.with_item { "بريد إلكتروني" }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
bar.with_menu do |menu|
|
|
53
|
+
menu.with_trigger { "تحرير" }
|
|
54
|
+
menu.with_item { "تراجع" }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Server-rendered open state (controllable-state: value: names the
|
|
60
|
+
# open menu; the coordinator reconciles on connect).
|
|
61
|
+
def open
|
|
62
|
+
render_component(label: "Application menu", value: "file") do |bar|
|
|
63
|
+
bar.with_menu(value: "file") do |menu|
|
|
64
|
+
menu.with_trigger { "File" }
|
|
65
|
+
menu.with_item(shortcut: "⌘T") { "New Tab" }
|
|
66
|
+
menu.with_item { "New Window" }
|
|
67
|
+
end
|
|
68
|
+
bar.with_menu(value: "edit") do |menu|
|
|
69
|
+
menu.with_trigger { "Edit" }
|
|
70
|
+
menu.with_item { "Undo" }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# A labelled, grouped menu - the label heading + role=group wrapper.
|
|
76
|
+
def grouped_with_label
|
|
77
|
+
render_component(label: "Grouped") do |bar|
|
|
78
|
+
bar.with_menu do |menu|
|
|
79
|
+
menu.with_trigger { "File" }
|
|
80
|
+
menu.with_label { "Recent" }
|
|
81
|
+
menu.with_group do |group|
|
|
82
|
+
group.with_item { "Report.pdf" }
|
|
83
|
+
group.with_item { "Notes.txt" }
|
|
84
|
+
end
|
|
85
|
+
menu.with_separator
|
|
86
|
+
menu.with_checkbox_item(checked: true, disabled: true) { "Autosave" }
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def file_menu(bar)
|
|
94
|
+
bar.with_menu do |menu|
|
|
95
|
+
menu.with_trigger { "File" }
|
|
96
|
+
menu.with_item(shortcut: "⌘T") { "New Tab" }
|
|
97
|
+
menu.with_item(shortcut: "⌘N") { "New Window" }
|
|
98
|
+
menu.with_item(disabled: true) { "New Incognito Window" }
|
|
99
|
+
menu.with_separator
|
|
100
|
+
menu.with_sub do |sub|
|
|
101
|
+
sub.with_trigger { "Share" }
|
|
102
|
+
sub.with_item { "Email link" }
|
|
103
|
+
sub.with_item { "Messages" }
|
|
104
|
+
sub.with_item { "Notes" }
|
|
105
|
+
end
|
|
106
|
+
menu.with_separator
|
|
107
|
+
menu.with_item(shortcut: "⌘P") { "Print..." }
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def edit_menu(bar)
|
|
112
|
+
bar.with_menu do |menu|
|
|
113
|
+
menu.with_trigger { "Edit" }
|
|
114
|
+
menu.with_item(shortcut: "⌘Z") { "Undo" }
|
|
115
|
+
menu.with_item(shortcut: "⇧⌘Z") { "Redo" }
|
|
116
|
+
menu.with_separator
|
|
117
|
+
menu.with_sub do |sub|
|
|
118
|
+
sub.with_trigger { "Find" }
|
|
119
|
+
sub.with_item { "Search the web" }
|
|
120
|
+
sub.with_separator
|
|
121
|
+
sub.with_item { "Find..." }
|
|
122
|
+
sub.with_item { "Find Next" }
|
|
123
|
+
sub.with_item { "Find Previous" }
|
|
124
|
+
end
|
|
125
|
+
menu.with_separator
|
|
126
|
+
menu.with_item { "Cut" }
|
|
127
|
+
menu.with_item { "Copy" }
|
|
128
|
+
menu.with_item { "Paste" }
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def view_menu(bar)
|
|
133
|
+
bar.with_menu do |menu|
|
|
134
|
+
menu.with_trigger { "View" }
|
|
135
|
+
menu.with_checkbox_item(close_on_select: false) { "Always Show Bookmarks Bar" }
|
|
136
|
+
menu.with_checkbox_item(checked: true, close_on_select: false) { "Always Show Full URLs" }
|
|
137
|
+
menu.with_separator
|
|
138
|
+
menu.with_item(inset: true, shortcut: "⌘R") { "Reload" }
|
|
139
|
+
menu.with_item(inset: true, disabled: true, shortcut: "⇧⌘R") { "Force Reload" }
|
|
140
|
+
menu.with_separator
|
|
141
|
+
menu.with_item(inset: true) { "Toggle Fullscreen" }
|
|
142
|
+
menu.with_separator
|
|
143
|
+
menu.with_item(inset: true) { "Hide Sidebar" }
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def profiles_menu(bar)
|
|
148
|
+
bar.with_menu do |menu|
|
|
149
|
+
menu.with_trigger { "Profiles" }
|
|
150
|
+
menu.with_radio_group(value: "benoit") do |group|
|
|
151
|
+
group.with_radio_item(value: "andy") { "Andy" }
|
|
152
|
+
group.with_radio_item(value: "benoit") { "Benoit" }
|
|
153
|
+
group.with_radio_item(value: "luis") { "Luis" }
|
|
154
|
+
end
|
|
155
|
+
menu.with_separator
|
|
156
|
+
menu.with_item(inset: true) { "Edit..." }
|
|
157
|
+
menu.with_separator
|
|
158
|
+
menu.with_item(inset: true) { "Add Profile..." }
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|