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,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Menubar
|
|
6
|
+
# Re-expressed through the cn-* theme layer, the source quirks
|
|
7
|
+
# preserved in the theme rules verbatim (content omits
|
|
8
|
+
# data-closed:animate-out, checkbox/radio round with rounded-xs, the
|
|
9
|
+
# sub-trigger has no [&_svg] block). :menu keeps display:contents
|
|
10
|
+
# inline - the one poetry addition (controller host erased from
|
|
11
|
+
# layout + the a11y tree).
|
|
12
|
+
class Style < Poetry::Core::Style
|
|
13
|
+
base "cn-menubar flex items-center"
|
|
14
|
+
|
|
15
|
+
# POETRY ADDITION: the logical Menu grouping needs a host element
|
|
16
|
+
# for its behavior wiring; display:contents erases it from layout
|
|
17
|
+
# and the a11y tree (the source anatomy renders no element here).
|
|
18
|
+
element :menu, "contents"
|
|
19
|
+
|
|
20
|
+
element :trigger, "cn-menubar-trigger flex items-center outline-hidden select-none"
|
|
21
|
+
|
|
22
|
+
element :content, "cn-menubar-content cn-menu-translucent z-50 " \
|
|
23
|
+
"origin-(--transform-origin) overflow-hidden"
|
|
24
|
+
|
|
25
|
+
# group/menubar-item: bare marker, no CSS - the vega theme's
|
|
26
|
+
# shortcut re-color (group-focus/menubar-item) keys on it.
|
|
27
|
+
element :item, "cn-menubar-item group/menubar-item relative flex cursor-default items-center " \
|
|
28
|
+
"outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 " \
|
|
29
|
+
"data-disabled:opacity-50 data-disabled:pointer-events-none"
|
|
30
|
+
|
|
31
|
+
element :checkbox_item, "cn-menubar-checkbox-item relative flex cursor-default items-center outline-hidden " \
|
|
32
|
+
"select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 data-disabled:opacity-50 " \
|
|
33
|
+
"data-disabled:pointer-events-none"
|
|
34
|
+
|
|
35
|
+
element :radio_item, "cn-menubar-radio-item relative flex cursor-default items-center outline-hidden " \
|
|
36
|
+
"select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 data-disabled:opacity-50 " \
|
|
37
|
+
"data-disabled:pointer-events-none"
|
|
38
|
+
|
|
39
|
+
element :label, "cn-menubar-label"
|
|
40
|
+
|
|
41
|
+
element :separator, "cn-menubar-separator -mx-1 h-px my-1"
|
|
42
|
+
|
|
43
|
+
element :shortcut, "cn-menubar-shortcut"
|
|
44
|
+
|
|
45
|
+
# DELTA vs the family: outline-none (not -hidden), no [&_svg] block
|
|
46
|
+
# (source-exact).
|
|
47
|
+
element :sub_trigger, "cn-menubar-sub-trigger flex cursor-default items-center " \
|
|
48
|
+
"outline-none select-none"
|
|
49
|
+
|
|
50
|
+
element :sub_content, "cn-menubar-sub-content z-50 " \
|
|
51
|
+
"origin-(--transform-origin) overflow-hidden"
|
|
52
|
+
|
|
53
|
+
# Source-exact wrapper span (anonymous in the ported source; poetry names
|
|
54
|
+
# it menubar-item-indicator - the self-identification rule).
|
|
55
|
+
element :item_indicator, "pointer-events-none absolute " \
|
|
56
|
+
"flex items-center justify-center"
|
|
57
|
+
|
|
58
|
+
# POETRY ADDITION (family convention): the indicator stays in the
|
|
59
|
+
# DOM; the parent item's data-checked/data-unchecked pair drives
|
|
60
|
+
# visibility.
|
|
61
|
+
element :item_indicator_state, "[[data-unchecked]>&]:hidden"
|
|
62
|
+
|
|
63
|
+
# The source's inline lucide icon classes, named per part. DELTA:
|
|
64
|
+
# the menubar sub chevron is ml-auto h-4 w-4 (source-exact).
|
|
65
|
+
element :indicator_check, "size-4"
|
|
66
|
+
element :indicator_circle, "size-2 fill-current"
|
|
67
|
+
element :sub_indicator, "ml-auto h-4 w-4"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Gives a menu family (DropdownMenu, ContextMenu, Menubar) one shared
|
|
6
|
+
# implementation of the menu item union and its anatomy classes.
|
|
7
|
+
# Family identity - the data-slot prefix, the Style dictionary, the
|
|
8
|
+
# error noun, the builder classes - resolves through the including
|
|
9
|
+
# family's namespace at render time, never through constants named
|
|
10
|
+
# here, so one implementation serves every family. Each family keeps
|
|
11
|
+
# a thin ItemSlots module carrying its own SLOT_BUILDERS and, where
|
|
12
|
+
# needed, a per-kind indicator override.
|
|
13
|
+
module Menus
|
|
14
|
+
# The closed vocabulary for the item variant axis.
|
|
15
|
+
ITEM_VARIANTS = %i[default destructive].freeze
|
|
16
|
+
|
|
17
|
+
# Shared attribute builders for the item union - mixed into every
|
|
18
|
+
# menu level (the family roots and the nested Sub / Group /
|
|
19
|
+
# RadioGroup parts) so the whole family renders the same anatomy
|
|
20
|
+
# through the same Builder.
|
|
21
|
+
module Helpers
|
|
22
|
+
include FamilyIdentity
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# menu items are role=menuitem DIVs (APG-exact) - no native
|
|
27
|
+
# disabled, so aria-disabled and data-disabled are written TOGETHER
|
|
28
|
+
# (the controller filters on either; CSS styles data-[disabled]).
|
|
29
|
+
def apply_item_flags(attrs, inset: false, disabled: false, text_value: nil, close_on_select: nil)
|
|
30
|
+
attrs["data-inset"] = "true" if inset
|
|
31
|
+
if disabled
|
|
32
|
+
attrs["aria-disabled"] = "true"
|
|
33
|
+
attrs["data-disabled"] = ""
|
|
34
|
+
end
|
|
35
|
+
attrs["data-text-value"] = text_value if text_value
|
|
36
|
+
attrs["data-close-on-select"] = close_on_select.to_s unless close_on_select.nil?
|
|
37
|
+
attrs
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Every menu item's activation, via the public escape hatch (each
|
|
41
|
+
# family Component's :item declaration mirrors it; the contract
|
|
42
|
+
# gate keeps the two in sync).
|
|
43
|
+
def item_action_attributes
|
|
44
|
+
stimulus_attributes(:menu) { |menu| menu.with_action(:activate, on: :click) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The named check/circle glyph wrapper (the source's two slots:
|
|
48
|
+
# <family>-checkbox-item-indicator / <family>-radio-item-indicator).
|
|
49
|
+
# State is carried by
|
|
50
|
+
# the parent item's aria-checked/data-checked pair; the glyph
|
|
51
|
+
# itself stays decorative (Icon defaults to aria-hidden).
|
|
52
|
+
def item_indicator(icon, icon_class, kind)
|
|
53
|
+
extra = [family_style.css(:item_indicator_state), indicator_extra_class(kind)].compact
|
|
54
|
+
content_tag(:span, "data-slot" => "#{family_slot_prefix}-#{kind}-item-indicator",
|
|
55
|
+
"class" => family_style.css(:item_indicator, class: extra)) do
|
|
56
|
+
render(Icon::Component.new(name: icon, class: icon_class))
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The one substantive family fork: Menubar themes its checkbox and
|
|
61
|
+
# radio indicators separately (a per-kind cn class rides along);
|
|
62
|
+
# the siblings share one treatment.
|
|
63
|
+
def indicator_extra_class(_kind)
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# A VISUAL keybinding hint only - poetry does not bind the key
|
|
68
|
+
# (family rule), so the span is aria-hidden presentation.
|
|
69
|
+
def shortcut_span(text)
|
|
70
|
+
return if text.blank?
|
|
71
|
+
|
|
72
|
+
content_tag(:span, text, "data-slot" => "#{family_slot_prefix}-shortcut", "aria-hidden" => "true",
|
|
73
|
+
"class" => family_style.css(:shortcut))
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The item UNION every menu level accepts: item | checkbox_item |
|
|
78
|
+
# radio_group | label | separator | group | sub - one ordered
|
|
79
|
+
# collection (interleaving preserved), polymorphic setters named per
|
|
80
|
+
# part. Included (through each family's thin ItemSlots) by the family
|
|
81
|
+
# roots, Sub (recursive submenus), and Group.
|
|
82
|
+
module ItemSlots
|
|
83
|
+
extend ActiveSupport::Concern
|
|
84
|
+
include Helpers
|
|
85
|
+
|
|
86
|
+
included do
|
|
87
|
+
renders_many :items,
|
|
88
|
+
doc: "The menu composition API: one ordered items collection accepting seven kinds, " \
|
|
89
|
+
"interleaved in call order - with_item an action row (href: renders it as a real link; " \
|
|
90
|
+
"submit: as a real submit button) with_checkbox_item a toggleable checked/unchecked row " \
|
|
91
|
+
"with_radio_group a single-select scope; add rows inside it via with_radio_item(value:) " \
|
|
92
|
+
"with_label a non-interactive heading for a run of items with_separator a horizontal " \
|
|
93
|
+
"rule between runs with_group semantic grouping around the same union, one level down " \
|
|
94
|
+
"with_sub a nested submenu: its own with_trigger plus the same union, recursively",
|
|
95
|
+
types: {
|
|
96
|
+
item: { renders: ->(**options, &block) { item_part(**options, &block) }, as: :item },
|
|
97
|
+
checkbox_item: {
|
|
98
|
+
renders: ->(**options, &block) { checkbox_item_part(**options, &block) }, as: :checkbox_item
|
|
99
|
+
},
|
|
100
|
+
radio_group: { renders: lambda { |**options|
|
|
101
|
+
family_namespace::RadioGroup.new(**options)
|
|
102
|
+
}, as: :radio_group },
|
|
103
|
+
label: { renders: ->(**options, &block) { label_part(**options, &block) }, as: :label },
|
|
104
|
+
separator: { renders: ->(**options) { separator_part(**options) }, as: :separator },
|
|
105
|
+
group: { renders: lambda { |**options|
|
|
106
|
+
family_namespace::Group.new(dir: menu_dir, **options)
|
|
107
|
+
}, as: :group },
|
|
108
|
+
sub: { renders: lambda { |**options|
|
|
109
|
+
family_namespace::Sub.new(dir: menu_dir, **options)
|
|
110
|
+
}, as: :sub }
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
# Builds one action row - a role=menuitem div, or a real <a> /
|
|
117
|
+
# submit <button> when href: / submit: is given.
|
|
118
|
+
def item_part(**options, &)
|
|
119
|
+
variant = (options.delete(:variant) || :default).to_sym
|
|
120
|
+
unless ITEM_VARIANTS.include?(variant)
|
|
121
|
+
raise ArgumentError,
|
|
122
|
+
"unknown #{family_name} item variant #{variant.inspect} - known: #{ITEM_VARIANTS.join(", ")}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
shortcut = options.delete(:shortcut)
|
|
126
|
+
# A link/submit item IS the interactive element (role=menuitem on the
|
|
127
|
+
# <a> or the <button>), never nested inside a menuitem div - one
|
|
128
|
+
# interactive element, so it keeps the APG contract without tripping
|
|
129
|
+
# nested-interactive a11y. A disabled link/submit drops its target and
|
|
130
|
+
# renders as the plain div (anchors/submit-buttons have no menu meaning
|
|
131
|
+
# once inert).
|
|
132
|
+
href = options.delete(:href)
|
|
133
|
+
external = options.delete(:external)
|
|
134
|
+
submit = options.delete(:submit)
|
|
135
|
+
method = options.delete(:method)
|
|
136
|
+
disabled = options[:disabled]
|
|
137
|
+
attrs = {
|
|
138
|
+
"data-slot" => "#{family_slot_prefix}-item", "role" => "menuitem", "tabindex" => "-1",
|
|
139
|
+
"data-poetry-collection-item" => "", "data-variant" => variant,
|
|
140
|
+
"class" => family_style.css(:item, class: options.delete(:class))
|
|
141
|
+
}.merge(item_action_attributes)
|
|
142
|
+
apply_item_flags(attrs, **options.extract!(:inset, :disabled, :text_value, :close_on_select))
|
|
143
|
+
content = safe_join([capture(&), shortcut_span(shortcut)].compact)
|
|
144
|
+
|
|
145
|
+
if submit && !disabled
|
|
146
|
+
# form: is RESERVED on submit items - the display:contents form
|
|
147
|
+
# IS the a11y mechanism (the button is the menuitem).
|
|
148
|
+
options.delete(:form)
|
|
149
|
+
options.delete("form")
|
|
150
|
+
# button_to's form is display:contents (transparent); the submit
|
|
151
|
+
# button IS the menuitem, POSTing with CSRF + the method override -
|
|
152
|
+
# the a11y-clean way to run a DELETE/POST action from a menu. The
|
|
153
|
+
# block form renders a <button> (the string form renders an <input>).
|
|
154
|
+
return helpers.button_to(submit,
|
|
155
|
+
{ method: method || :post, form: { class: "contents" } }
|
|
156
|
+
.merge(Poetry::Core::HTML::Attributes.merged(attrs, options))) { content }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
link = href && !disabled
|
|
160
|
+
if link
|
|
161
|
+
attrs["href"] = href
|
|
162
|
+
if external
|
|
163
|
+
attrs["target"] = "_blank"
|
|
164
|
+
attrs["rel"] = "noopener noreferrer"
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
content_tag(link ? :a : :div, Poetry::Core::HTML::Attributes.merged(attrs, options)) { content }
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Builds one role=menuitemcheckbox toggle row.
|
|
171
|
+
def checkbox_item_part(**options, &)
|
|
172
|
+
checked = options.delete(:checked) || false
|
|
173
|
+
shortcut = options.delete(:shortcut)
|
|
174
|
+
attrs = {
|
|
175
|
+
"data-slot" => "#{family_slot_prefix}-checkbox-item", "role" => "menuitemcheckbox", "tabindex" => "-1",
|
|
176
|
+
"data-poetry-collection-item" => "",
|
|
177
|
+
# aria-checked and the data-checked/data-unchecked pair written
|
|
178
|
+
# TOGETHER, never separately.
|
|
179
|
+
"aria-checked" => checked.to_s, (checked ? "data-checked" : "data-unchecked") => "",
|
|
180
|
+
"class" => family_style.css(:checkbox_item, class: options.delete(:class))
|
|
181
|
+
}.merge(item_action_attributes)
|
|
182
|
+
apply_item_flags(attrs, **options.extract!(:disabled, :text_value, :close_on_select))
|
|
183
|
+
content_tag(:div, Poetry::Core::HTML::Attributes.merged(attrs, options)) do
|
|
184
|
+
safe_join([item_indicator(:check, family_style.css(:indicator_check), :checkbox),
|
|
185
|
+
capture(&), shortcut_span(shortcut)].compact)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Builds the non-interactive heading row.
|
|
190
|
+
def label_part(inset: false, **options, &)
|
|
191
|
+
attrs = {
|
|
192
|
+
"data-slot" => "#{family_slot_prefix}-label",
|
|
193
|
+
"class" => family_style.css(:label, class: options.delete(:class))
|
|
194
|
+
}
|
|
195
|
+
attrs["data-inset"] = "true" if inset
|
|
196
|
+
content_tag(:div, Poetry::Core::HTML::Attributes.merged(attrs, options)) { capture(&) }
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Builds the role=separator rule.
|
|
200
|
+
def separator_part(**options)
|
|
201
|
+
attrs = {
|
|
202
|
+
"data-slot" => "#{family_slot_prefix}-separator", "role" => "separator",
|
|
203
|
+
"aria-orientation" => "horizontal",
|
|
204
|
+
"class" => family_style.css(:separator, class: options.delete(:class))
|
|
205
|
+
}
|
|
206
|
+
content_tag(:div, nil, Poetry::Core::HTML::Attributes.merged(attrs, options))
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# role=group semantic grouping between separators - the same item
|
|
211
|
+
# union, one level down.
|
|
212
|
+
#
|
|
213
|
+
# @api private
|
|
214
|
+
class Group < Poetry::Core::Component
|
|
215
|
+
internal_component!
|
|
216
|
+
include ItemSlots
|
|
217
|
+
|
|
218
|
+
def initialize(dir: nil, **extra_attributes)
|
|
219
|
+
super(extra_attributes)
|
|
220
|
+
@dir = dir
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def before_render
|
|
224
|
+
raise ArgumentError, "#{family_name} group requires at least one item" unless items?
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def call
|
|
228
|
+
attrs = { "data-slot" => "#{family_slot_prefix}-group", "role" => "group" }
|
|
229
|
+
content_tag(:div, Poetry::Core::HTML::Attributes.merged(attrs, html_attributes)) { safe_join(items.map(&:to_s)) }
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
private
|
|
233
|
+
|
|
234
|
+
def menu_dir
|
|
235
|
+
@dir
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# role=group scoping the single-select value for its radio items -
|
|
240
|
+
# radio items exist only through this group; duplicate values raise.
|
|
241
|
+
#
|
|
242
|
+
# @api private
|
|
243
|
+
class RadioGroup < Poetry::Core::Component
|
|
244
|
+
internal_component!
|
|
245
|
+
include Helpers
|
|
246
|
+
|
|
247
|
+
attr_reader :group_value
|
|
248
|
+
|
|
249
|
+
renders_many :radio_items,
|
|
250
|
+
doc: "One role=menuitemradio row; value: must be unique within the group.",
|
|
251
|
+
renders: lambda { |value:, disabled: false, text_value: nil,
|
|
252
|
+
close_on_select: nil, shortcut: nil, **options, &block|
|
|
253
|
+
key = value.to_s
|
|
254
|
+
unless @seen_values.add?(key)
|
|
255
|
+
raise ArgumentError, "duplicate #{family_name} radio value #{key.inspect} - values must be " \
|
|
256
|
+
"unique within their radio group"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
checked = !group_value.nil? && key == group_value
|
|
260
|
+
attrs = {
|
|
261
|
+
"data-slot" => "#{family_slot_prefix}-radio-item", "role" => "menuitemradio",
|
|
262
|
+
"tabindex" => "-1", "data-poetry-collection-item" => "", "data-value" => key,
|
|
263
|
+
"aria-checked" => checked.to_s, (checked ? "data-checked" : "data-unchecked") => "",
|
|
264
|
+
"class" => family_style.css(:radio_item, class: options.delete(:class))
|
|
265
|
+
}.merge(item_action_attributes)
|
|
266
|
+
apply_item_flags(attrs, disabled:, text_value:, close_on_select:)
|
|
267
|
+
content_tag(:div, Poetry::Core::HTML::Attributes.merged(attrs, options)) do
|
|
268
|
+
safe_join([item_indicator(:circle, family_style.css(:indicator_circle), :radio),
|
|
269
|
+
capture(&block), shortcut_span(shortcut)].compact)
|
|
270
|
+
end
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
def initialize(value: nil, **extra_attributes)
|
|
274
|
+
super(extra_attributes)
|
|
275
|
+
@group_value = value&.to_s
|
|
276
|
+
@seen_values = Set.new
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def before_render
|
|
280
|
+
raise ArgumentError, "#{family_name} radio group requires at least one with_radio_item" unless radio_items?
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def call
|
|
284
|
+
attrs = { "data-slot" => "#{family_slot_prefix}-radio-group", "role" => "group" }
|
|
285
|
+
attrs["data-value"] = group_value if group_value
|
|
286
|
+
content_tag(:div, Poetry::Core::HTML::Attributes.merged(attrs, html_attributes)) { safe_join(radio_items.map(&:to_s)) }
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# A submenu scope - its own positioning instance (trigger anchors
|
|
291
|
+
# content; side flips under RTL) around the same item union, recursively.
|
|
292
|
+
#
|
|
293
|
+
# @api private
|
|
294
|
+
class Sub < Poetry::Core::Component
|
|
295
|
+
internal_component!
|
|
296
|
+
include ItemSlots
|
|
297
|
+
|
|
298
|
+
renders_one :trigger,
|
|
299
|
+
doc: "role=menuitem in the PARENT's collection + aria wiring to its own sub-content; the " \
|
|
300
|
+
"trailing chevron ships built in (flips via logical ml-auto under RTL).",
|
|
301
|
+
renders: lambda { |inset: false, disabled: false, text_value: nil, **options, &block|
|
|
302
|
+
attrs = {
|
|
303
|
+
"id" => trigger_id, "data-slot" => "#{family_slot_prefix}-sub-trigger", "role" => "menuitem",
|
|
304
|
+
"tabindex" => "-1", "data-poetry-collection-item" => "",
|
|
305
|
+
"aria-haspopup" => "menu", "aria-expanded" => "false", "aria-controls" => content_id,
|
|
306
|
+
"class" => family_style.css(:sub_trigger, class: options.delete(:class))
|
|
307
|
+
}.merge(sub_trigger_stimulus_attributes)
|
|
308
|
+
apply_item_flags(attrs, inset:, disabled:, text_value:)
|
|
309
|
+
content_tag(:div, Poetry::Core::HTML::Attributes.merged(attrs, options)) do
|
|
310
|
+
safe_join([capture(&block), chevron])
|
|
311
|
+
end
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
def initialize(dir: nil, **extra_attributes)
|
|
315
|
+
super(extra_attributes)
|
|
316
|
+
@dir = dir
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def before_render
|
|
320
|
+
raise ArgumentError, "#{family_name} sub requires with_trigger (the sub-menu item)" unless trigger?
|
|
321
|
+
raise ArgumentError, "#{family_name} sub requires at least one item" unless items?
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def call
|
|
325
|
+
content_tag(:div, sub_attributes) { safe_join([trigger, sub_content]) }
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def trigger_id
|
|
329
|
+
"#{instance_id}-trigger"
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def content_id
|
|
333
|
+
"#{instance_id}-content"
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
private
|
|
337
|
+
|
|
338
|
+
def menu_dir
|
|
339
|
+
@dir
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def rtl?
|
|
343
|
+
@dir == :rtl
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def instance_id
|
|
347
|
+
@instance_id ||= poetry_instance_id("poetry-#{family_slot_prefix}-sub")
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def sub_attributes
|
|
351
|
+
attrs = { "data-slot" => "#{family_slot_prefix}-sub" }.merge(
|
|
352
|
+
stimulus_attributes(:popper) do |popper|
|
|
353
|
+
popper.register_controller
|
|
354
|
+
popper.with_value(:side, rtl? ? :left : :right)
|
|
355
|
+
popper.with_value(:align, :start)
|
|
356
|
+
end
|
|
357
|
+
)
|
|
358
|
+
Poetry::Core::HTML::Attributes.merged(attrs, html_attributes)
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def sub_content
|
|
362
|
+
attrs = {
|
|
363
|
+
"id" => content_id, "role" => "menu", "aria-orientation" => "vertical",
|
|
364
|
+
"aria-labelledby" => trigger_id, "tabindex" => "-1",
|
|
365
|
+
"data-slot" => "#{family_slot_prefix}-sub-content", "data-closed" => "", "hidden" => true,
|
|
366
|
+
"class" => family_style.css(:sub_content)
|
|
367
|
+
}.merge(stimulus_attributes(:popper) { |popper| popper.with_target(:content) })
|
|
368
|
+
content_tag(:div, attrs) { safe_join(items.map(&:to_s)) }
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def sub_trigger_stimulus_attributes
|
|
372
|
+
stimulus_attributes(:menu, :popper) do |menu, popper|
|
|
373
|
+
menu.with_action(:sub_enter, on: :pointerenter)
|
|
374
|
+
menu.with_action(:sub_leave, on: :pointerleave)
|
|
375
|
+
menu.with_action(:open_sub, on: :click)
|
|
376
|
+
popper.with_target(:anchor)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def chevron
|
|
381
|
+
render(Icon::Component.new(name: :"chevron-right", class: family_style.css(:sub_indicator)))
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<% if avatar? %><div data-slot="message-avatar" class="<%= css(:avatar) %>"><%= avatar %></div><% end %>
|
|
3
|
+
<div data-slot="message-content" class="<%= css(:content) %>">
|
|
4
|
+
<% if header? %><div data-slot="message-header" class="<%= css(:header) %>"><%= header %></div><% end %>
|
|
5
|
+
<%= content %>
|
|
6
|
+
<% if footer? %><div data-slot="message-footer" class="<%= css(:footer) %>"><%= footer %></div><% end %>
|
|
7
|
+
</div>
|
|
8
|
+
<% end %>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# One chat turn's row in a conversation transcript.
|
|
6
|
+
module Message
|
|
7
|
+
# One chat turn's row: an avatar beside a content column of
|
|
8
|
+
# header, message bubbles (the body block), and footer. align:
|
|
9
|
+
# :end mirrors the row for the local user's side. Purely
|
|
10
|
+
# presentational - no JavaScript.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# render Poetry::Ui::Message::Component.new do |message|
|
|
14
|
+
# message.with_avatar { "AI" }
|
|
15
|
+
# message.with_header { "Assistant" }
|
|
16
|
+
# tag.div("Here's the plan for today.")
|
|
17
|
+
# end
|
|
18
|
+
class Component < Poetry::Core::Component
|
|
19
|
+
# The closed vocabulary for the align axis.
|
|
20
|
+
ALIGNS = %i[start end].freeze
|
|
21
|
+
|
|
22
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
23
|
+
AGENT_RULES = [
|
|
24
|
+
"One Message per turn: avatar slot + header/footer slots; the body block holds the Bubbles.",
|
|
25
|
+
"align: :end is the local user's side - set it on the Message, never on the Bubbles inside.",
|
|
26
|
+
"The avatar slot is decorative context by default - pass meaningful sender identity in the header.",
|
|
27
|
+
"Timestamps and delivery state belong in the footer slot (it lifts the avatar automatically)."
|
|
28
|
+
].freeze
|
|
29
|
+
|
|
30
|
+
renders_one :avatar, doc: "The sender's avatar, kept beside the content column - decorative context; put " \
|
|
31
|
+
"meaningful sender identity in the header."
|
|
32
|
+
renders_one :header, doc: "The sender identity line above the bubbles."
|
|
33
|
+
renders_one :footer, doc: "Timestamps / delivery state below the bubbles."
|
|
34
|
+
|
|
35
|
+
option :align, :symbol, default: :start,
|
|
36
|
+
doc: "Which side the row sits on; :end mirrors it for the local user's side."
|
|
37
|
+
|
|
38
|
+
validates :align, inclusion: { in: ALIGNS }
|
|
39
|
+
|
|
40
|
+
part "message", "The chat-row root - avatar plus a content column; align: :end " \
|
|
41
|
+
"mirrors the row for the local user's side",
|
|
42
|
+
states: {
|
|
43
|
+
"data-align" => { condition: "always - the resolved align",
|
|
44
|
+
values: ALIGNS.map(&:to_s) }
|
|
45
|
+
}
|
|
46
|
+
part "message-avatar", "The avatar slot's box, kept out of the content column"
|
|
47
|
+
part "message-content", "The content column - header, the body block (the Bubbles), " \
|
|
48
|
+
"footer"
|
|
49
|
+
part "message-header", "Sender identity line above the bubbles (header slot)"
|
|
50
|
+
part "message-footer", "Timestamps / delivery state below the bubbles (footer slot - " \
|
|
51
|
+
"it lifts the avatar)"
|
|
52
|
+
|
|
53
|
+
# @api private
|
|
54
|
+
def root_attributes
|
|
55
|
+
html_attributes.merge_if_not_set(
|
|
56
|
+
{ "data-slot" => "message", "data-align" => align }.merge(component_data_attributes)
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private :root_attributes
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Message
|
|
6
|
+
# The Message preview matrix.
|
|
7
|
+
class Preview < Poetry::Core::Preview::Base
|
|
8
|
+
def default
|
|
9
|
+
render_component do |message|
|
|
10
|
+
message.with_avatar { "AI" }
|
|
11
|
+
message.with_header { "Assistant" }
|
|
12
|
+
tag.div("Here's the plan for today.", class: "rounded-xl bg-muted px-3 py-2 w-fit")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def align_end
|
|
17
|
+
render_component(align: :end) do |message|
|
|
18
|
+
message.with_footer { "Read 10:42" }
|
|
19
|
+
tag.div("Sounds good!", class: "rounded-xl bg-primary text-primary-foreground px-3 py-2 w-fit")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def with_footer_lifts_avatar
|
|
24
|
+
render_component do |message|
|
|
25
|
+
message.with_avatar { "AI" }
|
|
26
|
+
message.with_footer { "10:41" }
|
|
27
|
+
tag.div("Footer present - the avatar lifts.", class: "rounded-xl bg-muted px-3 py-2 w-fit")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Message
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The :has()/group
|
|
7
|
+
# context choreography stays inline (footer presence lifts the
|
|
8
|
+
# avatar; the align axis flips rows and self-alignment); type,
|
|
9
|
+
# spacing, and the ghost-Bubble padding collapse ride the theme.
|
|
10
|
+
class Style < Poetry::Core::Style
|
|
11
|
+
base "cn-message group/message relative flex w-full min-w-0 data-[align=end]:flex-row-reverse"
|
|
12
|
+
|
|
13
|
+
element :group, "cn-message-group flex min-w-0 flex-col"
|
|
14
|
+
|
|
15
|
+
element :avatar, "cn-message-avatar flex w-fit shrink-0 items-center justify-center self-end " \
|
|
16
|
+
"overflow-hidden rounded-full bg-muted " \
|
|
17
|
+
"group-has-data-[slot=message-footer]/message:-translate-y-8"
|
|
18
|
+
|
|
19
|
+
element :content, "cn-message-content flex w-full min-w-0 flex-col wrap-break-word " \
|
|
20
|
+
"group-data-[align=end]/message:*:data-slot:self-end"
|
|
21
|
+
|
|
22
|
+
element :header, "cn-message-header flex max-w-full min-w-0 items-center"
|
|
23
|
+
|
|
24
|
+
element :footer, "cn-message-footer flex max-w-full min-w-0 items-center " \
|
|
25
|
+
"group-data-[align=end]/message:justify-end"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<div <%= tag.attributes(viewport_attributes) %>>
|
|
3
|
+
<div <%= tag.attributes(content_attributes) %>>
|
|
4
|
+
<%= content %>
|
|
5
|
+
<div <%= tag.attributes(spacer_attributes) %>></div>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
<% if jump_button %>
|
|
9
|
+
<%= render Poetry::Ui::Button::Component.new(variant: :secondary, size: :"icon-sm",
|
|
10
|
+
label: t("poetry.message_scroller.scroll_to_end"),
|
|
11
|
+
**button_attributes) do %>
|
|
12
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :"arrow-down") %>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|