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,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A styled native <select>.
|
|
6
|
+
module NativeSelect
|
|
7
|
+
# A styled REAL <select> - platform picker, form submission, and
|
|
8
|
+
# mobile UX for free - with a decorative chevron replacing the
|
|
9
|
+
# native arrow. The fast path is options: pairs; compose
|
|
10
|
+
# <option>/<optgroup> in the content block for anything richer
|
|
11
|
+
# (poetry_native_select_option / _optgroup stamp the classes).
|
|
12
|
+
#
|
|
13
|
+
# @example The options: fast path
|
|
14
|
+
# render Poetry::Ui::NativeSelect::Component.new(
|
|
15
|
+
# name: "sort", label: "Sort by",
|
|
16
|
+
# options: [["Newest first", "newest"], ["Oldest first", "oldest"]],
|
|
17
|
+
# selected: "newest"
|
|
18
|
+
# )
|
|
19
|
+
class Component < Poetry::Core::Component
|
|
20
|
+
# The closed vocabulary for the size axis.
|
|
21
|
+
SIZES = %i[default sm].freeze
|
|
22
|
+
|
|
23
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
24
|
+
AGENT_RULES = [
|
|
25
|
+
"This is a REAL <select> - use it for plain picking; the JS Select is for styled options.",
|
|
26
|
+
"Pair it with a Label (for_id: its id) or a Field - a bare select has no accessible name.",
|
|
27
|
+
"The fast path is options: [[label, value], ...] + selected:; a content block overrides it."
|
|
28
|
+
].freeze
|
|
29
|
+
|
|
30
|
+
option :name, :string, doc: "The submitted field name, forwarded to the native select."
|
|
31
|
+
option :id, :string, doc: "The select's dom id - the seam a Label's for_id: points at."
|
|
32
|
+
option :label, :string,
|
|
33
|
+
doc: "The accessible name for label-less placements (a visible Label paired via id:/for_id: is still " \
|
|
34
|
+
"the default pattern)."
|
|
35
|
+
option :size, :symbol, default: :default, doc: "The control size axis; :sm suits dense toolbars and table rows."
|
|
36
|
+
option :disabled, :boolean, default: false, doc: "Disables the native select; the wrapper dims the whole pair."
|
|
37
|
+
option :invalid, :boolean, default: false, doc: "Marks the select invalid (aria-invalid on the element itself)."
|
|
38
|
+
option :described_by, :string,
|
|
39
|
+
doc: "Space-separated hint/error ids wired to the SELECT itself - a raw aria-describedby in " \
|
|
40
|
+
"html_attributes would land on the wrapper div, unassociated for assistive technology."
|
|
41
|
+
|
|
42
|
+
validates :size, inclusion: { in: SIZES }
|
|
43
|
+
|
|
44
|
+
part "native-select-wrapper", "Relative shell around the select and the chevron - " \
|
|
45
|
+
"dims the pair when the select is disabled",
|
|
46
|
+
states: {
|
|
47
|
+
"data-size" => { condition: "always - the resolved size",
|
|
48
|
+
values: SIZES.map(&:to_s) }
|
|
49
|
+
}
|
|
50
|
+
part "native-select", "The real <select> - appearance-none (the chevron replaces the " \
|
|
51
|
+
"native arrow); platform picker and form submission stay native",
|
|
52
|
+
states: {
|
|
53
|
+
"data-size" => { condition: "always - the resolved size (mirrors the wrapper)",
|
|
54
|
+
values: SIZES.map(&:to_s) }
|
|
55
|
+
}
|
|
56
|
+
part "native-select-icon", "The decorative chevron wrapper - absolutely pinned, " \
|
|
57
|
+
"aria-hidden"
|
|
58
|
+
part "native-select-option", "An <option> from the options: fast path (or " \
|
|
59
|
+
"poetry_native_select_option) - Canvas system colors " \
|
|
60
|
+
"keep the native dropdown legible"
|
|
61
|
+
|
|
62
|
+
# @api private
|
|
63
|
+
def call
|
|
64
|
+
content_tag(:div, wrapper_attributes.to_attributes) do
|
|
65
|
+
safe_join([select_element, chevron])
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @api private
|
|
70
|
+
def wrapper_attributes
|
|
71
|
+
html_attributes.merge_if_not_set(
|
|
72
|
+
{
|
|
73
|
+
"data-slot" => "native-select-wrapper", "data-size" => size
|
|
74
|
+
}.merge(component_data_attributes)
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @api private
|
|
79
|
+
def select_attributes
|
|
80
|
+
attrs = { "data-slot" => "native-select", "data-size" => size, "class" => css(:select) }
|
|
81
|
+
attrs["name"] = name if name.present?
|
|
82
|
+
attrs["id"] = id if id.present?
|
|
83
|
+
attrs["aria-label"] = label if label.present?
|
|
84
|
+
attrs["aria-describedby"] = described_by if described_by.present?
|
|
85
|
+
attrs["disabled"] = true if disabled
|
|
86
|
+
attrs["aria-invalid"] = true if invalid
|
|
87
|
+
attrs
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
# options: pairs are structural data, not a typed option.
|
|
93
|
+
def initialize(options: nil, selected: nil, **)
|
|
94
|
+
super(**)
|
|
95
|
+
@options = options
|
|
96
|
+
@selected = selected
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def select_element
|
|
100
|
+
content_tag(:select, select_content, select_attributes)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def select_content
|
|
104
|
+
return content if content.present?
|
|
105
|
+
|
|
106
|
+
safe_join(Array(@options).map do |entry|
|
|
107
|
+
label, value = entry.is_a?(Array) ? entry : [entry, entry]
|
|
108
|
+
tag.option(label, value: value, selected: value.to_s == @selected.to_s || nil,
|
|
109
|
+
"data-slot": "native-select-option", class: css(:option))
|
|
110
|
+
end)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The chevron svg is the icon part itself (the source's shape) - the
|
|
114
|
+
# theme rule sizes and pins it; no wrapper span.
|
|
115
|
+
def chevron
|
|
116
|
+
render(Poetry::Ui::Icon::Component.new(name: :"chevron-down", class: css(:icon),
|
|
117
|
+
data: { slot: "native-select-icon" }))
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private :wrapper_attributes, :select_attributes
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<%# The labelled pair - a bare select has no accessible name. %>
|
|
2
|
+
<div class="flex flex-col gap-2 p-4">
|
|
3
|
+
<%= poetry_label(for_id: "native-select-sort") { "Sort by" } %>
|
|
4
|
+
<%= poetry_native_select(name: "sort", id: "native-select-sort",
|
|
5
|
+
options: [["Newest first", "newest"], ["Oldest first", "oldest"], ["Title", "title"]],
|
|
6
|
+
selected: "newest") %>
|
|
7
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module NativeSelect
|
|
6
|
+
# The NativeSelect preview: the labelled pair (its whole a11y
|
|
7
|
+
# contract), plus small/disabled states.
|
|
8
|
+
class Preview < Poetry::Core::Preview::Base
|
|
9
|
+
def default
|
|
10
|
+
render_with_template(template: "poetry/ui/native_select/labelled_preview")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def small_disabled
|
|
14
|
+
render_component(size: :sm, disabled: true, name: "plan", id: "native-select-plan",
|
|
15
|
+
label: "Plan", options: %w[Starter Team], selected: "Team")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module NativeSelect
|
|
6
|
+
# Re-expressed through the cn-* theme layer. appearance-none
|
|
7
|
+
# stays inline as a mechanism guard (a swapped theme must never
|
|
8
|
+
# resurrect the double native arrow); the wrapper and the
|
|
9
|
+
# option/optgroup Canvas system-color guards are structural, no cn
|
|
10
|
+
# names. The chevron wrapper keeps position mechanics inline.
|
|
11
|
+
class Style < Poetry::Core::Style
|
|
12
|
+
base "relative w-fit has-[select:disabled]:opacity-50 group/native-select"
|
|
13
|
+
|
|
14
|
+
element :select, "cn-native-select w-full appearance-none outline-none " \
|
|
15
|
+
"disabled:pointer-events-none disabled:cursor-not-allowed"
|
|
16
|
+
element :icon, "cn-native-select-icon pointer-events-none absolute select-none"
|
|
17
|
+
element :option, "bg-[Canvas] text-[CanvasText]"
|
|
18
|
+
element :optgroup, "bg-[Canvas] text-[CanvasText]"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<%# The site-nav bar: a trigger item with a link panel + plain links. %>
|
|
2
|
+
<div class="flex min-h-64 justify-center p-4">
|
|
3
|
+
<%= poetry_navigation_menu(label: "Main") do |nav| %>
|
|
4
|
+
<% nav.with_item("Products", value: "products") do %>
|
|
5
|
+
<div class="grid w-64 gap-1">
|
|
6
|
+
<%= poetry_navigation_menu_link(href: "#", active: true) { "Analytics" } %>
|
|
7
|
+
<%= poetry_navigation_menu_link(href: "#") { "Automation" } %>
|
|
8
|
+
<%= poetry_navigation_menu_link(href: "#") { "Reports" } %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% nav.with_link("Pricing", href: "#") %>
|
|
12
|
+
<% nav.with_link("Docs", href: "#") %>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<%= content_tag(:nav, **root_attributes.to_attributes) do %>
|
|
2
|
+
<div data-slot="navigation-menu-list" class="<%= css(:list) %>">
|
|
3
|
+
<% entries.each do |entry| %>
|
|
4
|
+
<%= content_tag(:div, item_attributes(entry)) do %>
|
|
5
|
+
<% if entry.panel %>
|
|
6
|
+
<%= content_tag(:button, trigger_attributes(entry)) do %>
|
|
7
|
+
<%= entry.title %>
|
|
8
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :"chevron-down",
|
|
9
|
+
class: css(:chevron), "aria-hidden": "true") %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<%= content_tag(:div, capture(&entry.panel), panel_attributes(entry)) %>
|
|
12
|
+
<% else %>
|
|
13
|
+
<a href="<%= entry.href %>" data-slot="navigation-menu-link" class="<%= css(:trigger) %>"><%= entry.title %></a>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
18
|
+
<% if viewport %>
|
|
19
|
+
<%= content_tag(:div, positioner_attributes) do %>
|
|
20
|
+
<div data-slot="navigation-menu-popup" data-closed class="<%= css(:popup) %>">
|
|
21
|
+
<div data-slot="navigation-menu-viewport" class="<%= css(:viewport_shell) %>"></div>
|
|
22
|
+
</div>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% end %>
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A site-navigation bar with disclosure panels.
|
|
6
|
+
module NavigationMenu
|
|
7
|
+
# A site-navigation bar - a <nav> landmark, never a menu role:
|
|
8
|
+
# top-level links plus triggers whose panels of links open on
|
|
9
|
+
# hover or click beneath their items. It is a DISCLOSURE bar,
|
|
10
|
+
# so Tab moves through it normally and nothing traps focus.
|
|
11
|
+
#
|
|
12
|
+
# By default each panel opens under its own item. viewport: true
|
|
13
|
+
# switches to one shared card that morphs its size and position
|
|
14
|
+
# between triggers - the fit for rich title-and-description panel
|
|
15
|
+
# grids.
|
|
16
|
+
#
|
|
17
|
+
# @example Disclosure bar with a panel and a link
|
|
18
|
+
# <%= poetry_navigation_menu(label: "Main") do |nav| %>
|
|
19
|
+
# <% nav.with_item("Products", value: "products") do %>
|
|
20
|
+
# <%= poetry_navigation_menu_link(href: products_path) { "All products" } %>
|
|
21
|
+
# <% end %>
|
|
22
|
+
# <% nav.with_link("Docs", href: docs_path) %>
|
|
23
|
+
# <% end %>
|
|
24
|
+
class Component < Poetry::Core::Component
|
|
25
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
26
|
+
AGENT_RULES = [
|
|
27
|
+
"label: is REQUIRED (the nav landmark's accessible name).",
|
|
28
|
+
"with_item(title, value:) declares a trigger + panel; with_link(title, href:) is a " \
|
|
29
|
+
"top-level destination - use links for pages, panels for groups of links.",
|
|
30
|
+
"Panel content is poetry_navigation_menu_link entries (active: marks the current page) - " \
|
|
31
|
+
"never buttons; navigation navigates.",
|
|
32
|
+
"This is a DISCLOSURE bar: Tab moves through it normally and nothing traps - do not " \
|
|
33
|
+
"wire menu/menuitem roles.",
|
|
34
|
+
"Rich panels (title + description grids) want viewport: true - the shared morphing " \
|
|
35
|
+
"card contains and sizes them; the default per-item mode suits simple link lists " \
|
|
36
|
+
"(the top-nav block shows the viewport pattern)."
|
|
37
|
+
].freeze
|
|
38
|
+
|
|
39
|
+
# One declared bar entry - a link (href:) or a trigger + panel pair.
|
|
40
|
+
# @api private
|
|
41
|
+
Entry = Data.define(:title, :value, :href, :panel)
|
|
42
|
+
|
|
43
|
+
renders_many :items,
|
|
44
|
+
doc: "The bar entries. with_item(title, value:) { panel } declares a trigger + panel; " \
|
|
45
|
+
"with_item(title, href:) a top-level link (with_link is the shorthand).",
|
|
46
|
+
renders: lambda { |title, value: nil, href: nil, &panel|
|
|
47
|
+
if href.nil? && panel.nil?
|
|
48
|
+
raise ArgumentError,
|
|
49
|
+
"NavigationMenu item #{title.inspect} needs href: (a link) or a panel block"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
entries << Entry.new(title: title, value: value&.to_s || title.to_s.parameterize, href: href,
|
|
53
|
+
panel: panel)
|
|
54
|
+
nil
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
use_stimulus do
|
|
58
|
+
on :root do
|
|
59
|
+
controller :navigation_menu do
|
|
60
|
+
register
|
|
61
|
+
action :keydown, on: :keydown
|
|
62
|
+
action :focus_left, on: :focusout
|
|
63
|
+
end
|
|
64
|
+
# The whole positioning engine is viewport-gated.
|
|
65
|
+
controller :popper, if: :viewport do
|
|
66
|
+
register
|
|
67
|
+
value :side, "bottom"
|
|
68
|
+
value :align, "start"
|
|
69
|
+
value :side_offset, 6
|
|
70
|
+
value :strategy, "absolute"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
# Hover intent per panel-bearing item (the call site gates
|
|
74
|
+
# per-entry - plain links carry no wiring).
|
|
75
|
+
on :item do
|
|
76
|
+
controller :navigation_menu do
|
|
77
|
+
action :schedule_open, on: :pointerenter
|
|
78
|
+
action :schedule_close, on: :pointerleave
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
on :trigger do
|
|
82
|
+
controller(:navigation_menu) { action :toggle, on: :click }
|
|
83
|
+
end
|
|
84
|
+
# BOTH controllers on ONE element, declared together - the wiring
|
|
85
|
+
# merges through the Builder, never as two separate Attributes
|
|
86
|
+
# joined with plain Hash#merge (that drops one controller's
|
|
87
|
+
# tokens).
|
|
88
|
+
on :positioner do
|
|
89
|
+
controller(:popper) { target :content }
|
|
90
|
+
controller :navigation_menu do
|
|
91
|
+
action :cancel_close, on: :pointerenter
|
|
92
|
+
action :schedule_close, on: :pointerleave
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
option :label, :string, required: true,
|
|
98
|
+
doc: "The nav landmark's accessible name - a page may hold more than one nav."
|
|
99
|
+
option :viewport, :boolean, default: false,
|
|
100
|
+
doc: "Opts into the shared morphing viewport: panels adopt into one positioned " \
|
|
101
|
+
"card that morphs size and position between triggers. Off, each panel opens " \
|
|
102
|
+
"under its own item (also the no-JS shape)."
|
|
103
|
+
|
|
104
|
+
part "navigation-menu", "The <nav> landmark around the whole disclosure bar",
|
|
105
|
+
states: {
|
|
106
|
+
"data-viewport" => "the mode marker (\"true\" = shared morphing viewport, \"false\" = " \
|
|
107
|
+
"per-item panels) - the dictionary's group-data chrome keys on it"
|
|
108
|
+
}
|
|
109
|
+
part "navigation-menu-list", "The bar row holding every item"
|
|
110
|
+
part "navigation-menu-item", "One bar entry - wraps a trigger + panel pair or a top-level link",
|
|
111
|
+
states: {
|
|
112
|
+
"data-value" => "the entry's value - the controller's open/close key"
|
|
113
|
+
}
|
|
114
|
+
part "navigation-menu-trigger", "The disclosure button opening its panel",
|
|
115
|
+
states: {
|
|
116
|
+
"data-popup-open" => "its panel is open (written with aria-expanded - the chevron " \
|
|
117
|
+
"rotation hook)",
|
|
118
|
+
"data-open" => "its panel is open (the controller writes both vocabularies)",
|
|
119
|
+
"data-closed" => "its panel is closed (written after the first close)"
|
|
120
|
+
}
|
|
121
|
+
part "navigation-menu-content", "One item's panel - presence-animated; in viewport mode it is " \
|
|
122
|
+
"adopted into the shared viewport on first activation",
|
|
123
|
+
states: {
|
|
124
|
+
"data-open" => "panel is open (presence flips the pair at runtime)",
|
|
125
|
+
"data-closed" => "panel is closed or animating out (the server-rendered state)",
|
|
126
|
+
"data-activation-direction" => "which way the activation traveled between triggers " \
|
|
127
|
+
"(left/right, viewport mode) - keys the slide styles",
|
|
128
|
+
"data-viewport-panel" => "stamped once the panel is adopted into the shared viewport"
|
|
129
|
+
}
|
|
130
|
+
part "navigation-menu-positioner", "The viewport-mode shell popper positions against the " \
|
|
131
|
+
"active trigger",
|
|
132
|
+
states: {
|
|
133
|
+
"data-instant" => "suppresses the morph transitions for one painted frame (cold opens)"
|
|
134
|
+
},
|
|
135
|
+
vars: {
|
|
136
|
+
"--positioner-width" => "the pinned morph width (reset to auto once the transition settles)",
|
|
137
|
+
"--positioner-height" => "the pinned morph height (reset to auto once the transition settles)"
|
|
138
|
+
}
|
|
139
|
+
part "navigation-menu-popup", "The morphing card inside the positioner - open state and the " \
|
|
140
|
+
"size transition ride here",
|
|
141
|
+
states: {
|
|
142
|
+
"data-open" => "a panel is showing (the controller flips the pair)",
|
|
143
|
+
"data-closed" => "the popup is closed (the server-rendered state)",
|
|
144
|
+
"data-instant" => "suppresses the morph transitions for one painted frame (cold opens)",
|
|
145
|
+
"data-starting-style" => "the enter transition's first frame (the presence module's " \
|
|
146
|
+
"two-frame trick)",
|
|
147
|
+
"data-ending-style" => "held through the exit transition before the popup hides"
|
|
148
|
+
},
|
|
149
|
+
vars: {
|
|
150
|
+
"--popup-width" => "the pinned morph width (reset to auto once the transition settles)",
|
|
151
|
+
"--popup-height" => "the pinned morph height (reset to auto once the transition settles)"
|
|
152
|
+
}
|
|
153
|
+
part "navigation-menu-viewport", "The adoption container inside the popup - adopted panels " \
|
|
154
|
+
"stack absolutely in it"
|
|
155
|
+
part "navigation-menu-link", "A REAL destination link - top-level (with_link) or a panel entry " \
|
|
156
|
+
"(poetry_navigation_menu_link)",
|
|
157
|
+
states: {
|
|
158
|
+
"data-active" => "the current page (active: true)"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
# Enforces the required label and at least one entry.
|
|
162
|
+
# @api private
|
|
163
|
+
def before_render
|
|
164
|
+
raise ArgumentError, "NavigationMenu requires label: (the nav landmark's name)" if label.blank?
|
|
165
|
+
raise ArgumentError, "NavigationMenu requires at least one with_item or with_link" unless items?
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Declares a top-level destination link - shorthand for
|
|
169
|
+
# with_item(title, href:).
|
|
170
|
+
# @param title [String] the visible link text
|
|
171
|
+
# @param href [String] the destination URL
|
|
172
|
+
def with_link(title, href:)
|
|
173
|
+
with_item(title, href: href)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# The declared entries, in bar order.
|
|
177
|
+
# @api private
|
|
178
|
+
def entries
|
|
179
|
+
@entries ||= []
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# @api private
|
|
183
|
+
def root_attributes
|
|
184
|
+
html_attributes.merge_if_not_set(
|
|
185
|
+
{
|
|
186
|
+
"aria-label" => label, "data-slot" => "navigation-menu",
|
|
187
|
+
# The mode marker the dictionary's group-data-[viewport=false]
|
|
188
|
+
# chrome keys on.
|
|
189
|
+
"data-viewport" => viewport.to_s
|
|
190
|
+
}.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
191
|
+
)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @api private
|
|
195
|
+
def item_attributes(entry)
|
|
196
|
+
attrs = {
|
|
197
|
+
"data-slot" => "navigation-menu-item", "data-value" => entry.value,
|
|
198
|
+
"class" => css(:item)
|
|
199
|
+
}
|
|
200
|
+
attrs.merge!(stimulus_attributes_for(:item)) if entry.panel
|
|
201
|
+
attrs
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# @api private
|
|
205
|
+
def trigger_attributes(entry)
|
|
206
|
+
{
|
|
207
|
+
"type" => "button", "data-slot" => "navigation-menu-trigger",
|
|
208
|
+
"aria-expanded" => "false", "aria-controls" => panel_id(entry),
|
|
209
|
+
"class" => "#{css(:trigger)} group"
|
|
210
|
+
}.merge(stimulus_attributes_for(:trigger))
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# @api private
|
|
214
|
+
def panel_attributes(entry)
|
|
215
|
+
{
|
|
216
|
+
"id" => panel_id(entry), "data-slot" => "navigation-menu-content",
|
|
217
|
+
"data-closed" => "", "hidden" => true,
|
|
218
|
+
# Viewport mode: panels stack absolutely inside the shared viewport
|
|
219
|
+
# (adopted on first activation); per-item mode positions under the
|
|
220
|
+
# relative item.
|
|
221
|
+
"class" => "#{css(:content)} #{viewport ? css(:viewport_panel) : css(:content_position)}"
|
|
222
|
+
}
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# The shared shell (viewport mode): the positioner is re-anchored
|
|
226
|
+
# against the ACTIVE trigger on each activation with the full
|
|
227
|
+
# positioning engine; the popup carries the morphing size vars;
|
|
228
|
+
# panels adopt into the viewport.
|
|
229
|
+
# @api private
|
|
230
|
+
def positioner_attributes
|
|
231
|
+
attrs = {
|
|
232
|
+
"data-slot" => "navigation-menu-positioner", "hidden" => true,
|
|
233
|
+
"class" => css(:positioner)
|
|
234
|
+
}
|
|
235
|
+
attrs.merge(stimulus_attributes_for(:positioner))
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# @api private
|
|
239
|
+
def panel_id(entry)
|
|
240
|
+
"#{instance_id}-panel-#{entry.value}"
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
private
|
|
244
|
+
|
|
245
|
+
def instance_id
|
|
246
|
+
@instance_id ||= poetry_instance_id("poetry-nav")
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
private :entries, :root_attributes, :item_attributes, :trigger_attributes, :panel_attributes
|
|
250
|
+
private :positioner_attributes, :panel_id
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module NavigationMenu
|
|
6
|
+
# The NavigationMenu preview: a bar with a panel item and plain links
|
|
7
|
+
# (the panel opens on hover/click - the dommy tier drives it; the
|
|
8
|
+
# sidecar template composes the panel's link grid).
|
|
9
|
+
class Preview < Poetry::Core::Preview::Base
|
|
10
|
+
def default
|
|
11
|
+
render_with_template(template: "poetry/ui/navigation_menu/bar_preview")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def viewport
|
|
15
|
+
render_with_template(template: "poetry/ui/navigation_menu/viewport_preview")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module NavigationMenu
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The morph
|
|
7
|
+
# machinery stays ENTIRELY inline (positioner insets + size-var
|
|
8
|
+
# transitions, panel adoption pins, activation-direction slides,
|
|
9
|
+
# data-instant suppressors) - a swapped theme restyles the popup
|
|
10
|
+
# surface, never the morph. The viewport=false chrome chain and the
|
|
11
|
+
# trigger/link treatments ride the theme.
|
|
12
|
+
class Style < Poetry::Core::Style
|
|
13
|
+
base "cn-navigation-menu group/navigation-menu relative flex max-w-max flex-1 items-center justify-center"
|
|
14
|
+
|
|
15
|
+
element :list, "cn-navigation-menu-list group flex flex-1 list-none items-center justify-center"
|
|
16
|
+
element :item, "relative"
|
|
17
|
+
|
|
18
|
+
element :trigger, "cn-navigation-menu-trigger group/navigation-menu-trigger inline-flex h-9 " \
|
|
19
|
+
"w-max items-center justify-center outline-none " \
|
|
20
|
+
"disabled:pointer-events-none disabled:opacity-50"
|
|
21
|
+
element :chevron, "cn-navigation-menu-trigger-icon relative top-px transition duration-300 " \
|
|
22
|
+
"group-data-popup-open/navigation-menu-trigger:rotate-180 " \
|
|
23
|
+
"group-data-open/navigation-menu-trigger:rotate-180"
|
|
24
|
+
|
|
25
|
+
# The activation-direction slides stay inline (authored as VALID
|
|
26
|
+
# Tailwind variants - upstream's own strings are malformed and
|
|
27
|
+
# compile to nothing): content slides
|
|
28
|
+
# in FROM the travel direction and out the other way.
|
|
29
|
+
# h-full is the VIEWPORT-mode contract (the panel fills the
|
|
30
|
+
# morphing popup box); inline panels size to their content - an
|
|
31
|
+
# unscoped h-full clamps them to the 36px list item and the
|
|
32
|
+
# popover chrome paints short of the rows.
|
|
33
|
+
element :content,
|
|
34
|
+
"cn-navigation-menu-content w-auto " \
|
|
35
|
+
"group-data-[viewport=true]/navigation-menu:h-full " \
|
|
36
|
+
"transition-[opacity,transform,translate] duration-[0.35s] " \
|
|
37
|
+
"ease-[cubic-bezier(0.22,1,0.36,1)] " \
|
|
38
|
+
"group-data-[viewport=false]/navigation-menu:duration-300 " \
|
|
39
|
+
"data-ending-style:opacity-0 data-starting-style:opacity-0 " \
|
|
40
|
+
"data-[activation-direction=right]:data-starting-style:translate-x-1/2 " \
|
|
41
|
+
"data-[activation-direction=left]:data-starting-style:-translate-x-1/2 " \
|
|
42
|
+
"data-[activation-direction=right]:data-ending-style:-translate-x-1/2 " \
|
|
43
|
+
"data-[activation-direction=left]:data-ending-style:translate-x-1/2 " \
|
|
44
|
+
"**:data-[slot=navigation-menu-link]:focus:ring-0 " \
|
|
45
|
+
"**:data-[slot=navigation-menu-link]:focus:outline-none"
|
|
46
|
+
element :content_position, "absolute top-full left-0 isolate z-50 mt-1.5 w-max min-w-48"
|
|
47
|
+
|
|
48
|
+
# The morphing shared viewport: the popper writes the positioner's
|
|
49
|
+
# insets (CSS transitions them - the position morph); the popup pins
|
|
50
|
+
# --popup-width/height old -> new so size transitions; panels stack
|
|
51
|
+
# absolutely inside the viewport and size intrinsically. data-instant
|
|
52
|
+
# (cold opens) suppresses both transitions for a frame.
|
|
53
|
+
element :positioner, "absolute isolate z-50 w-(--positioner-width) h-(--positioner-height) " \
|
|
54
|
+
"transition-[top,left,right,bottom] duration-[0.35s] " \
|
|
55
|
+
"ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none"
|
|
56
|
+
element :popup, "cn-navigation-menu-popup relative h-(--popup-height) w-(--popup-width) " \
|
|
57
|
+
"overflow-hidden transition-[width,height] duration-[0.35s] " \
|
|
58
|
+
"ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none"
|
|
59
|
+
# The ACTIVE panel sits in flow - after the settle reset returns the
|
|
60
|
+
# size vars to auto, IT is what sizes the popup (all-absolute panels
|
|
61
|
+
# would collapse the auto popup to 0x0). Only an EXITING panel lifts
|
|
62
|
+
# out of flow (data-ending-style rides the whole exit), overlaying
|
|
63
|
+
# the incoming one while both are visible - the crossfade, done
|
|
64
|
+
# declaratively.
|
|
65
|
+
element :viewport_shell, "relative overflow-hidden"
|
|
66
|
+
element :viewport_panel, "w-max min-w-48 data-ending-style:absolute " \
|
|
67
|
+
"data-ending-style:top-0 data-ending-style:left-0"
|
|
68
|
+
|
|
69
|
+
element :link, "cn-navigation-menu-link flex items-center outline-none"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<%# The morphing shared viewport: two panel items - switching between
|
|
2
|
+
them morphs the shared popup's size and position; panels slide by
|
|
3
|
+
activation direction. %>
|
|
4
|
+
<div class="flex min-h-72 justify-center p-4">
|
|
5
|
+
<%= poetry_navigation_menu(label: "Main", viewport: true) do |nav| %>
|
|
6
|
+
<% nav.with_item("Products", value: "products") do %>
|
|
7
|
+
<div class="grid w-64 gap-1">
|
|
8
|
+
<%= poetry_navigation_menu_link(href: "#", active: true) { "Analytics" } %>
|
|
9
|
+
<%= poetry_navigation_menu_link(href: "#") { "Automation" } %>
|
|
10
|
+
<%= poetry_navigation_menu_link(href: "#") { "Reports" } %>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% nav.with_item("Company", value: "company") do %>
|
|
14
|
+
<div class="grid w-96 grid-cols-2 gap-1">
|
|
15
|
+
<%= poetry_navigation_menu_link(href: "#") { "About" } %>
|
|
16
|
+
<%= poetry_navigation_menu_link(href: "#") { "Careers" } %>
|
|
17
|
+
<%= poetry_navigation_menu_link(href: "#") { "Press" } %>
|
|
18
|
+
<%= poetry_navigation_menu_link(href: "#") { "Contact" } %>
|
|
19
|
+
</div>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% nav.with_link("Docs", href: "#") %>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<%# Two-input architecture (Base UI): the group holds the formatted
|
|
2
|
+
visible text input between two stepper addons; the hidden number
|
|
3
|
+
input beside it is the form/validation truth. %>
|
|
4
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
5
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(group_attributes).to_attributes) do %>
|
|
6
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(addon_attributes(:start)).to_attributes) do %>
|
|
7
|
+
<%= render stepper(:decrement) do %>
|
|
8
|
+
<%= render Poetry::Ui::Icon::Component.new(name: stepper_icon(:decrement)) %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<%= tag.input(**input_attributes.to_attributes) %>
|
|
12
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(addon_attributes(:end)).to_attributes) do %>
|
|
13
|
+
<%= render stepper(:increment) do %>
|
|
14
|
+
<%= render Poetry::Ui::Icon::Component.new(name: stepper_icon(:increment)) %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|
|
18
|
+
<%= tag.input(**hidden_attributes.to_attributes) %>
|
|
19
|
+
<% end %>
|