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,252 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Exclusive or multi-select toggle sets.
|
|
6
|
+
module ToggleGroup
|
|
7
|
+
# A set of Toggle-styled buttons under one value: type: :single
|
|
8
|
+
# keeps at most one pressed (re-pressing deselects to empty),
|
|
9
|
+
# :multiple toggles each item independently. The group is one Tab
|
|
10
|
+
# stop - arrow keys move focus between items WITHOUT selecting, so
|
|
11
|
+
# browsing options never fires effects; Space/Enter press the
|
|
12
|
+
# focused item. Single groups render role=radiogroup with
|
|
13
|
+
# aria-checked items; multiple groups render role=toolbar with
|
|
14
|
+
# aria-pressed items.
|
|
15
|
+
#
|
|
16
|
+
# A ToggleGroup is UI state, not form data: a single-select that
|
|
17
|
+
# must submit is a RadioGroup, a multi-select that must submit is a
|
|
18
|
+
# checkbox group. spacing: 0 renders the classic segmented control.
|
|
19
|
+
#
|
|
20
|
+
# @example A text-alignment switcher
|
|
21
|
+
# render Poetry::Ui::ToggleGroup::Component.new(value: "left", label: "Text alignment") do |group|
|
|
22
|
+
# group.with_item(value: "left", label: "Align left") { icon(:"align-left") }
|
|
23
|
+
# group.with_item(value: "center", label: "Align center") { icon(:"align-center") }
|
|
24
|
+
# end
|
|
25
|
+
class Component < Poetry::Core::Component
|
|
26
|
+
# The closed vocabulary for the type axis.
|
|
27
|
+
TYPES = %i[single multiple].freeze
|
|
28
|
+
# The closed vocabulary for the orientation axis.
|
|
29
|
+
ORIENTATIONS = %i[horizontal vertical].freeze
|
|
30
|
+
|
|
31
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
32
|
+
AGENT_RULES = [
|
|
33
|
+
"Use poetry_toggle_group - never hand-assemble Toggles with your own exclusivity logic.",
|
|
34
|
+
"ToggleGroup is UI state, NOT form data: submitting single-select -> RadioGroup; submitting " \
|
|
35
|
+
"multi-select -> Checkbox group. No name: exists; don't route around it.",
|
|
36
|
+
"Every item MUST have a unique value: (ArgumentError on duplicates); icon-only items MUST " \
|
|
37
|
+
"pass label: (state-invariant).",
|
|
38
|
+
"Name the group via label: - a nameless radiogroup/toolbar fails the audit.",
|
|
39
|
+
"Exclusive view/mode switching that shows PANELS is Tabs (aria-selected + tabpanels), not a " \
|
|
40
|
+
"single ToggleGroup.",
|
|
41
|
+
"Never mix vocabularies: single items carry aria-checked, multiple carry aria-pressed - the " \
|
|
42
|
+
"controller enforces it; agents patching DOM must too.",
|
|
43
|
+
"single deselects to empty by re-press - if your UI needs always-one-selected, " \
|
|
44
|
+
"handle the empty change in the host."
|
|
45
|
+
].freeze
|
|
46
|
+
|
|
47
|
+
# The same facts the before_render raise enforces, stated statically:
|
|
48
|
+
# poetry check flags the omission without rendering.
|
|
49
|
+
REQUIRED_SLOTS = { item: "at least one item" }.freeze
|
|
50
|
+
|
|
51
|
+
renders_many :items,
|
|
52
|
+
doc: "Declares one item: value: (unique - duplicates raise), label: (required when icon-only), " \
|
|
53
|
+
"disabled:; the block is the content. Pressed state comes from value:/values:.",
|
|
54
|
+
renders: lambda { |value:, label: nil, disabled: false, **options, &block|
|
|
55
|
+
item_value = register_item_value!(value)
|
|
56
|
+
content = capture(&block)
|
|
57
|
+
ensure_item_name!(content, label, item_value)
|
|
58
|
+
on = pressed_values.include?(item_value)
|
|
59
|
+
item_disabled = disabled || self.disabled
|
|
60
|
+
|
|
61
|
+
attrs = {
|
|
62
|
+
type: "button", class: item_classes(options.delete(:class)),
|
|
63
|
+
"data-slot" => "toggle-group-item", "data-poetry-collection-item" => "",
|
|
64
|
+
"data-value" => item_value,
|
|
65
|
+
"data-variant" => variant, "data-size" => size, "data-spacing" => spacing
|
|
66
|
+
}
|
|
67
|
+
# Pressed is a bare presence attribute: data-pressed when on,
|
|
68
|
+
# absent when off (never data-pressed=false).
|
|
69
|
+
attrs["data-pressed"] = "" if on
|
|
70
|
+
# The role/vocabulary split: single wears the radio vocabulary
|
|
71
|
+
# (aria-checked), never aria-pressed.
|
|
72
|
+
if single?
|
|
73
|
+
attrs["role"] = "radio"
|
|
74
|
+
attrs["aria-checked"] = on.to_s
|
|
75
|
+
else
|
|
76
|
+
attrs["aria-pressed"] = on.to_s
|
|
77
|
+
end
|
|
78
|
+
if item_disabled
|
|
79
|
+
attrs[:disabled] = true
|
|
80
|
+
attrs["data-disabled"] = "" # the roving-focus collection filter
|
|
81
|
+
end
|
|
82
|
+
attrs["aria-label"] = label if label.present?
|
|
83
|
+
attrs.merge!(stimulus_attributes_for(:item))
|
|
84
|
+
|
|
85
|
+
content_tag(:button, content, Poetry::Core::HTML::Attributes.merged(attrs, options))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
use_stimulus do
|
|
89
|
+
on :root do
|
|
90
|
+
controller :toggle_group do
|
|
91
|
+
register
|
|
92
|
+
value :type
|
|
93
|
+
end
|
|
94
|
+
controller :roving_focus do
|
|
95
|
+
register
|
|
96
|
+
# DEFAULT tabindex-managing mode (contrast Accordion's
|
|
97
|
+
# manage_tabindex: false).
|
|
98
|
+
value :orientation
|
|
99
|
+
value :loop, true
|
|
100
|
+
action :keydown, on: :keydown
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
on :item do
|
|
104
|
+
controller(:toggle_group) { action :toggle, on: :click }
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
style :variant, default: :default, required: true, variants: Toggle::Component::VARIANTS,
|
|
109
|
+
doc: "The shared Toggle variant axis, cascaded from the root to every item (root wins)."
|
|
110
|
+
style :size, default: :default, required: true, variants: Toggle::Component::SIZES,
|
|
111
|
+
doc: "The shared Toggle size axis, cascaded from the root to every item (root wins)."
|
|
112
|
+
|
|
113
|
+
option :type, :symbol, default: :single,
|
|
114
|
+
doc: ":single keeps at most one item pressed; :multiple toggles items independently."
|
|
115
|
+
option :value, :string, doc: "single: the pressed item's value. ArgumentError with :multiple."
|
|
116
|
+
option :values, :list, default: -> { [] },
|
|
117
|
+
doc: "multiple: the pressed items' values. ArgumentError with :single."
|
|
118
|
+
option :spacing, :integer, default: 2,
|
|
119
|
+
doc: "0 = the classic segmented control (joined corners, collapsed outline " \
|
|
120
|
+
"borders); >0 = free-standing items separated by that gap step."
|
|
121
|
+
option :orientation, :symbol, default: :horizontal,
|
|
122
|
+
doc: "The roving axis; :vertical stacks the items and flips the arrow keys."
|
|
123
|
+
option :disabled, :boolean, default: false, doc: "Disables every item in the group."
|
|
124
|
+
option :label, :string,
|
|
125
|
+
doc: "The group's accessible name (aria-label) - a nameless radiogroup/toolbar logs a lint warning."
|
|
126
|
+
|
|
127
|
+
validates :orientation, inclusion: { in: ORIENTATIONS }
|
|
128
|
+
|
|
129
|
+
part "toggle-group", "The role=radiogroup (single) / role=toolbar (multiple) root - the " \
|
|
130
|
+
"value-set machine and roving focus ride here; the axes cascade to items",
|
|
131
|
+
states: {
|
|
132
|
+
"data-variant" => { condition: "the shared Toggle variant (root wins)",
|
|
133
|
+
values: Toggle::Component::VARIANTS.map(&:to_s) },
|
|
134
|
+
"data-size" => { condition: "the shared Toggle size (root wins)",
|
|
135
|
+
values: Toggle::Component::SIZES.map(&:to_s) },
|
|
136
|
+
"data-spacing" => "the gap step - 0 is the segmented chain (joined corners), >0 free-standing",
|
|
137
|
+
"data-orientation" => { condition: "the roving axis", values: ORIENTATIONS.map(&:to_s) },
|
|
138
|
+
"data-disabled" => "the whole group is disabled (disables every item)"
|
|
139
|
+
},
|
|
140
|
+
vars: {
|
|
141
|
+
"--gap" => "the item gap, set inline from spacing: - the root's gap utility consumes it"
|
|
142
|
+
}
|
|
143
|
+
part "toggle-group-item", "One dumb <button> under the group machine - Toggle-styled, no " \
|
|
144
|
+
"per-item controller",
|
|
145
|
+
states: {
|
|
146
|
+
"data-pressed" => "pressed (bare presence boolean - absent when off; the controller " \
|
|
147
|
+
"rederives the type-correct aria attribute from it)",
|
|
148
|
+
"data-disabled" => "the item (or the whole group) is disabled - the roving-focus " \
|
|
149
|
+
"collection filter",
|
|
150
|
+
"data-value" => "the item's key in the value set (always present, unique)",
|
|
151
|
+
"data-variant" => { condition: "cascaded from the root",
|
|
152
|
+
values: Toggle::Component::VARIANTS.map(&:to_s) },
|
|
153
|
+
"data-size" => { condition: "cascaded from the root",
|
|
154
|
+
values: Toggle::Component::SIZES.map(&:to_s) },
|
|
155
|
+
"data-spacing" => "cascaded from the root - keys the segmented corner/border chain"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# The wrong value pair for the type is unrepresentable, not ignored.
|
|
159
|
+
# @api private
|
|
160
|
+
def initialize(attributes = {})
|
|
161
|
+
type = (attributes[:type] || attributes["type"] || :single).to_sym
|
|
162
|
+
raise ArgumentError, "ToggleGroup type must be :single or :multiple" unless TYPES.include?(type)
|
|
163
|
+
|
|
164
|
+
if type == :single && attributes.values_at(:values, "values").any?
|
|
165
|
+
raise ArgumentError, "values: is the :multiple API - single takes value: (one pressed item)"
|
|
166
|
+
end
|
|
167
|
+
if type == :multiple && attributes.values_at(:value, "value").any?
|
|
168
|
+
raise ArgumentError, "value: is the :single API - multiple takes values: (an array)"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
super
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# @api private
|
|
175
|
+
def before_render
|
|
176
|
+
raise ArgumentError, "ToggleGroup requires at least one with_item" unless items?
|
|
177
|
+
|
|
178
|
+
return if named?
|
|
179
|
+
|
|
180
|
+
# Lint-level warning, not an error: a radiogroup/toolbar SHOULD
|
|
181
|
+
# have an accessible name.
|
|
182
|
+
Rails.logger&.warn(
|
|
183
|
+
"poetry ToggleGroup: nameless #{single? ? "radiogroup" : "toolbar"} - give it label: (or aria-labelledby)"
|
|
184
|
+
)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# @api private
|
|
188
|
+
def single?
|
|
189
|
+
type != :multiple
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# @api private
|
|
193
|
+
def pressed_values
|
|
194
|
+
@pressed_values ||= (single? ? Array(value) : Array(values)).compact.map(&:to_s)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# @api private
|
|
198
|
+
def root_attributes
|
|
199
|
+
attrs = {
|
|
200
|
+
"role" => single? ? "radiogroup" : "toolbar",
|
|
201
|
+
"data-slot" => "toggle-group",
|
|
202
|
+
"data-variant" => variant, "data-size" => size, "data-spacing" => spacing,
|
|
203
|
+
"data-orientation" => orientation, "style" => "--gap: #{spacing}"
|
|
204
|
+
}
|
|
205
|
+
attrs["aria-label"] = label if label.present?
|
|
206
|
+
attrs["data-disabled"] = "" if disabled
|
|
207
|
+
html_attributes.merge_if_not_set(
|
|
208
|
+
attrs.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
209
|
+
)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
private
|
|
213
|
+
|
|
214
|
+
def register_item_value!(value)
|
|
215
|
+
@item_values ||= Set.new
|
|
216
|
+
item_value = value.to_s
|
|
217
|
+
unless @item_values.add?(item_value)
|
|
218
|
+
raise ArgumentError, "duplicate ToggleGroup item value #{item_value.inspect} - values key the set machine"
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
item_value
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def ensure_item_name!(content, label, item_value)
|
|
225
|
+
return if label.present? || content.to_s.gsub(/<[^>]+>/, " ").strip.present?
|
|
226
|
+
|
|
227
|
+
raise ArgumentError,
|
|
228
|
+
"icon-only ToggleGroup item #{item_value.inspect} requires label: (the accessible name, " \
|
|
229
|
+
"state-invariant)"
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def named?
|
|
233
|
+
aria = html_attributes["aria"] || {}
|
|
234
|
+
label.present? ||
|
|
235
|
+
html_attributes["aria-label"].present? || html_attributes["aria-labelledby"].present? ||
|
|
236
|
+
aria["label"].present? || aria["labelledby"].present?
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Shared-not-copied: the item's variant/size classes come from
|
|
240
|
+
# Toggle's dictionary (the toggleVariants import graph); this
|
|
241
|
+
# component's dictionary contributes only the item overrides. The
|
|
242
|
+
# merger collapses conflicts exactly as the source's cn() does
|
|
243
|
+
# (px-3 wins, min-w-0 wins).
|
|
244
|
+
def item_classes(extra)
|
|
245
|
+
classnames(Toggle::Style.css(variant: variant, size: size), css(:item), extra)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
private :single?, :pressed_values, :root_attributes
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module ToggleGroup
|
|
6
|
+
# The ToggleGroup preview matrix: both types x both variants x both
|
|
7
|
+
# spacing modes with mixed item states - the toggle-group-demo corpus
|
|
8
|
+
# plus the segmented picker and the disabled-item edge.
|
|
9
|
+
class Preview < Poetry::Core::Preview::Base
|
|
10
|
+
# @!group Types
|
|
11
|
+
|
|
12
|
+
# The toggle-group-demo port: MULTIPLE + outline, icon items each
|
|
13
|
+
# with a state-invariant aria-label (toolbar semantics).
|
|
14
|
+
def default
|
|
15
|
+
render_component(type: :multiple, variant: :outline, values: %w[bold],
|
|
16
|
+
label: "Text formatting") do |group|
|
|
17
|
+
formatting_items(group)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# single = a radio group that can deselect to empty: role=radiogroup,
|
|
22
|
+
# items role=radio + aria-checked (aria-pressed stripped).
|
|
23
|
+
def single
|
|
24
|
+
render_component(type: :single, value: "center", label: "Text alignment") do |group|
|
|
25
|
+
alignment_items(group)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @!endgroup
|
|
30
|
+
|
|
31
|
+
# @!group Variants
|
|
32
|
+
|
|
33
|
+
# The classic segmented control: single + outline + spacing 0
|
|
34
|
+
# (joined corners, collapsed borders, focus ring painting over).
|
|
35
|
+
def segmented
|
|
36
|
+
render_component(type: :single, variant: :outline, value: "list", spacing: 0,
|
|
37
|
+
label: "View") do |group|
|
|
38
|
+
group.with_item(value: "list", label: "List view") { embed(Icon::Component.new(name: :list)) }
|
|
39
|
+
group.with_item(value: "grid", label: "Grid view") { embed(Icon::Component.new(name: :"layout-grid")) }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# spacing > 0: free-standing toggles with a gap (each keeps its own
|
|
44
|
+
# rounded corners + shadow).
|
|
45
|
+
def spaced
|
|
46
|
+
render_component(type: :multiple, variant: :outline, spacing: 2, values: %w[bold italic],
|
|
47
|
+
label: "Text formatting") do |group|
|
|
48
|
+
formatting_items(group)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# orientation: :vertical - the column layout (data-vertical flips
|
|
53
|
+
# the root; segment chains and radii are orientation-guarded).
|
|
54
|
+
def vertical
|
|
55
|
+
render_component(type: :multiple, orientation: :vertical, spacing: 1,
|
|
56
|
+
values: %w[bold italic], label: "Text formatting") do |group|
|
|
57
|
+
formatting_items(group)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# The vertical SEGMENTED control: the orientation-guarded border/
|
|
62
|
+
# radius chain (border-t collapse, first rounded-t / last rounded-b).
|
|
63
|
+
def vertical_segmented
|
|
64
|
+
render_component(type: :single, variant: :outline, orientation: :vertical, spacing: 0,
|
|
65
|
+
value: "list", label: "View") do |group|
|
|
66
|
+
group.with_item(value: "list", label: "List view") { embed(Icon::Component.new(name: :list)) }
|
|
67
|
+
group.with_item(value: "grid", label: "Grid view") { embed(Icon::Component.new(name: :"layout-grid")) }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @!endgroup
|
|
72
|
+
|
|
73
|
+
# @!group Sizes
|
|
74
|
+
|
|
75
|
+
def small
|
|
76
|
+
render_component(type: :multiple, size: :sm, variant: :outline, label: "Text formatting") do |group|
|
|
77
|
+
formatting_items(group)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def large
|
|
82
|
+
render_component(type: :multiple, size: :lg, label: "Text formatting") do |group|
|
|
83
|
+
formatting_items(group)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @!endgroup
|
|
88
|
+
|
|
89
|
+
# @!group States
|
|
90
|
+
|
|
91
|
+
# A disabled item mid-group: skipped by Tab AND filtered from the
|
|
92
|
+
# roving collection; the segment borders still join.
|
|
93
|
+
def disabled_item
|
|
94
|
+
render_component(type: :single, variant: :outline, value: "left",
|
|
95
|
+
label: "Text alignment") do |group|
|
|
96
|
+
group.with_item(value: "left", label: "Align left") { embed(Icon::Component.new(name: :"text-align-start")) }
|
|
97
|
+
group.with_item(value: "center", label: "Align center", disabled: true) do
|
|
98
|
+
embed(Icon::Component.new(name: :"text-align-center"))
|
|
99
|
+
end
|
|
100
|
+
group.with_item(value: "right", label: "Align right") { embed(Icon::Component.new(name: :"text-align-end")) }
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def disabled_group
|
|
105
|
+
render_component(type: :multiple, variant: :outline, disabled: true,
|
|
106
|
+
label: "Text formatting") do |group|
|
|
107
|
+
formatting_items(group)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# @!endgroup
|
|
112
|
+
|
|
113
|
+
# @!group Composition
|
|
114
|
+
|
|
115
|
+
# Icon + text items (the caller's content block, Toggle-style).
|
|
116
|
+
def with_text
|
|
117
|
+
render_component(type: :single, variant: :outline, value: "preview", label: "Mode") do |group|
|
|
118
|
+
group.with_item(value: "code") { embed(Icon::Component.new(name: :bold)).concat("Code") }
|
|
119
|
+
group.with_item(value: "preview") { "Preview" }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# @!endgroup
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def formatting_items(group)
|
|
128
|
+
group.with_item(value: "bold", label: "Toggle bold") { embed(Icon::Component.new(name: :bold)) }
|
|
129
|
+
group.with_item(value: "italic", label: "Toggle italic") { embed(Icon::Component.new(name: :italic)) }
|
|
130
|
+
group.with_item(value: "underline", label: "Toggle underline") do
|
|
131
|
+
embed(Icon::Component.new(name: :underline))
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def alignment_items(group)
|
|
136
|
+
group.with_item(value: "left", label: "Align left") { embed(Icon::Component.new(name: :"text-align-start")) }
|
|
137
|
+
group.with_item(value: "center", label: "Align center") { embed(Icon::Component.new(name: :"text-align-center")) }
|
|
138
|
+
group.with_item(value: "right", label: "Align right") { embed(Icon::Component.new(name: :"text-align-end")) }
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module ToggleGroup
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The gap mechanism
|
|
7
|
+
# (gap-[--spacing(var(--gap))]) and the whole data-[spacing=0]
|
|
8
|
+
# segmented-control chain stay inline - upstream's own split keeps
|
|
9
|
+
# the segmentation machinery in markup; the group radius + the
|
|
10
|
+
# flagged-dead shadow selector ride the theme. Item variant/size
|
|
11
|
+
# classes still come from Toggle::Style (shared, never copied).
|
|
12
|
+
class Style < Poetry::Core::Style
|
|
13
|
+
base "cn-toggle-group group/toggle-group flex w-fit flex-row items-center " \
|
|
14
|
+
"gap-[--spacing(var(--gap))] data-vertical:flex-col data-vertical:items-stretch"
|
|
15
|
+
|
|
16
|
+
# The item overrides over Toggle's classes: w-auto/min-w-0 relax the
|
|
17
|
+
# square-ish standalone shape, focus z-index lets the ring paint
|
|
18
|
+
# OVER adjacent joined segments, and the data-[spacing=0] chain is
|
|
19
|
+
# the segmented control (joined corners + collapsed outline borders).
|
|
20
|
+
# The WHOLE segment-radius cluster (rounded-none + first/last edge
|
|
21
|
+
# radii) is theme-side - split-side rule: an inline
|
|
22
|
+
# rounded-none would beat every theme's edge rounding by layer
|
|
23
|
+
# order (exactly that happened when only the edges moved).
|
|
24
|
+
element :item, "cn-toggle-group-item w-auto min-w-0 shrink-0 focus:z-10 focus-visible:z-10 " \
|
|
25
|
+
"data-[spacing=0]:shadow-none " \
|
|
26
|
+
"group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 " \
|
|
27
|
+
"group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 " \
|
|
28
|
+
"group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l " \
|
|
29
|
+
"group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Single-Tab-stop control strips.
|
|
6
|
+
module Toolbar
|
|
7
|
+
# One Tab stop of grouped controls over a data surface - bulk
|
|
8
|
+
# actions above a table, an editor's control strip. The root wears
|
|
9
|
+
# role=toolbar; the typed slots render real Buttons, Inputs, and
|
|
10
|
+
# Separators, and arrow keys move between them while Tab leaves the
|
|
11
|
+
# whole strip. An Input inside stays safe to edit: horizontal
|
|
12
|
+
# arrows stay with the text caret until it reaches a boundary.
|
|
13
|
+
#
|
|
14
|
+
# label: is required - screen readers announce it on entering the
|
|
15
|
+
# toolbar. Styling is utility-only; restyle via data-slot=toolbar.
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# render Poetry::Ui::Toolbar::Component.new(label: "Bulk actions") do |toolbar|
|
|
19
|
+
# toolbar.with_button(variant: :outline) { "Archive" }
|
|
20
|
+
# toolbar.with_separator
|
|
21
|
+
# toolbar.with_input(name: "q", placeholder: "Filter…")
|
|
22
|
+
# end
|
|
23
|
+
class Component < Poetry::Core::Component
|
|
24
|
+
# The roving-focus controller's identifier path.
|
|
25
|
+
ROVING = %i[poetry core roving_focus].freeze
|
|
26
|
+
|
|
27
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
28
|
+
AGENT_RULES = [
|
|
29
|
+
"A Toolbar is ONE Tab stop: arrows move between its controls - use it for grouped " \
|
|
30
|
+
"actions over a surface (table bulk actions, editor strips), never as page navigation.",
|
|
31
|
+
"Compose through the typed slots: with_button (a real poetry Button - tag: :a makes it " \
|
|
32
|
+
"a link), with_input (search/filter - the caret keeps its arrow keys), with_separator " \
|
|
33
|
+
"(orientation flips automatically).",
|
|
34
|
+
"label: is the toolbar's accessible name and is required - screen readers announce it " \
|
|
35
|
+
"on entry.",
|
|
36
|
+
"A ToggleGroup composed inside keeps its own arrow navigation (its items rove locally); " \
|
|
37
|
+
"place it between separators so the seam reads as a group."
|
|
38
|
+
].freeze
|
|
39
|
+
|
|
40
|
+
# The same fact the before_render raise enforces, stated
|
|
41
|
+
# statically: poetry check flags the omission without rendering.
|
|
42
|
+
REQUIRED_SLOTS = { button: "at least one control (with_button / with_input)" }.freeze
|
|
43
|
+
|
|
44
|
+
renders_many :items,
|
|
45
|
+
doc: "The control slots: with_button (a real Button - tag: :a makes it a link), with_input " \
|
|
46
|
+
"(search/filter), with_separator (its orientation flips automatically).",
|
|
47
|
+
types: {
|
|
48
|
+
button: {
|
|
49
|
+
renders: ->(**options) { Poetry::Ui::Button::Component.new(**item_options(options)) },
|
|
50
|
+
as: :button
|
|
51
|
+
},
|
|
52
|
+
input: {
|
|
53
|
+
renders: ->(**options) { Poetry::Ui::Input::Component.new(**item_options(options)) },
|
|
54
|
+
as: :input
|
|
55
|
+
},
|
|
56
|
+
separator: {
|
|
57
|
+
renders: lambda { |**options|
|
|
58
|
+
Poetry::Ui::Separator::Component.new(
|
|
59
|
+
orientation: orientation == :horizontal ? :vertical : :horizontal,
|
|
60
|
+
class: "self-stretch", **options
|
|
61
|
+
)
|
|
62
|
+
},
|
|
63
|
+
as: :separator
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
style :orientation, default: :horizontal, variants: %i[horizontal vertical],
|
|
68
|
+
doc: "The strip's axis; :vertical stacks the controls and flips the arrow keys."
|
|
69
|
+
|
|
70
|
+
option :label, :string, required: true, doc: "The toolbar's accessible name. Required."
|
|
71
|
+
option :loop, :boolean, default: true, doc: "Whether arrow navigation wraps at the ends."
|
|
72
|
+
|
|
73
|
+
part "toolbar", "The role=toolbar root - one Tab stop; arrow keys rove across the " \
|
|
74
|
+
"slotted controls (roving-focus, with the caret guard protecting inputs)",
|
|
75
|
+
states: {
|
|
76
|
+
"data-orientation" => { condition: "always - which arrows rove",
|
|
77
|
+
values: %w[horizontal vertical] }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# @api private
|
|
81
|
+
def before_render
|
|
82
|
+
raise ArgumentError, "Toolbar requires at least one control slot" unless items?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @api private
|
|
86
|
+
def call
|
|
87
|
+
content_tag(:div, safe_join(items.map(&:to_s)), **root_attributes.to_attributes)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @api private
|
|
91
|
+
def root_attributes
|
|
92
|
+
html_attributes.merge_if_not_set(
|
|
93
|
+
{
|
|
94
|
+
"role" => "toolbar", "aria-label" => label, "aria-orientation" => orientation,
|
|
95
|
+
"data-slot" => "toolbar", "data-orientation" => orientation
|
|
96
|
+
}.merge(component_data_attributes).merge(roving_attributes)
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
# Every slotted control is a roving collection item; a disabled one
|
|
103
|
+
# is filtered from the collection (the tabs idiom - roving reads
|
|
104
|
+
# data-disabled, the native attribute alone is invisible to it).
|
|
105
|
+
def item_options(options)
|
|
106
|
+
extra = { "data-poetry-collection-item" => "" }
|
|
107
|
+
extra["data-disabled"] = "" if options[:disabled]
|
|
108
|
+
options.merge(extra)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def roving_attributes
|
|
112
|
+
attrs = Poetry::Core::HTML::Attributes.new
|
|
113
|
+
roving = Poetry::Core::Stimulus::Builder.new(ROVING, attrs)
|
|
114
|
+
roving.register_controller
|
|
115
|
+
roving.with_value(:orientation, orientation)
|
|
116
|
+
roving.with_value(:loop, loop)
|
|
117
|
+
roving.with_action(:keydown, on: :keydown)
|
|
118
|
+
attrs.to_attributes
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private :root_attributes
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Toolbar
|
|
6
|
+
# The Toolbar preview: a formatting strip, the table bulk-action
|
|
7
|
+
# row with a filter input, and the vertical orientation.
|
|
8
|
+
class Preview < Poetry::Core::Preview::Base
|
|
9
|
+
def default
|
|
10
|
+
render_component(label: "Text formatting") do |toolbar|
|
|
11
|
+
toolbar.with_button(variant: :ghost, size: :sm) { "Bold" }
|
|
12
|
+
toolbar.with_button(variant: :ghost, size: :sm) { "Italic" }
|
|
13
|
+
toolbar.with_separator
|
|
14
|
+
toolbar.with_button(variant: :ghost, size: :sm) { "Link" }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The table bulk-action strip: actions, a seam, then the filter
|
|
19
|
+
# input - the roving caret guard keeps the input's arrow keys.
|
|
20
|
+
def bulk_actions_with_filter
|
|
21
|
+
render_component(label: "Invoice actions") do |toolbar|
|
|
22
|
+
toolbar.with_button(variant: :outline, size: :sm) { "Export" }
|
|
23
|
+
toolbar.with_button(variant: :outline, size: :sm, disabled: true) { "Archive" }
|
|
24
|
+
toolbar.with_separator
|
|
25
|
+
toolbar.with_input(type: "search", placeholder: "Filter invoices…",
|
|
26
|
+
"aria-label": "Filter invoices")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def vertical
|
|
31
|
+
render_component(label: "Canvas tools", orientation: :vertical) do |toolbar|
|
|
32
|
+
toolbar.with_button(variant: :ghost, size: :sm) { "Select" }
|
|
33
|
+
toolbar.with_button(variant: :ghost, size: :sm) { "Draw" }
|
|
34
|
+
toolbar.with_separator
|
|
35
|
+
toolbar.with_button(variant: :ghost, size: :sm) { "Erase" }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Toolbar
|
|
6
|
+
# Utility-only (the Separator/Spinner rule): there is no upstream
|
|
7
|
+
# look to be faithful to - the strip is a structural gap row;
|
|
8
|
+
# data-slot=toolbar is the restyle seam for any theme that wants
|
|
9
|
+
# chrome (border, background) on it.
|
|
10
|
+
class Style < Poetry::Core::Style
|
|
11
|
+
base "flex w-fit items-center gap-1"
|
|
12
|
+
|
|
13
|
+
variant :orientation, {
|
|
14
|
+
horizontal: "flex-row",
|
|
15
|
+
vertical: "flex-col items-stretch"
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<%= trigger %>
|
|
3
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(content_attributes).to_attributes) do %>
|
|
4
|
+
<% if label.present? %>
|
|
5
|
+
<%# label: substitutes the ANNOUNCED body - rich children stay visual
|
|
6
|
+
(one content node: visual wrapper hidden from AT, sr-only text
|
|
7
|
+
carries the announcement). %>
|
|
8
|
+
<span aria-hidden="true"><%= content %></span>
|
|
9
|
+
<span class="sr-only"><%= label %></span>
|
|
10
|
+
<% else %>
|
|
11
|
+
<%= content %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%# invisible until popper stamps data-side: an unpositioned arrow
|
|
14
|
+
(pinned/server-open, popper not yet run) is a stray nub in-flow. %>
|
|
15
|
+
<%# no whitespace inside the wrapper: a stray text node makes a line
|
|
16
|
+
box that stacks above the block diamond and inflates the measured
|
|
17
|
+
arrow height (28px for a 10px diamond - the bottom-side gap bug). %>
|
|
18
|
+
<span data-slot="tooltip-arrow" aria-hidden="true" class="invisible data-[side]:visible inline-block leading-none" <%= tag.attributes(**stimulus_attributes_for(:arrow)) %>><span class="<%= css(:arrow) %>"></span></span>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|