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,203 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A click-opened panel anchored to its trigger.
|
|
6
|
+
module Popover
|
|
7
|
+
# The placement vocabularies - the popper-consumer kit owns them.
|
|
8
|
+
SIDES = Poetry::Ui::PopperConsumer::SIDES
|
|
9
|
+
# The closed vocabulary for the align axis.
|
|
10
|
+
ALIGNS = Poetry::Ui::PopperConsumer::ALIGNS
|
|
11
|
+
|
|
12
|
+
# A click-opened role=dialog panel anchored to its trigger, for
|
|
13
|
+
# interactive content: small forms, filters, pickers. Opening
|
|
14
|
+
# moves focus to the first tabbable element in the panel; Escape
|
|
15
|
+
# or outside interaction closes it and returns focus to the
|
|
16
|
+
# trigger. Non-modal by default - the rest of the page stays
|
|
17
|
+
# interactive while it is open.
|
|
18
|
+
#
|
|
19
|
+
# with_trigger composes a Button as the control. Name the panel
|
|
20
|
+
# via with_title (preferred) or label: - a dialog needs an
|
|
21
|
+
# accessible name. The focus and dismiss behavior activates only
|
|
22
|
+
# while open, so closed popovers cost nothing at page load.
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# render Poetry::Ui::Popover::Component.new do |popover|
|
|
26
|
+
# popover.with_trigger(variant: :outline) { "Open popover" }
|
|
27
|
+
# popover.with_title { "Dimensions" }
|
|
28
|
+
# tag.p("Set the dimensions for the layer.")
|
|
29
|
+
# end
|
|
30
|
+
class Component < Poetry::Core::Component
|
|
31
|
+
include Poetry::Ui::ComposableTrigger
|
|
32
|
+
include Poetry::Ui::PopperConsumer
|
|
33
|
+
|
|
34
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
35
|
+
AGENT_RULES = [
|
|
36
|
+
ComposableTrigger::AGENT_RULE,
|
|
37
|
+
"Use poetry_popover - never hand-roll an anchored role=dialog panel with Tailwind.",
|
|
38
|
+
"Popover content is INTERACTIVE - for text-only hover hints use Tooltip; for pointer-only " \
|
|
39
|
+
"previews use HoverCard.",
|
|
40
|
+
"Give the panel a name: use with_title (preferred) or label: - a role=dialog without a name " \
|
|
41
|
+
"fails the audit.",
|
|
42
|
+
"Icon-only triggers MUST have an accessible name (the composed Button's label: rule).",
|
|
43
|
+
"Default is NON-modal (modal: false) - reach for modal: true only when stray outside " \
|
|
44
|
+
"interaction would corrupt the task; reach for Dialog when the task deserves full modality.",
|
|
45
|
+
"Critical-path panels must also be reachable without JS (full page or server-rendered " \
|
|
46
|
+
"open: true) - popovers are JS-required interaction.",
|
|
47
|
+
"Do not nest a Popover inside a Popover - restructure (the layer stack allows it; " \
|
|
48
|
+
"comprehension does not)."
|
|
49
|
+
].freeze
|
|
50
|
+
|
|
51
|
+
# Slots the component cannot render without; static checks read this without rendering.
|
|
52
|
+
REQUIRED_SLOTS = { trigger: "the panel's control" }.freeze
|
|
53
|
+
|
|
54
|
+
# The class each slot's builder renders - with_trigger composes a
|
|
55
|
+
# Button, so callers get Button's full option contract.
|
|
56
|
+
SLOT_RENDERS = { trigger: Button::Component }.freeze
|
|
57
|
+
|
|
58
|
+
renders_one :trigger,
|
|
59
|
+
doc: "The control that opens the panel - a composed Button. The slot owns the " \
|
|
60
|
+
"aria-haspopup/expanded/controls wiring regardless of the composed content, so composition " \
|
|
61
|
+
"cannot drop the aria; aria-controls renders even while closed (the stable id is the " \
|
|
62
|
+
"wiring's resolution seam).",
|
|
63
|
+
renders: lambda { |**options, &block|
|
|
64
|
+
wiring = {
|
|
65
|
+
"id" => trigger_id, "data-slot" => "popover-trigger",
|
|
66
|
+
"aria-haspopup" => "dialog", "aria-expanded" => open.to_s, "aria-controls" => content_id
|
|
67
|
+
}.merge(stimulus_attributes_for(:trigger))
|
|
68
|
+
# Trigger open state: bare data-popup-open while open, NO
|
|
69
|
+
# attribute while closed (absence IS the state).
|
|
70
|
+
wiring["data-popup-open"] = "" if open
|
|
71
|
+
composed_trigger(wiring, options, &block) ||
|
|
72
|
+
Button::Component.new(**wiring, **options, &block)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
renders_one :anchor,
|
|
76
|
+
doc: "Optional alternate anchor: when present, the panel positions against IT instead of the " \
|
|
77
|
+
"trigger (targets beat selectors in the positioning fallback chain).",
|
|
78
|
+
renders: lambda { |**options, &block|
|
|
79
|
+
attrs = { "data-slot" => "popover-anchor" }
|
|
80
|
+
.merge(stimulus_attributes_for(:anchor_part))
|
|
81
|
+
content_tag(:div, attrs.merge(options)) { capture(&block) }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
renders_one :title, doc: "Panel heading - presence wires the content's aria-labelledby, so the title names " \
|
|
85
|
+
"the dialog."
|
|
86
|
+
|
|
87
|
+
renders_one :description, doc: "Supporting text - presence wires the content's aria-describedby."
|
|
88
|
+
|
|
89
|
+
use_stimulus do
|
|
90
|
+
on :root do
|
|
91
|
+
controller :popover do
|
|
92
|
+
register
|
|
93
|
+
value :open
|
|
94
|
+
value :modal
|
|
95
|
+
end
|
|
96
|
+
controller :popper do
|
|
97
|
+
register
|
|
98
|
+
# The trigger anchors by id selector; an anchor part
|
|
99
|
+
# overrides it with the anchor TARGET (render-time decision -
|
|
100
|
+
# slots may be set in any order, so the trigger itself
|
|
101
|
+
# carries no popper target).
|
|
102
|
+
value :anchor, from: :trigger_anchor_selector, unless: :anchor?
|
|
103
|
+
value :side
|
|
104
|
+
value :align
|
|
105
|
+
value :side_offset
|
|
106
|
+
value :align_offset
|
|
107
|
+
value :avoid_collisions
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
on :trigger do
|
|
111
|
+
controller(:popover) { action :toggle, on: :click }
|
|
112
|
+
end
|
|
113
|
+
on :anchor_part do
|
|
114
|
+
controller(:popper) { target :anchor }
|
|
115
|
+
end
|
|
116
|
+
on :content do
|
|
117
|
+
controller(:popper) { target :content }
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
option :open, :boolean, default: false, doc: "Server-renders the panel open."
|
|
122
|
+
option :modal, :boolean, default: false,
|
|
123
|
+
doc: "Reserves interaction for the panel while open; the default keeps the rest of " \
|
|
124
|
+
"the page interactive."
|
|
125
|
+
# The placement axes for the anchored panel (side, align, offsets).
|
|
126
|
+
popper_placement_options(side: :bottom, side_offset: 4)
|
|
127
|
+
option :label, :string, doc: "role=dialog fallback name when no title part is present."
|
|
128
|
+
option :content_class, :string,
|
|
129
|
+
doc: "Class merge seam for the panel itself (e.g. widen the default with content_class: \"w-80\") - " \
|
|
130
|
+
"root-level class: styles the wrapper, not the panel."
|
|
131
|
+
|
|
132
|
+
part "popover", "Root wrapper around the trigger, the optional anchor, and the panel"
|
|
133
|
+
part "popover-anchor", "Optional alternate popper anchor - when " \
|
|
134
|
+
"present the panel positions against it instead of the trigger"
|
|
135
|
+
part "popover-content", "The role=dialog panel - positioning, animation, and the open " \
|
|
136
|
+
"state ride here",
|
|
137
|
+
states: {
|
|
138
|
+
"data-open" => "panel is open (the controller flips the pair at runtime)",
|
|
139
|
+
"data-closed" => "panel is closed (the server-rendered state; hidden rides along)",
|
|
140
|
+
"data-side" => { condition: "always - the side (initial placement, re-resolved " \
|
|
141
|
+
"live by popper after flip)",
|
|
142
|
+
values: SIDES.map(&:to_s) },
|
|
143
|
+
"data-align" => { condition: "always - the alignment (re-resolved live by popper)",
|
|
144
|
+
values: ALIGNS.map(&:to_s) }
|
|
145
|
+
},
|
|
146
|
+
vars: Poetry::Ui::PopperConsumer.content_vars
|
|
147
|
+
part "popover-header", "Title block wrapping the title and description (renders only " \
|
|
148
|
+
"when either is present)"
|
|
149
|
+
part "popover-title", "The heading - the panel's accessible name via aria-labelledby"
|
|
150
|
+
part "popover-description", "Muted copy under the title, wired to aria-describedby"
|
|
151
|
+
|
|
152
|
+
# Enforces the required trigger and warns on a nameless dialog.
|
|
153
|
+
# @api private
|
|
154
|
+
def before_render
|
|
155
|
+
raise ArgumentError, "Popover requires with_trigger (the panel's control)" unless trigger?
|
|
156
|
+
|
|
157
|
+
return if title? || label.present?
|
|
158
|
+
|
|
159
|
+
# Lint-level warning, not an error: a role=dialog SHOULD have an
|
|
160
|
+
# accessible name (with_title preferred, label: the fallback).
|
|
161
|
+
Rails.logger&.warn(
|
|
162
|
+
"poetry Popover: role=dialog panel has no accessible name - give it with_title or label:"
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# @api private
|
|
167
|
+
def title_id
|
|
168
|
+
"#{instance_id}-title"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @api private
|
|
172
|
+
def description_id
|
|
173
|
+
"#{instance_id}-description"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# @api private
|
|
177
|
+
def content_attributes
|
|
178
|
+
attrs = {
|
|
179
|
+
"id" => content_id, "role" => "dialog", "tabindex" => "-1",
|
|
180
|
+
"data-slot" => "popover-content", (open ? "data-open" : "data-closed") => "",
|
|
181
|
+
# Initial placement, re-resolved live by popper on open.
|
|
182
|
+
"data-side" => side, "data-align" => align,
|
|
183
|
+
"class" => css(:content, class: content_class)
|
|
184
|
+
}.merge(stimulus_attributes_for(:content))
|
|
185
|
+
if title?
|
|
186
|
+
attrs["aria-labelledby"] = title_id
|
|
187
|
+
elsif label.present?
|
|
188
|
+
attrs["aria-label"] = label
|
|
189
|
+
end
|
|
190
|
+
attrs["aria-describedby"] = description_id if description?
|
|
191
|
+
attrs["hidden"] = true unless open
|
|
192
|
+
attrs
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
private
|
|
196
|
+
|
|
197
|
+
def trigger_anchor_selector = "##{trigger_id}"
|
|
198
|
+
|
|
199
|
+
private :title_id, :description_id, :content_attributes
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<%# Class-wide sidecar (it displaces poetry-core's generic preview.html.erb
|
|
2
|
+
fallback, so it must keep that contract): examples that pass their own
|
|
3
|
+
composition flow through unchanged; the template-owned examples
|
|
4
|
+
(default/modal) render the upstream popover-demo form - grid gap-2 rows,
|
|
5
|
+
each grid-cols-3 with the input spanning two columns at h-8 - the layout
|
|
6
|
+
the port originally dropped (bare label+input pairs had no spacing). %>
|
|
7
|
+
<div class="<%= defined?(container_class) && container_class.presence || "p-4" %>">
|
|
8
|
+
<% if local_assigns[:content_block] %>
|
|
9
|
+
<%= render(component, &content_block) %>
|
|
10
|
+
<% else %>
|
|
11
|
+
<%= render component do |popover| %>
|
|
12
|
+
<% popover.with_trigger(variant: :outline) { "Open popover" } %>
|
|
13
|
+
<% popover.with_title { "Dimensions" } %>
|
|
14
|
+
<% popover.with_description { "Set the dimensions for the layer." } %>
|
|
15
|
+
<div class="grid gap-2">
|
|
16
|
+
<div class="grid grid-cols-3 items-center gap-4">
|
|
17
|
+
<%= render Poetry::Ui::Label::Component.new(for_id: "popover-demo-width").with_content("Width") %>
|
|
18
|
+
<%= render Poetry::Ui::Input::Component.new(name: "width", value: "100%",
|
|
19
|
+
id: "popover-demo-width", class: "col-span-2 h-8") %>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="grid grid-cols-3 items-center gap-4">
|
|
22
|
+
<%= render Poetry::Ui::Label::Component.new(for_id: "popover-demo-height").with_content("Height") %>
|
|
23
|
+
<%= render Poetry::Ui::Input::Component.new(name: "height", value: "25px",
|
|
24
|
+
id: "popover-demo-height", class: "col-span-2 h-8") %>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
28
|
+
<% end %>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Popover
|
|
6
|
+
# The Popover preview matrix: the ported popover-demo composition
|
|
7
|
+
# (form-in-popover, w-80 override) plus both modality modes, the
|
|
8
|
+
# anchor part, the label: naming fallback, a placement sample, and
|
|
9
|
+
# the server-rendered open state.
|
|
10
|
+
class Preview < Poetry::Core::Preview::Base
|
|
11
|
+
# The popover-demo port: outline Button trigger, titled/described
|
|
12
|
+
# panel, the dimensions form in upstream's grid rows (the sidecar
|
|
13
|
+
# preview.html.erb - herb-scanned, so the layout classes reach the
|
|
14
|
+
# safelist), the demo's w-80 class override.
|
|
15
|
+
def default
|
|
16
|
+
render_with(component: Component.new(content_class: "w-80"))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# modal: true - focus-scope trapped + the dismissable scrim.
|
|
20
|
+
def modal
|
|
21
|
+
render_with(component: Component.new(content_class: "w-80", modal: true))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The anchor part takes the popper anchor target: the panel
|
|
25
|
+
# positions against IT, not the trigger (the source's anchor part).
|
|
26
|
+
def with_anchor
|
|
27
|
+
render_component do |popover|
|
|
28
|
+
popover.with_trigger(variant: :outline) { "Open popover" }
|
|
29
|
+
popover.with_anchor { "The panel anchors to this text, not the button." }
|
|
30
|
+
popover.with_title { "Anchored" }
|
|
31
|
+
"Positioned against the anchor part."
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# No title part: label: names the role=dialog via aria-label.
|
|
36
|
+
def named_by_label
|
|
37
|
+
render_component(label: "Quick settings") do |popover|
|
|
38
|
+
popover.with_trigger(variant: :outline) { "Settings" }
|
|
39
|
+
"A panel named by label: instead of a title part."
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Server-rendered open state (controllable-state: the attributes
|
|
44
|
+
# are the store; the controller reconciles on connect).
|
|
45
|
+
def open
|
|
46
|
+
render_component(open: true) do |popover|
|
|
47
|
+
popover.with_trigger(variant: :outline) { "Open popover" }
|
|
48
|
+
popover.with_title { "Server-opened" }
|
|
49
|
+
popover.with_description { "Rendered open - fully usable before (or without) JS." }
|
|
50
|
+
"Static content."
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Placement sample (side/align flow through to popper; data-side
|
|
55
|
+
# re-resolves live on collision).
|
|
56
|
+
def side_top
|
|
57
|
+
render_component(side: :top, align: :start) do |popover|
|
|
58
|
+
popover.with_trigger(variant: :outline) { "Open above" }
|
|
59
|
+
popover.with_title { "Placement" }
|
|
60
|
+
"side: :top, align: :start"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Popover
|
|
6
|
+
# Re-expressed through the cn-* theme layer. w-72 stays inline
|
|
7
|
+
# per upstream's split (the caller-overridable width default); the
|
|
8
|
+
# origin class binds through the tokens/aliases.css alias to popper's
|
|
9
|
+
# generic var and stays inline as mechanism.
|
|
10
|
+
class Style < Poetry::Core::Style
|
|
11
|
+
# The panel's DISPLAY + header/body gap are THEME-owned (every
|
|
12
|
+
# theme port ships its own flex-col gap-*; lyra/nova deliberately run
|
|
13
|
+
# tighter at 2.5) - closed panels stay hidden regardless because
|
|
14
|
+
# preflight's [hidden] rule is !important.
|
|
15
|
+
element :content, "cn-popover-content z-50 w-72 " \
|
|
16
|
+
"origin-(--transform-origin) outline-hidden"
|
|
17
|
+
|
|
18
|
+
# Ported-source additions (plain divs there; poetry wires their
|
|
19
|
+
# ids to the dialog's aria-labelledby/describedby).
|
|
20
|
+
element :header, "cn-popover-header flex flex-col"
|
|
21
|
+
element :title, "cn-popover-title"
|
|
22
|
+
element :description, "cn-popover-description"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Gives a trigger-anchored popup component (Popover, HoverCard,
|
|
6
|
+
# Tooltip) the shared positioning surface: the placement vocabulary,
|
|
7
|
+
# the popper_placement_options macro, the content part's CSS-var
|
|
8
|
+
# contract, and the trigger/content id pair. Stimulus declarations
|
|
9
|
+
# stay per-family: each family's value set genuinely differs.
|
|
10
|
+
module PopperConsumer
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
include FamilyIdentity
|
|
13
|
+
|
|
14
|
+
# The closed vocabulary for the side placement axis.
|
|
15
|
+
SIDES = %i[top right bottom left].freeze
|
|
16
|
+
# The closed vocabulary for the align placement axis.
|
|
17
|
+
ALIGNS = %i[start center end].freeze
|
|
18
|
+
|
|
19
|
+
class_methods do
|
|
20
|
+
# Declares the five placement options (side, align, side_offset,
|
|
21
|
+
# align_offset, avoid_collisions) plus their vocabulary
|
|
22
|
+
# validations on the including component - each family passes its
|
|
23
|
+
# own defaults.
|
|
24
|
+
def popper_placement_options(side:, side_offset:, align: :center, align_offset: 0)
|
|
25
|
+
option :side, :symbol, default: side, doc: "Which side of the anchor the panel opens on."
|
|
26
|
+
option :align, :symbol, default: align, doc: "Panel alignment along the chosen side."
|
|
27
|
+
option :side_offset, :integer, default: side_offset,
|
|
28
|
+
doc: "Gap in pixels between the anchor and the panel."
|
|
29
|
+
option :align_offset, :integer, default: align_offset,
|
|
30
|
+
doc: "Shift in pixels along the alignment axis."
|
|
31
|
+
option :avoid_collisions, :boolean, default: true,
|
|
32
|
+
doc: "Flips and shifts the panel to stay inside the viewport."
|
|
33
|
+
validates :side, inclusion: { in: SIDES }
|
|
34
|
+
validates :align, inclusion: { in: ALIGNS }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The CSS custom properties the positioning engine writes onto the
|
|
39
|
+
# content part - inlined into a family's part declaration as its
|
|
40
|
+
# vars:. noun names the family's surface in the prose ("panel",
|
|
41
|
+
# "bubble").
|
|
42
|
+
def self.content_vars(noun = "panel")
|
|
43
|
+
{
|
|
44
|
+
"--transform-origin" => "the anchor-facing origin popper writes for scale-in animation",
|
|
45
|
+
"--available-width" => "viewport space left for the #{noun} (popper, post-flip)",
|
|
46
|
+
"--available-height" => "viewport space left for the #{noun} (popper, post-flip)",
|
|
47
|
+
"--anchor-width" => "the anchor's measured width (popper)",
|
|
48
|
+
"--anchor-height" => "the anchor's measured height (popper)"
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The trigger element's server-stable id.
|
|
53
|
+
# @api private
|
|
54
|
+
def trigger_id
|
|
55
|
+
"#{instance_id}-trigger"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The content element's server-stable id. The controller resolves
|
|
59
|
+
# content by the id pair ("-trigger" -> "-content"), portal-safe -
|
|
60
|
+
# no Stimulus target.
|
|
61
|
+
# @api private
|
|
62
|
+
def content_id
|
|
63
|
+
"#{instance_id}-content"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private :trigger_id, :content_id
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A determinate progress bar.
|
|
6
|
+
module Progress
|
|
7
|
+
# A determinate task's completion, server-rendered: a
|
|
8
|
+
# role=progressbar root carrying the value in aria, with a filled
|
|
9
|
+
# track sized to the percentage. label: is the accessible name and
|
|
10
|
+
# renders as the visible caption beside a percent readout. For an
|
|
11
|
+
# unknown duration use Spinner - this bar has no indeterminate
|
|
12
|
+
# state.
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# render Poetry::Ui::Progress::Component.new(value: 60, label: "Uploading")
|
|
16
|
+
class Component < Poetry::Core::Component
|
|
17
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
18
|
+
AGENT_RULES = [
|
|
19
|
+
"label: is REQUIRED - it is the progressbar's accessible name and the visible caption.",
|
|
20
|
+
"value: is the current progress (0..max:, default max 100); the component computes the width.",
|
|
21
|
+
"For an UNKNOWN duration use Spinner, not Progress - this bar is determinate."
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
24
|
+
option :value, :integer, required: true, doc: "The current progress, clamped into 0..max:."
|
|
25
|
+
option :max, :integer, default: 100, doc: "The completion value."
|
|
26
|
+
option :label, :string, required: true, doc: "The progressbar's accessible name and visible caption."
|
|
27
|
+
option :show_value, :boolean, default: true, doc: "Set false to hide the percent readout."
|
|
28
|
+
|
|
29
|
+
part "progress", "Root (role=progressbar, aria-value* and the accessible name) - " \
|
|
30
|
+
"label, value readout, and track stack here"
|
|
31
|
+
part "progress-label", "The visible caption span (label:)"
|
|
32
|
+
part "progress-value", "The tabular percent readout - renders unless show_value: false"
|
|
33
|
+
part "progress-track", "The full-width rail the indicator fills"
|
|
34
|
+
part "progress-indicator", "The filled bar - sized by an inline width percentage " \
|
|
35
|
+
"computed from value:/max:"
|
|
36
|
+
|
|
37
|
+
# Enforces the required label and a positive max.
|
|
38
|
+
# @api private
|
|
39
|
+
def before_render
|
|
40
|
+
raise ArgumentError, "Progress requires label: (the progressbar's accessible name)" if label.blank?
|
|
41
|
+
raise ArgumentError, "Progress max: must be positive" unless max.positive?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @api private
|
|
45
|
+
def call
|
|
46
|
+
content_tag(:div, root_attributes.to_attributes) do
|
|
47
|
+
safe_join([label_part, value_part, track].compact)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @api private
|
|
52
|
+
def percent
|
|
53
|
+
(value.to_f / max * 100).clamp(0, 100)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @api private
|
|
57
|
+
def percent_text
|
|
58
|
+
"#{percent.round}%"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @api private
|
|
62
|
+
def root_attributes
|
|
63
|
+
html_attributes.merge_if_not_set(
|
|
64
|
+
{
|
|
65
|
+
"data-slot" => "progress", "role" => "progressbar",
|
|
66
|
+
"aria-valuemin" => 0, "aria-valuemax" => max, "aria-valuenow" => value.clamp(0, max),
|
|
67
|
+
"aria-label" => label
|
|
68
|
+
}.merge(component_data_attributes)
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def label_part
|
|
75
|
+
content_tag(:span, label, "data-slot" => "progress-label", class: css(:label))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def value_part
|
|
79
|
+
return unless show_value
|
|
80
|
+
|
|
81
|
+
content_tag(:span, percent_text, "data-slot" => "progress-value", class: css(:value))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def track
|
|
85
|
+
content_tag(:div, "data-slot" => "progress-track", class: css(:track)) do
|
|
86
|
+
content_tag(:div, nil, "data-slot" => "progress-indicator", class: css(:indicator),
|
|
87
|
+
style: "width: #{percent.round(4)}%")
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private :percent, :percent_text, :root_attributes
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Progress
|
|
6
|
+
# The Progress preview: mid-flight, complete, and a custom max.
|
|
7
|
+
class Preview < Poetry::Core::Preview::Base
|
|
8
|
+
def default
|
|
9
|
+
render_component(value: 60, label: "Uploading photos")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def complete
|
|
13
|
+
render_component(value: 100, label: "Backup")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def custom_max_without_value
|
|
17
|
+
render_component(value: 3, max: 8, label: "Steps completed", show_value: false)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Progress
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The root keeps no
|
|
7
|
+
# cn name (its whole poetry surface is structural; upstream's
|
|
8
|
+
# cn-progress-root returns with content in a future theme).
|
|
9
|
+
class Style < Poetry::Core::Style
|
|
10
|
+
base "flex flex-wrap gap-3"
|
|
11
|
+
|
|
12
|
+
element :track, "cn-progress-track relative flex w-full items-center overflow-x-hidden"
|
|
13
|
+
element :indicator, "cn-progress-indicator h-full transition-all"
|
|
14
|
+
element :label, "cn-progress-label"
|
|
15
|
+
element :value, "cn-progress-value"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<%= form_with(url: url, method: http_method, html: root_attributes.to_attributes) do %>
|
|
2
|
+
<% if progress? %>
|
|
3
|
+
<% custom_progress = progress.to_s %>
|
|
4
|
+
<div <%= tag.attributes({ "class" => css(:progress, class: progress_class), "data-slot" => "questionnaire-progress",
|
|
5
|
+
"role" => "progressbar", "aria-label" => "Questionnaire progress",
|
|
6
|
+
"aria-live" => "polite",
|
|
7
|
+
"data-current" => active_index + 1,
|
|
8
|
+
"data-total" => enabled_items.size,
|
|
9
|
+
"aria-valuemin" => "1",
|
|
10
|
+
"aria-valuemax" => enabled_items.size,
|
|
11
|
+
"aria-valuenow" => active_index + 1,
|
|
12
|
+
"aria-valuetext" => progress_label }
|
|
13
|
+
.merge(custom_progress.present? ? { "data-custom" => "" } : {})
|
|
14
|
+
.merge(stimulus_attributes_for(:progress))) %>>
|
|
15
|
+
<%= custom_progress.presence || progress_label %>
|
|
16
|
+
</div>
|
|
17
|
+
<% end %>
|
|
18
|
+
<% item_models.each do |item| %>
|
|
19
|
+
<%= content_tag(:fieldset, **item_attributes(item)) do %>
|
|
20
|
+
<legend data-slot="questionnaire-title" class="<%= css(:title) %>"><%= item.title %></legend>
|
|
21
|
+
<% if item.description %>
|
|
22
|
+
<p data-slot="questionnaire-description" id="<%= item_dom_id(item, "description") %>"
|
|
23
|
+
class="<%= css(:description) %>"><%= item.description %></p>
|
|
24
|
+
<% end %>
|
|
25
|
+
<div data-slot="questionnaire-choices" class="<%= css(:choices) %>">
|
|
26
|
+
<% item.choices.each_with_index do |choice, index| %>
|
|
27
|
+
<%= content_tag(:label, **choice_attributes(item, choice, index)) do %>
|
|
28
|
+
<input type="<%= input_type(item) %>" name="<%= field_name(item) %>"
|
|
29
|
+
value="<%= choice.value %>" data-slot="questionnaire-choice-input"
|
|
30
|
+
class="<%= css(:choice_input) %>"
|
|
31
|
+
<% if choice.checked %>checked<% end %> <% if choice.disabled || item.disabled %>disabled<% end %>
|
|
32
|
+
<%= tag.attributes({ (choice.checked ? "data-checked" : "data-unchecked") => "" }) %>>
|
|
33
|
+
<span aria-hidden="true" data-slot="questionnaire-choice-indicator" class="<%= css(:choice_indicator) %>">
|
|
34
|
+
<span data-slot="questionnaire-choice-indicator-dot" class="<%= css(:choice_indicator_dot) %>"></span>
|
|
35
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :check, class: css(:choice_indicator_check),
|
|
36
|
+
data: { slot: "questionnaire-choice-indicator-check" }) %>
|
|
37
|
+
</span>
|
|
38
|
+
<span data-slot="questionnaire-choice-label" class="<%= css(:choice_label) %>">
|
|
39
|
+
<span><%= choice.label %></span>
|
|
40
|
+
<% if choice.description %>
|
|
41
|
+
<span data-slot="questionnaire-choice-description" class="<%= css(:choice_description) %>"><%= choice.description %></span>
|
|
42
|
+
<% end %>
|
|
43
|
+
</span>
|
|
44
|
+
<% if (key = shortcut_for(item, index)) %>
|
|
45
|
+
<span aria-hidden="true" data-slot="questionnaire-choice-shortcut" class="<%= css(:choice_shortcut) %>"><%= key %></span>
|
|
46
|
+
<% end %>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% end %>
|
|
49
|
+
<% if item.input %>
|
|
50
|
+
<div data-slot="questionnaire-input-wrapper" class="<%= css(:input_wrapper) %>">
|
|
51
|
+
<input type="text" name="<%= field_name(item) %>" data-slot="questionnaire-input" autocomplete="off"
|
|
52
|
+
class="<%= css(:input) %>" aria-label="<%= item.input.label %>"
|
|
53
|
+
placeholder="<%= item.input.placeholder %>" value="<%= item.input.value %>"
|
|
54
|
+
<%= tag.attributes({ (item.input.value.present? ? "data-filled" : "data-empty") => "" }) %>>
|
|
55
|
+
</div>
|
|
56
|
+
<% end %>
|
|
57
|
+
</div>
|
|
58
|
+
<p data-slot="questionnaire-error" id="<%= item_dom_id(item, "error") %>"
|
|
59
|
+
class="<%= css(:error) %>" hidden><%= item.error_message %></p>
|
|
60
|
+
<% end %>
|
|
61
|
+
<% end %>
|
|
62
|
+
<div data-slot="questionnaire-actions" class="<%= css(:actions) %>">
|
|
63
|
+
<%= render(Poetry::Ui::Button::Component.new(
|
|
64
|
+
variant: :outline, type: :button,
|
|
65
|
+
**nav_button_options(:previous, hidden: enabled_items.size <= 1 || first?)
|
|
66
|
+
)) { previous_label } %>
|
|
67
|
+
<%= render(Poetry::Ui::Button::Component.new(
|
|
68
|
+
variant: :outline, type: :button,
|
|
69
|
+
**nav_button_options(:skip, hidden: active_item.required)
|
|
70
|
+
)) { skip_label } %>
|
|
71
|
+
<%= render(Poetry::Ui::Button::Component.new(
|
|
72
|
+
type: :button,
|
|
73
|
+
**nav_button_options(:next, hidden: enabled_items.size <= 1 || last?)
|
|
74
|
+
)) { next_label } %>
|
|
75
|
+
<%= render(Poetry::Ui::Button::Component.new(
|
|
76
|
+
type: :submit,
|
|
77
|
+
**nav_button_options(:submit, hidden: !last?)
|
|
78
|
+
)) { submit_label } %>
|
|
79
|
+
</div>
|
|
80
|
+
<% end %>
|