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,185 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Hover/focus text hints.
|
|
6
|
+
module Tooltip
|
|
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 hover/focus text hint. The bubble describes its trigger and
|
|
13
|
+
# never receives focus: content is role=tooltip, the trigger's
|
|
14
|
+
# aria-describedby exists only while open (a description pointing
|
|
15
|
+
# at hidden content mis-announces), and no aria-haspopup/expanded
|
|
16
|
+
# is written - a tooltip is a description, not a popup the user
|
|
17
|
+
# operates. Opening is delayed on hover but instant on keyboard
|
|
18
|
+
# focus; only one tooltip is open globally; Esc closes the tooltip
|
|
19
|
+
# first when overlays are stacked; touch never opens one, so
|
|
20
|
+
# essential information must never live only in a tooltip.
|
|
21
|
+
#
|
|
22
|
+
# Content must be plain text, never interactive - use Popover for
|
|
23
|
+
# links or controls. Wrap rows of triggers in one
|
|
24
|
+
# poetry_tooltip_provider so moving along the row skips the delay.
|
|
25
|
+
#
|
|
26
|
+
# @example A described icon button
|
|
27
|
+
# render Poetry::Ui::Tooltip::Component.new do |tooltip|
|
|
28
|
+
# tooltip.with_trigger(variant: :outline, size: :icon, label: "Print") do
|
|
29
|
+
# poetry_icon(name: :printer)
|
|
30
|
+
# end
|
|
31
|
+
# "Print the current page"
|
|
32
|
+
# end
|
|
33
|
+
class Component < Poetry::Core::Component
|
|
34
|
+
include Poetry::Ui::ComposableTrigger
|
|
35
|
+
include Poetry::Ui::PopperConsumer
|
|
36
|
+
|
|
37
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
38
|
+
AGENT_RULES = [
|
|
39
|
+
ComposableTrigger::AGENT_RULE,
|
|
40
|
+
"Use poetry_tooltip - never hand-roll title-attribute replacements or hover divs.",
|
|
41
|
+
"Tooltip content is TEXT and never interactive/focusable - links, buttons, or inputs inside " \
|
|
42
|
+
"are a contract violation (use Popover).",
|
|
43
|
+
"Never put essential information only in a tooltip - touch users NEVER see it (no long-press " \
|
|
44
|
+
"path, by design).",
|
|
45
|
+
"The tooltip DESCRIBES; it never names. Icon-only triggers still require label: on the " \
|
|
46
|
+
"composed Button.",
|
|
47
|
+
"Wrap toolbar/button rows in ONE poetry_tooltip_provider so the warm grace makes the row " \
|
|
48
|
+
"feel continuous.",
|
|
49
|
+
"Rich visual content needs label: (the plain-text announcement).",
|
|
50
|
+
"Do not pin tooltips open as onboarding callouts - that is a Popover."
|
|
51
|
+
].freeze
|
|
52
|
+
|
|
53
|
+
# The same facts the before_render raise enforces, stated statically:
|
|
54
|
+
# poetry check flags the omission without rendering.
|
|
55
|
+
REQUIRED_SLOTS = { trigger: "the described control" }.freeze
|
|
56
|
+
|
|
57
|
+
# The component behind the forwarding slot: with_trigger renders a Button.
|
|
58
|
+
SLOT_RENDERS = { trigger: Button::Component }.freeze
|
|
59
|
+
|
|
60
|
+
renders_one :trigger,
|
|
61
|
+
doc: "The described control - commonly a poetry Button (with_trigger(variant: :outline) { " \
|
|
62
|
+
"\"Hover\" }). The slot owns the state + timing wiring regardless of the composed content. " \
|
|
63
|
+
"NO aria-haspopup/expanded/controls - the tooltip is invisible as a popup; " \
|
|
64
|
+
"aria-describedby is written by the controller on open (and server-rendered only when " \
|
|
65
|
+
"open: true).",
|
|
66
|
+
renders: lambda { |**options, &block|
|
|
67
|
+
wiring = {
|
|
68
|
+
"id" => trigger_id, "data-slot" => "tooltip-trigger"
|
|
69
|
+
}.merge(stimulus_attributes_for(:trigger))
|
|
70
|
+
# Open state is a bare data-popup-open presence attribute -
|
|
71
|
+
# absent while closed (absence IS the state).
|
|
72
|
+
wiring["data-popup-open"] = "" if open
|
|
73
|
+
wiring["aria-describedby"] = content_id if open
|
|
74
|
+
composed_trigger(wiring, options, &block) ||
|
|
75
|
+
Button::Component.new(**wiring, **options, &block)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
use_stimulus do
|
|
79
|
+
on :root do
|
|
80
|
+
# Full identifier: the bare :tooltip suffix is ambiguous the
|
|
81
|
+
# moment a host also loads poetry-charts (poetry--charts--
|
|
82
|
+
# tooltip joins the manifest catalog).
|
|
83
|
+
controller "poetry--core--tooltip" do
|
|
84
|
+
register
|
|
85
|
+
value :open
|
|
86
|
+
# Inherit-from-provider: unset renders NO attribute - the
|
|
87
|
+
# controller falls back to [data-slot=tooltip-provider].
|
|
88
|
+
value :delay_duration, unless: -> { delay_duration.nil? }
|
|
89
|
+
value :disable_hoverable_content, unless: -> { disable_hoverable_content.nil? }
|
|
90
|
+
end
|
|
91
|
+
controller :popper do
|
|
92
|
+
register
|
|
93
|
+
value :side
|
|
94
|
+
value :align
|
|
95
|
+
value :side_offset
|
|
96
|
+
value :align_offset
|
|
97
|
+
value :avoid_collisions
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
# The trigger handlers: pointermove opens (touch excluded, once
|
|
101
|
+
# per hover), pointerdown/click close, focus opens instantly /
|
|
102
|
+
# blur closes.
|
|
103
|
+
on :trigger do
|
|
104
|
+
controller "poetry--core--tooltip" do
|
|
105
|
+
action :pointer_move, on: :pointermove
|
|
106
|
+
action :pointer_leave, on: :pointerleave
|
|
107
|
+
action :pointer_down, on: :pointerdown
|
|
108
|
+
action :click_close, on: :click
|
|
109
|
+
action :focus_open, on: :focus
|
|
110
|
+
action :blur_close, on: :blur
|
|
111
|
+
end
|
|
112
|
+
controller(:popper) { target :anchor }
|
|
113
|
+
end
|
|
114
|
+
on :content do
|
|
115
|
+
controller(:popper) { target :content }
|
|
116
|
+
end
|
|
117
|
+
# The arrow's positioning target.
|
|
118
|
+
on :arrow do
|
|
119
|
+
controller(:popper) { target :arrow }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
option :open, :boolean, default: false, doc: "Server-renders the tooltip open."
|
|
124
|
+
option :delay_duration, :integer, doc: "The hover-open delay in ms; nil inherits the provider's (default 0)."
|
|
125
|
+
option :disable_hoverable_content, :boolean,
|
|
126
|
+
doc: "When true the bubble closes as the pointer leaves the trigger - it cannot be hovered into; nil " \
|
|
127
|
+
"inherits the provider."
|
|
128
|
+
# Placement defaults: :top with side_offset 0 (the arrow supplies the gap).
|
|
129
|
+
popper_placement_options(side: :top, side_offset: 0)
|
|
130
|
+
option :label, :string,
|
|
131
|
+
doc: "Plain-text announcement override for rich content (the visual children stay; the announced body " \
|
|
132
|
+
"becomes this text)."
|
|
133
|
+
option :content_class, :string, doc: "The bubble's class merge seam (caller classes win on conflicts)."
|
|
134
|
+
|
|
135
|
+
part "tooltip", "Root wrapper around the trigger and the bubble"
|
|
136
|
+
part "tooltip-content", "The role=tooltip bubble - positioning, animation, and the open " \
|
|
137
|
+
"state ride here",
|
|
138
|
+
states: {
|
|
139
|
+
"data-open" => "bubble is open (the controller flips the pair at runtime)",
|
|
140
|
+
"data-closed" => "bubble is closed (the server-rendered state; hidden rides along)",
|
|
141
|
+
"data-instant" => { condition: "the open skipped the delay - warm-grace/" \
|
|
142
|
+
"programmatic or keyboard focus (runtime-only; " \
|
|
143
|
+
"absent on a delayed open)",
|
|
144
|
+
values: %w[delay focus] },
|
|
145
|
+
"data-side" => { condition: "always - the side (initial placement, re-resolved " \
|
|
146
|
+
"live by popper after flip)",
|
|
147
|
+
values: SIDES.map(&:to_s) },
|
|
148
|
+
"data-align" => { condition: "always - the alignment (re-resolved live by popper)",
|
|
149
|
+
values: ALIGNS.map(&:to_s) }
|
|
150
|
+
},
|
|
151
|
+
vars: Poetry::Ui::PopperConsumer.content_vars("bubble")
|
|
152
|
+
part "tooltip-arrow", "The arrow wrapper (aria-hidden) - popper pins it to the bubble's " \
|
|
153
|
+
"anchor-facing edge and rotates it toward the anchor",
|
|
154
|
+
states: {
|
|
155
|
+
"data-side" => { condition: "written by popper alongside the content's - the " \
|
|
156
|
+
"resolved side, for per-side restyling",
|
|
157
|
+
values: SIDES.map(&:to_s) }
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# @api private
|
|
161
|
+
def before_render
|
|
162
|
+
raise ArgumentError, "Tooltip requires with_trigger (the described control)" unless trigger?
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @api private
|
|
166
|
+
def content_attributes
|
|
167
|
+
# A server-pinned open tooltip renders bare data-open; the
|
|
168
|
+
# controller adds data-instant on ITS opens - the reason
|
|
169
|
+
# attribute is runtime-only.
|
|
170
|
+
attrs = {
|
|
171
|
+
"id" => content_id, "role" => "tooltip",
|
|
172
|
+
"data-slot" => "tooltip-content", (open ? "data-open" : "data-closed") => "",
|
|
173
|
+
# Initial placement, re-resolved live by popper on open.
|
|
174
|
+
"data-side" => side, "data-align" => align,
|
|
175
|
+
"class" => css(:content, class: content_class)
|
|
176
|
+
}.merge(stimulus_attributes_for(:content))
|
|
177
|
+
attrs["hidden"] = true unless open
|
|
178
|
+
attrs
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
private :content_attributes
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Tooltip
|
|
6
|
+
# The Tooltip preview matrix: the ported tooltip-demo composition,
|
|
7
|
+
# the provider warm row (one scope, three controls), the label:
|
|
8
|
+
# announcement override, a placement sample, the provider-style opt-back
|
|
9
|
+
# delay, and the server-pinned open state.
|
|
10
|
+
class Preview < Poetry::Core::Preview::Base
|
|
11
|
+
# The tooltip-demo port: outline Button trigger, plain text hint.
|
|
12
|
+
def default
|
|
13
|
+
render_component do |tooltip|
|
|
14
|
+
tooltip.with_trigger(variant: :outline) { "Hover" }
|
|
15
|
+
"Add to library"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# ONE provider scope: the first open is delayed, sweeping along
|
|
20
|
+
# the row is instant (the warm grace), cold again 300ms after
|
|
21
|
+
# leaving - wrap toolbar rows exactly like this.
|
|
22
|
+
def provider_row
|
|
23
|
+
render_with_template
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Rich visual content with label: - the announced body is the
|
|
27
|
+
# plain-text label; the visual children stay (the kbd recipe).
|
|
28
|
+
def with_label
|
|
29
|
+
render_component(label: "Command S saves the document") do |tooltip|
|
|
30
|
+
tooltip.with_trigger(variant: :outline, label: "Save shortcut") { "Save" }
|
|
31
|
+
"Saves the document <kbd>⌘S</kbd>".html_safe
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Server-pinned open (controllable-state; the controller
|
|
36
|
+
# reconciles describedby + the layer on connect).
|
|
37
|
+
def open
|
|
38
|
+
render_component(open: true) do |tooltip|
|
|
39
|
+
tooltip.with_trigger(variant: :outline) { "Pinned" }
|
|
40
|
+
"Server-rendered open"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Placement sample (the ported source defaults side: :top - the trio's
|
|
45
|
+
# odd one out; the arrow follows the resolved side).
|
|
46
|
+
def side_bottom
|
|
47
|
+
render_component(side: :bottom, align: :start) do |tooltip|
|
|
48
|
+
tooltip.with_trigger(variant: :outline) { "Below" }
|
|
49
|
+
"side: :bottom, align: :start"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# the provider-style opt-back for hint-dense screens: the source's provider
|
|
54
|
+
# default is 0ms; 700ms is the recommended delay when a page is
|
|
55
|
+
# dense with tooltips.
|
|
56
|
+
def delayed
|
|
57
|
+
render_component(delay_duration: 700) do |tooltip|
|
|
58
|
+
tooltip.with_trigger(variant: :outline) { "Patient hover" }
|
|
59
|
+
"Opens after 700ms"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# disable_hoverable_content: true - pointing at the card itself
|
|
64
|
+
# never holds it open (the strict hover mode).
|
|
65
|
+
def not_hoverable
|
|
66
|
+
render_component(disable_hoverable_content: true) do |tooltip|
|
|
67
|
+
tooltip.with_trigger(variant: :outline) { "Hover" }
|
|
68
|
+
"Closes the moment you leave the trigger"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<%# ONE provider scope wrapping a control row: the first tooltip opens
|
|
2
|
+
delayed, sweeping along the row opens instantly (the warm grace), and
|
|
3
|
+
the scope cools 300ms after leaving - the toolbar recipe. %>
|
|
4
|
+
<div class="p-4">
|
|
5
|
+
<%= poetry_tooltip_provider(delay_duration: 700, class: "flex items-center gap-2") do %>
|
|
6
|
+
<%= poetry_tooltip do |tooltip| %>
|
|
7
|
+
<% tooltip.with_trigger(variant: :outline, size: :icon, label: "Add") do %>
|
|
8
|
+
<%= poetry_icon(name: :plus) %>
|
|
9
|
+
<% end %>
|
|
10
|
+
Add
|
|
11
|
+
<% end %>
|
|
12
|
+
<%= poetry_tooltip do |tooltip| %>
|
|
13
|
+
<% tooltip.with_trigger(variant: :outline, size: :icon, label: "Confirm") do %>
|
|
14
|
+
<%= poetry_icon(name: :check) %>
|
|
15
|
+
<% end %>
|
|
16
|
+
Confirm
|
|
17
|
+
<% end %>
|
|
18
|
+
<%= poetry_tooltip do |tooltip| %>
|
|
19
|
+
<% tooltip.with_trigger(variant: :outline, size: :icon, label: "Dismiss") do %>
|
|
20
|
+
<%= poetry_icon(name: :x) %>
|
|
21
|
+
<% end %>
|
|
22
|
+
Dismiss
|
|
23
|
+
<% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Tooltip
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The inverse scheme
|
|
7
|
+
# (bg-foreground/text-background) stays INLINE per upstream's own
|
|
8
|
+
# split - it IS the treatment and upstream keeps it in markup; the
|
|
9
|
+
# box, type, and animation chain ride the theme (animate-in remains
|
|
10
|
+
# UNGATED there, source-exact).
|
|
11
|
+
class Style < Poetry::Core::Style
|
|
12
|
+
element :content, "cn-tooltip-content z-50 w-fit origin-(--transform-origin) bg-foreground " \
|
|
13
|
+
"text-background max-w-xs"
|
|
14
|
+
|
|
15
|
+
# The arrow: popper positions/rotates the outer box; the visual
|
|
16
|
+
# size/rounding rides the theme, the paint + geometry stay inline.
|
|
17
|
+
# block: the diamond is a bare span - inline boxes IGNORE size-2.5,
|
|
18
|
+
# which left the arrow 0x0 (invisible) in every theme since the port.
|
|
19
|
+
element :arrow, "cn-tooltip-arrow z-50 block translate-y-[calc(-50%_-_2px)] rotate-45 " \
|
|
20
|
+
"bg-foreground fill-foreground"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<%# The flat treegrid: every row a sibling, hierarchy in aria-* computed
|
|
2
|
+
server-side, rows under collapsed ancestors hidden. %>
|
|
3
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
4
|
+
<% if rows.any? %>
|
|
5
|
+
<% rows.each_with_index do |row, index| %>
|
|
6
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(row_attributes(row, index)).to_attributes) do %>
|
|
7
|
+
<span role="gridcell" class="<%= css(:cell) %>">
|
|
8
|
+
<% if row.expandable %>
|
|
9
|
+
<%= content_tag(:button, **Poetry::Core::HTML::Attributes.new(toggle_attributes(row, index)).to_attributes) do %>
|
|
10
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :"chevron-right") %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% else %>
|
|
13
|
+
<span class="<%= css(:toggle_spacer) %>" aria-hidden="true"></span>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% if row.href.present? && !row.disabled %>
|
|
16
|
+
<a href="<%= row.href %>" data-slot="tree-item-label" class="<%= css(:label) %>" tabindex="-1"><%= row.text %></a>
|
|
17
|
+
<% else %>
|
|
18
|
+
<span data-slot="tree-item-label" class="<%= css(:label) %>"><%= row.text %></span>
|
|
19
|
+
<% end %>
|
|
20
|
+
</span>
|
|
21
|
+
<% end %>
|
|
22
|
+
<% end %>
|
|
23
|
+
<% else %>
|
|
24
|
+
<%# An empty treegrid with bare content is invalid ARIA - the empty
|
|
25
|
+
state wraps in a placeholder row > gridcell (the contract). %>
|
|
26
|
+
<div role="row" aria-level="1" data-slot="tree-item" data-value tabindex="-1" class="<%= css(:item) %>" style="--poetry-tree-level: 1">
|
|
27
|
+
<span role="gridcell" class="<%= css(:cell) %>">
|
|
28
|
+
<span data-slot="tree-item-label" class="text-muted-foreground"><%= t("poetry.tree.empty") %></span>
|
|
29
|
+
</span>
|
|
30
|
+
</div>
|
|
31
|
+
<% end %>
|
|
32
|
+
<% end %>
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Hierarchical expandable lists.
|
|
6
|
+
module Tree
|
|
7
|
+
# A hierarchical expandable list - file navigators, nested
|
|
8
|
+
# categories, org structures. The DOM is a flat list of sibling
|
|
9
|
+
# rows; hierarchy lives entirely in server-computed
|
|
10
|
+
# aria-level/posinset/setsize, so no nested markup is needed and
|
|
11
|
+
# the whole tree server-renders. Rows under a collapsed ancestor
|
|
12
|
+
# render hidden. Arrow keys move over visible rows,
|
|
13
|
+
# ArrowLeft/Right collapse and expand (ArrowLeft on a leaf walks to
|
|
14
|
+
# the parent), Enter/press toggles, and typing jumps to a matching
|
|
15
|
+
# row.
|
|
16
|
+
#
|
|
17
|
+
# Items build through a nested builder (see with_item). Expansion
|
|
18
|
+
# state lives in the DOM - persist it by listening for
|
|
19
|
+
# poetry:tree:toggle and re-rendering with expanded: from your
|
|
20
|
+
# store. href: items navigate; a Tree offers no selection modes.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# <%= poetry_tree(label: "Files") do |tree| %>
|
|
24
|
+
# <% tree.with_item(text: "docs", value: "docs", expanded: true) do |docs| %>
|
|
25
|
+
# <% docs.with_item(text: "intro.md", value: "intro", href: "/docs/intro") %>
|
|
26
|
+
# <% end %>
|
|
27
|
+
# <% end %>
|
|
28
|
+
class Component < Poetry::Core::Component
|
|
29
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
30
|
+
AGENT_RULES = [
|
|
31
|
+
"Hierarchical expandable lists are a Tree - never hand-rolled nested <ul>s with " \
|
|
32
|
+
"click handlers; the treegrid semantics, expansion keys, and focus rules ride the " \
|
|
33
|
+
"controller.",
|
|
34
|
+
"label: is REQUIRED (the treegrid's accessible name).",
|
|
35
|
+
"Items: tree.with_item(text:, value:, expanded:, disabled:, href:) with nesting via " \
|
|
36
|
+
"the block - the component flattens and computes aria-level/posinset/setsize.",
|
|
37
|
+
"Expansion is client state; persist it by listening for poetry:tree:toggle and " \
|
|
38
|
+
"re-rendering with expanded: from your store.",
|
|
39
|
+
"Navigation destinations take href: (the label renders as a link); a Tree is not a " \
|
|
40
|
+
"menu - actions belong to DropdownMenu, picking to Select/Combobox."
|
|
41
|
+
].freeze
|
|
42
|
+
|
|
43
|
+
use_stimulus do
|
|
44
|
+
on :root do
|
|
45
|
+
controller :tree do
|
|
46
|
+
register
|
|
47
|
+
action :keydown, on: :keydown
|
|
48
|
+
action :press, on: :click
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
on :toggle do
|
|
52
|
+
controller :tree do
|
|
53
|
+
action :pressStart, on: :pointerdown
|
|
54
|
+
action :toggle, on: :click
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
option :label, :string, required: true, doc: "The tree's accessible name. Required."
|
|
60
|
+
|
|
61
|
+
part "tree", "The treegrid container (role=treegrid, the accessible name) - roving " \
|
|
62
|
+
"focus, expansion keys, and typeahead ride here; rows are FLAT siblings"
|
|
63
|
+
part "tree-item", "One row (role=row > gridcell) - hierarchy in aria-level/posinset/" \
|
|
64
|
+
"setsize, indentation via --poetry-tree-level; rows under a " \
|
|
65
|
+
"collapsed ancestor render hidden",
|
|
66
|
+
states: {
|
|
67
|
+
"data-expanded" => "the row's subtree is open (parents only; aria-expanded " \
|
|
68
|
+
"is the canonical twin)",
|
|
69
|
+
"data-disabled" => "the item is disabled (skipped by arrows and typeahead)",
|
|
70
|
+
"data-value" => { condition: "always - the toggle event's identity" },
|
|
71
|
+
"data-level" => { condition: "always - the 1-based depth (aria-level's twin; " \
|
|
72
|
+
"--poetry-tree-level drives the indent)" }
|
|
73
|
+
},
|
|
74
|
+
vars: {
|
|
75
|
+
"--poetry-tree-level" => "the 1-based depth - indentation is " \
|
|
76
|
+
"calc((level - 1) * step) in the dictionary"
|
|
77
|
+
}
|
|
78
|
+
part "tree-item-toggle", "The chevron (parents only): tabindex -1, never steals " \
|
|
79
|
+
"focus, aria-label flips Expand/Collapse",
|
|
80
|
+
states: {
|
|
81
|
+
"data-expand-label" => "always - the localized Expand string the controller " \
|
|
82
|
+
"swaps in on collapse",
|
|
83
|
+
"data-collapse-label" => "always - the localized Collapse string the " \
|
|
84
|
+
"controller swaps in on expand"
|
|
85
|
+
}
|
|
86
|
+
part "tree-item-label", "The row's text - a link when href: is given"
|
|
87
|
+
|
|
88
|
+
# @api private
|
|
89
|
+
def before_render
|
|
90
|
+
raise ArgumentError, "Tree requires label: (the treegrid's accessible name)" if label.blank?
|
|
91
|
+
|
|
92
|
+
# Consume the content block: it runs for its with_item side
|
|
93
|
+
# effects (the builder API), never for output.
|
|
94
|
+
content
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Declares one row. Nest children by calling with_item again on the
|
|
98
|
+
# yielded builder. Keywords: text: (the row's label, required), value:
|
|
99
|
+
# (the toggle event's identity, defaults to text:), expanded: (render
|
|
100
|
+
# the subtree open), disabled:, href: (the label renders as a link).
|
|
101
|
+
#
|
|
102
|
+
# @example
|
|
103
|
+
# tree.with_item(text: "docs", value: "docs", expanded: true) do |docs|
|
|
104
|
+
# docs.with_item(text: "intro.md", href: "/docs/intro")
|
|
105
|
+
# end
|
|
106
|
+
def with_item(**, &block)
|
|
107
|
+
root_items << Item.new(**).tap { |item| block&.call(item) }
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# @api private
|
|
112
|
+
def root_items
|
|
113
|
+
@root_items ||= []
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @api private
|
|
117
|
+
def rows
|
|
118
|
+
@rows ||= flatten(root_items, level: 1, hidden: false)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @api private
|
|
122
|
+
def root_attributes
|
|
123
|
+
html_attributes.merge_if_not_set(
|
|
124
|
+
{
|
|
125
|
+
"data-slot" => "tree", "role" => "treegrid",
|
|
126
|
+
"aria-label" => label, "class" => css
|
|
127
|
+
}.merge(component_data_attributes).merge(stimulus_attributes_for(:root))
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# @api private
|
|
132
|
+
def row_attributes(row, index)
|
|
133
|
+
attrs = {
|
|
134
|
+
"id" => row_id(index), "role" => "row", "data-slot" => "tree-item",
|
|
135
|
+
"data-value" => row.value, "data-level" => row.level,
|
|
136
|
+
"aria-level" => row.level, "aria-posinset" => row.posinset,
|
|
137
|
+
"aria-setsize" => row.setsize,
|
|
138
|
+
"tabindex" => index == first_visible_index ? "0" : "-1",
|
|
139
|
+
"style" => "--poetry-tree-level: #{row.level}",
|
|
140
|
+
"class" => css(:item)
|
|
141
|
+
}
|
|
142
|
+
attrs["aria-expanded"] = row.expanded.to_s if row.expandable
|
|
143
|
+
attrs["data-expanded"] = "" if row.expandable && row.expanded
|
|
144
|
+
if row.disabled
|
|
145
|
+
attrs["data-disabled"] = ""
|
|
146
|
+
attrs["aria-disabled"] = "true"
|
|
147
|
+
end
|
|
148
|
+
attrs["hidden"] = "" if row.hidden
|
|
149
|
+
attrs
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# @api private
|
|
153
|
+
def toggle_attributes(row, index)
|
|
154
|
+
{
|
|
155
|
+
"type" => "button", "tabindex" => "-1",
|
|
156
|
+
"data-slot" => "tree-item-toggle", "class" => css(:toggle),
|
|
157
|
+
"aria-label" => row.expanded ? t("poetry.tree.collapse") : t("poetry.tree.expand"),
|
|
158
|
+
"aria-labelledby" => "#{row_id(index)}-toggle #{row_id(index)}",
|
|
159
|
+
"id" => "#{row_id(index)}-toggle",
|
|
160
|
+
"data-expand-label" => t("poetry.tree.expand"),
|
|
161
|
+
"data-collapse-label" => t("poetry.tree.collapse")
|
|
162
|
+
}.merge(stimulus_attributes_for(:toggle))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @api private
|
|
166
|
+
def row_id(index)
|
|
167
|
+
"#{tree_id}-item-#{index}"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# @api private
|
|
171
|
+
def tree_id
|
|
172
|
+
@tree_id ||= poetry_instance_id("poetry-tree")
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @api private
|
|
176
|
+
def first_visible_index
|
|
177
|
+
@first_visible_index ||= rows.index { |row| !row.hidden } || 0
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# One flattened row (built by #flatten below).
|
|
181
|
+
# @api private
|
|
182
|
+
Row = Struct.new(
|
|
183
|
+
:text, :value, :href, :level, :posinset, :setsize,
|
|
184
|
+
:expanded, :expandable, :disabled, :hidden,
|
|
185
|
+
keyword_init: true
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# The nested builder yielded to item blocks - call with_item on it
|
|
189
|
+
# to declare children. Never constructed directly.
|
|
190
|
+
class Item
|
|
191
|
+
# @api private
|
|
192
|
+
attr_reader :options, :children
|
|
193
|
+
|
|
194
|
+
# @api private
|
|
195
|
+
def initialize(**options)
|
|
196
|
+
@options = options
|
|
197
|
+
@children = []
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Declares a child row; takes the same keywords as the
|
|
201
|
+
# component's with_item and yields its own builder for nesting.
|
|
202
|
+
def with_item(**)
|
|
203
|
+
child = Item.new(**)
|
|
204
|
+
@children << child
|
|
205
|
+
yield child if block_given?
|
|
206
|
+
child
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
private
|
|
211
|
+
|
|
212
|
+
def flatten(items, level:, hidden:)
|
|
213
|
+
items.flat_map.with_index do |item, index|
|
|
214
|
+
expandable = item.children.any?
|
|
215
|
+
expanded = expandable && item.options.fetch(:expanded, false)
|
|
216
|
+
row = Row.new(
|
|
217
|
+
text: item.options.fetch(:text), value: item.options[:value] || item.options.fetch(:text),
|
|
218
|
+
href: item.options[:href], level: level,
|
|
219
|
+
posinset: index + 1, setsize: items.size,
|
|
220
|
+
expanded: expanded, expandable: expandable,
|
|
221
|
+
disabled: item.options.fetch(:disabled, false), hidden: hidden
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
[row] + flatten(item.children, level: level + 1, hidden: hidden || !expanded)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
private :root_items, :rows, :root_attributes, :row_attributes, :toggle_attributes, :row_id, :tree_id
|
|
229
|
+
private :first_visible_index
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Tree
|
|
6
|
+
class Preview < Poetry::Core::Preview::Base
|
|
7
|
+
def default
|
|
8
|
+
render_component(label: "Files") do |tree|
|
|
9
|
+
tree.with_item(text: "docs", value: "docs", expanded: true) do |docs|
|
|
10
|
+
docs.with_item(text: "guides", value: "guides") do |guides|
|
|
11
|
+
guides.with_item(text: "intro.md", value: "intro")
|
|
12
|
+
guides.with_item(text: "advanced.md", value: "advanced")
|
|
13
|
+
end
|
|
14
|
+
docs.with_item(text: "README.md", value: "docs-readme")
|
|
15
|
+
end
|
|
16
|
+
tree.with_item(text: "src", value: "src") do |src|
|
|
17
|
+
src.with_item(text: "main.rb", value: "main")
|
|
18
|
+
end
|
|
19
|
+
tree.with_item(text: "LICENSE", value: "license")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Server-persisted expansion: collapsed parents render their
|
|
24
|
+
# subtree hidden; nested collapsed state survives cycles.
|
|
25
|
+
def deeply_nested
|
|
26
|
+
render_component(label: "Organization") do |tree|
|
|
27
|
+
tree.with_item(text: "Engineering", value: "eng", expanded: true) do |eng|
|
|
28
|
+
eng.with_item(text: "Platform", value: "platform", expanded: true) do |platform|
|
|
29
|
+
platform.with_item(text: "Infra", value: "infra") do |infra|
|
|
30
|
+
infra.with_item(text: "On-call", value: "oncall")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
eng.with_item(text: "Product", value: "product", disabled: true)
|
|
34
|
+
end
|
|
35
|
+
tree.with_item(text: "Design", value: "design")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# href: items render their labels as links (a file navigator).
|
|
40
|
+
def with_links
|
|
41
|
+
render_component(label: "Pages") do |tree|
|
|
42
|
+
tree.with_item(text: "Getting started", value: "start", expanded: true) do |start|
|
|
43
|
+
start.with_item(text: "Install", value: "install", href: "#install")
|
|
44
|
+
start.with_item(text: "Theming", value: "theming", href: "#theming")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def empty
|
|
50
|
+
render_component(label: "Files")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Tree
|
|
6
|
+
# Utility-only (the Separator/Spinner rule): rows indent off the
|
|
7
|
+
# server-stamped --poetry-tree-level custom property, the chevron
|
|
8
|
+
# rotates on the row's data-expanded (group-scoped), and focus rides
|
|
9
|
+
# a ring on the row itself. data-slot selectors are the restyle seam.
|
|
10
|
+
class Style < Poetry::Core::Style
|
|
11
|
+
base "flex w-full flex-col gap-px outline-none"
|
|
12
|
+
|
|
13
|
+
element :item, "group/tree-item flex cursor-default items-center gap-1.5 rounded-md " \
|
|
14
|
+
"py-1.5 pr-2 text-sm outline-none " \
|
|
15
|
+
"pl-[calc(0.5rem+(var(--poetry-tree-level)-1)*1.25rem)] " \
|
|
16
|
+
"hover:bg-accent/50 " \
|
|
17
|
+
"focus-visible:ring-[3px] focus-visible:ring-ring/50 " \
|
|
18
|
+
"data-disabled:pointer-events-none data-disabled:opacity-50"
|
|
19
|
+
element :cell, "contents"
|
|
20
|
+
element :toggle, "inline-flex size-4 shrink-0 items-center justify-center rounded-sm " \
|
|
21
|
+
"text-muted-foreground outline-none transition-transform " \
|
|
22
|
+
"group-data-[expanded]/tree-item:rotate-90 [&_svg]:size-3.5"
|
|
23
|
+
# Leaves keep the chevron's footprint so labels align across levels.
|
|
24
|
+
element :toggle_spacer, "inline-flex size-4 shrink-0"
|
|
25
|
+
element :label, "truncate text-foreground no-underline"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|