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,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Semantic data tables composed from part helpers.
|
|
6
|
+
module Table
|
|
7
|
+
# A semantic <table> wrapped in a horizontally scrolling container.
|
|
8
|
+
# Compose the sections with the part helpers (poetry_table_header /
|
|
9
|
+
# _body / _row / _head / _cell / _footer / _caption), which render
|
|
10
|
+
# real thead/tbody/tr/th/td elements carrying the family's styling.
|
|
11
|
+
# Static and JS-free by itself - DataTable adds sorting, filtering,
|
|
12
|
+
# and selection on top.
|
|
13
|
+
#
|
|
14
|
+
# sticky_header: true pins the <thead> while the container scrolls.
|
|
15
|
+
# It only takes effect once container_class: caps the height (e.g.
|
|
16
|
+
# "max-h-96"), and it requires scroll_label: - the container becomes
|
|
17
|
+
# a focusable scroll region, which needs an accessible name.
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# render Poetry::Ui::Table::Component.new do
|
|
21
|
+
# safe_join([
|
|
22
|
+
# poetry_table_header { poetry_table_row { poetry_table_head { "Invoice" } } },
|
|
23
|
+
# poetry_table_body { poetry_table_row { poetry_table_cell { "INV001" } } }
|
|
24
|
+
# ])
|
|
25
|
+
# end
|
|
26
|
+
class Component < Poetry::Core::Component
|
|
27
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
28
|
+
AGENT_RULES = [
|
|
29
|
+
"Compose the table with the part helpers (poetry_table_header/_body/_row/_head/_cell) - " \
|
|
30
|
+
"they carry the data-slot + classes onto real thead/tbody/tr/th/td.",
|
|
31
|
+
"A column header is poetry_table_head (a <th>); a data cell is poetry_table_cell (a <td>).",
|
|
32
|
+
"Mark a selected row with data-selected on poetry_table_row - never a bespoke highlight class.",
|
|
33
|
+
"sticky_header: true pins the thead while the container scrolls - it only scrolls once " \
|
|
34
|
+
"container_class: caps the height (\"max-h-96\"); without a cap nothing sticks.",
|
|
35
|
+
"sticky_header requires scroll_label: - the container becomes a focusable scroll region " \
|
|
36
|
+
"(tabindex=0 + role=region) and a keyboard-reachable region needs a name (the ScrollArea rule)."
|
|
37
|
+
].freeze
|
|
38
|
+
|
|
39
|
+
option :sticky_header, :boolean, default: false,
|
|
40
|
+
doc: "Pins the <thead> while the container scrolls; needs a height cap " \
|
|
41
|
+
"(container_class:) to take effect, and requires scroll_label:."
|
|
42
|
+
option :container_class, :string,
|
|
43
|
+
doc: "Extra classes for the scroll container - e.g. \"max-h-96\" to cap its height."
|
|
44
|
+
option :scroll_label, :string,
|
|
45
|
+
doc: "The scroll region's accessible name, required with sticky_header: a scrollable region a " \
|
|
46
|
+
"keyboard can't reach fails WCAG (axe scrollable-region-focusable), and a focusable region needs " \
|
|
47
|
+
"a name."
|
|
48
|
+
|
|
49
|
+
part "table", "The semantic <table> element itself - the root the part helpers compose into"
|
|
50
|
+
part "table-caption", "The <caption> (poetry_table_caption) - the table's accessible purpose"
|
|
51
|
+
part "table-header", "The <thead> (poetry_table_header) holding the column-header row"
|
|
52
|
+
part "table-body", "The <tbody> (poetry_table_body) holding the data rows"
|
|
53
|
+
part "table-footer", "The <tfoot> (poetry_table_footer) - totals/summary rows"
|
|
54
|
+
part "table-row", "A <tr> (poetry_table_row) in any section",
|
|
55
|
+
states: {
|
|
56
|
+
"data-selected" => "the row is marked selected (presence attribute, no value) - " \
|
|
57
|
+
"the theme tints it"
|
|
58
|
+
}
|
|
59
|
+
part "table-head", "A column header <th> (poetry_table_head)"
|
|
60
|
+
part "table-cell", "A data <td> (poetry_table_cell)"
|
|
61
|
+
|
|
62
|
+
# No content = an empty <table> in a scroll container.
|
|
63
|
+
requires_content "the table sections (poetry_table_* helpers)"
|
|
64
|
+
|
|
65
|
+
# @api private
|
|
66
|
+
def before_render
|
|
67
|
+
ensure_content!
|
|
68
|
+
return unless sticky_header && scroll_label.blank?
|
|
69
|
+
|
|
70
|
+
raise ArgumentError,
|
|
71
|
+
"Table sticky_header: requires scroll_label: (the scroll region's accessible name)"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @api private
|
|
75
|
+
def container_attributes
|
|
76
|
+
extra = [(css(:container_sticky) if sticky_header), container_class].compact.join(" ")
|
|
77
|
+
attrs = { "data-slot" => "table-container", "class" => css(:container, class: extra.presence) }
|
|
78
|
+
attrs.merge!("tabindex" => "0", "role" => "region", "aria-label" => scroll_label) if sticky_header
|
|
79
|
+
attrs
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @api private
|
|
83
|
+
def root_attributes
|
|
84
|
+
html_attributes.merge_if_not_set(
|
|
85
|
+
{ "data-slot" => "table" }.merge(component_data_attributes)
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private :container_attributes, :root_attributes
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Table
|
|
6
|
+
# The Table preview: the ported table-demo (recent invoices) with a
|
|
7
|
+
# caption, a footer total, and a selected row. Built with the same
|
|
8
|
+
# data-slot + Style parts the poetry_table_* helpers stamp (the
|
|
9
|
+
# helpers themselves are covered by the components-helper drift test).
|
|
10
|
+
class Preview < Poetry::Core::Preview::Base
|
|
11
|
+
ROWS = [
|
|
12
|
+
["INV001", "Paid", "$250.00", true],
|
|
13
|
+
["INV002", "Pending", "$150.00", false],
|
|
14
|
+
["INV003", "Unpaid", "$350.00", false],
|
|
15
|
+
["INV004", "Paid", "$500.00", false]
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
STATUSES = %w[Paid Pending Unpaid].freeze
|
|
19
|
+
|
|
20
|
+
def default
|
|
21
|
+
render_component do
|
|
22
|
+
safe_join([caption, header, body, footer])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# sticky_header pins the thead while the capped container scrolls
|
|
27
|
+
# - enough rows to overflow the max-h-56 cap.
|
|
28
|
+
def sticky
|
|
29
|
+
render_component(sticky_header: true, container_class: "max-h-56",
|
|
30
|
+
scroll_label: "Recent invoices") do
|
|
31
|
+
safe_join([header, long_body])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def caption
|
|
38
|
+
part(:caption, :caption, "table-caption") { "A list of your recent invoices." }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def header
|
|
42
|
+
part(:thead, :header, "table-header") do
|
|
43
|
+
row do
|
|
44
|
+
safe_join([head { "Invoice" }, head { "Status" }, head(class: "text-right") { "Amount" }])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def body
|
|
50
|
+
part(:tbody, :body, "table-body") do
|
|
51
|
+
safe_join(ROWS.map do |invoice, status, amount, selected|
|
|
52
|
+
row(data: selected ? { slot: "table-row", selected: "" } : { slot: "table-row" }) do
|
|
53
|
+
safe_join([
|
|
54
|
+
cell(class: "font-medium") { invoice },
|
|
55
|
+
cell { status },
|
|
56
|
+
cell(class: "text-right") { amount }
|
|
57
|
+
])
|
|
58
|
+
end
|
|
59
|
+
end)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def footer
|
|
64
|
+
part(:tfoot, :footer, "table-footer") do
|
|
65
|
+
row { safe_join([cell(colspan: 2) { "Total" }, cell(class: "text-right") { "$1,250.00" }]) }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def long_body
|
|
70
|
+
part(:tbody, :body, "table-body") do
|
|
71
|
+
safe_join((1..12).map do |i|
|
|
72
|
+
row do
|
|
73
|
+
safe_join([
|
|
74
|
+
cell(class: "font-medium") { format("INV%03d", i) },
|
|
75
|
+
cell { STATUSES[i % 3] },
|
|
76
|
+
cell(class: "text-right") { format("$%d50.00", i) }
|
|
77
|
+
])
|
|
78
|
+
end
|
|
79
|
+
end)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# tag.<el> with the Style class + data-slot - what the helper emits.
|
|
84
|
+
def part(tag_name, element, slot, **attrs, &)
|
|
85
|
+
classes = [Style.css(element), attrs.delete(:class)].compact.join(" ")
|
|
86
|
+
data = attrs.delete(:data) || { slot: slot }
|
|
87
|
+
content_tag(tag_name, capture(&), **attrs, class: classes, data: data)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def row(**attrs, &) = part(:tr, :row, "table-row", **attrs, &)
|
|
91
|
+
def head(**attrs, &) = part(:th, :head, "table-head", **attrs, &)
|
|
92
|
+
def cell(**attrs, &) = part(:td, :cell, "table-cell", **attrs, &)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Table
|
|
6
|
+
# Re-expressed through the cn-* theme layer. Zero JS - the row's
|
|
7
|
+
# selected state travels as data-selected, its tint in the theme
|
|
8
|
+
# with every other row tint. The scroll container carries its own
|
|
9
|
+
# themed hook (cn-table-container).
|
|
10
|
+
class Style < Poetry::Core::Style
|
|
11
|
+
base "cn-table"
|
|
12
|
+
|
|
13
|
+
element :container, "cn-table-container"
|
|
14
|
+
element :container_sticky,
|
|
15
|
+
"overflow-y-auto [&_thead]:sticky [&_thead]:top-0 [&_thead]:z-10 [&_thead]:bg-background"
|
|
16
|
+
element :header, "cn-table-header"
|
|
17
|
+
element :body, "cn-table-body"
|
|
18
|
+
element :footer, "cn-table-footer"
|
|
19
|
+
element :row, "cn-table-row transition-colors has-aria-expanded:bg-muted/50"
|
|
20
|
+
element :head, "cn-table-head"
|
|
21
|
+
element :cell, "cn-table-cell"
|
|
22
|
+
element :caption, "cn-table-caption"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<%= content_tag(:div, list_attributes) do %>
|
|
3
|
+
<% tab_defs.each do |tab| %>
|
|
4
|
+
<%= content_tag(:button, tab.title, trigger_attributes(tab)) %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% tab_defs.reject(&:panel_less).each do |tab| %>
|
|
8
|
+
<%= content_tag(:div, panel_body(tab), panel_attributes(tab)) %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Tabbed views switched by a tablist.
|
|
6
|
+
module Tabs
|
|
7
|
+
# A tablist of triggers that switches between panels. Declare each
|
|
8
|
+
# tab with with_tab (title plus a panel block) and the component
|
|
9
|
+
# wires the tab/tablist/tabpanel roles, their ids, and the keyboard:
|
|
10
|
+
# arrow keys move focus along the tablist and activate the focused
|
|
11
|
+
# tab. The active panel is server-rendered visible, so the initial
|
|
12
|
+
# view needs no JS.
|
|
13
|
+
#
|
|
14
|
+
# default: picks the active tab by value (otherwise the first
|
|
15
|
+
# enabled tab wins); label: names the tablist for assistive tech -
|
|
16
|
+
# recommended when a page has several tab sets.
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# <%= poetry_tabs(default: "account", label: "Account settings") do |tabs| %>
|
|
20
|
+
# <% tabs.with_tab("Account", value: "account") do %>...panel...<% end %>
|
|
21
|
+
# <% tabs.with_tab("Password", value: "password") do %>...panel...<% end %>
|
|
22
|
+
# <% end %>
|
|
23
|
+
class Component < Poetry::Core::Component
|
|
24
|
+
# The closed vocabulary for the orientation axis.
|
|
25
|
+
ORIENTATIONS = %i[horizontal vertical].freeze
|
|
26
|
+
# The closed vocabulary for the list-variant axis.
|
|
27
|
+
VARIANTS = %i[default line].freeze
|
|
28
|
+
|
|
29
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
30
|
+
AGENT_RULES = [
|
|
31
|
+
"Declare tabs with with_tab(title, value:) + the panel block (or defer: for a " \
|
|
32
|
+
"lazy turbo-frame panel) - never hand-wire role=tab/tabpanel ids.",
|
|
33
|
+
"panel: false declares a list-only tab (no tabpanel renders, the trigger drops " \
|
|
34
|
+
"aria-controls) - for demos/pattern shells; real tab sets carry panels.",
|
|
35
|
+
"default: picks the server-rendered active tab (the first enabled tab otherwise) - the " \
|
|
36
|
+
"panel is visible without JS.",
|
|
37
|
+
"label: names the tablist (aria-label) - recommended whenever the page has several tab sets.",
|
|
38
|
+
"Tabs switch VIEWS of one context; use navigation (links) when the URL should change."
|
|
39
|
+
].freeze
|
|
40
|
+
|
|
41
|
+
# The same facts the before_render raise enforces, stated
|
|
42
|
+
# statically: poetry check flags the omission without rendering.
|
|
43
|
+
REQUIRED_SLOTS = { tab: "at least one tab" }.freeze
|
|
44
|
+
|
|
45
|
+
renders_many :tabs,
|
|
46
|
+
doc: "Declares one tab: the title, its value:, and the panel as the block (defer: swaps in a " \
|
|
47
|
+
"lazy turbo-frame panel; panel: false declares a list-only tab). Omitting all three " \
|
|
48
|
+
"raises.",
|
|
49
|
+
renders: lambda { |title, value:, disabled: false, defer: nil, panel: true, &block|
|
|
50
|
+
unless block || defer || panel == false
|
|
51
|
+
raise ArgumentError,
|
|
52
|
+
"Tabs tab #{title.inspect} requires a panel block, defer:, or panel: false"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
tab_defs << Tab.new(title: title, value: value.to_s, disabled: disabled, panel: block,
|
|
56
|
+
defer: defer, panel_less: panel == false)
|
|
57
|
+
nil
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
use_stimulus do
|
|
61
|
+
on :root do
|
|
62
|
+
controller(:tabs) { register }
|
|
63
|
+
end
|
|
64
|
+
# Both controllers declare on one element: roving-focus registers
|
|
65
|
+
# and owns the keyboard; the tabs controller is NOT registered on
|
|
66
|
+
# the list - its focus_activate action routes up to the root
|
|
67
|
+
# instance.
|
|
68
|
+
on :list do
|
|
69
|
+
controller :roving_focus do
|
|
70
|
+
register
|
|
71
|
+
value :orientation
|
|
72
|
+
value :loop, true
|
|
73
|
+
action :keydown, on: :keydown
|
|
74
|
+
end
|
|
75
|
+
controller :tabs do
|
|
76
|
+
action :focus_activate, on: event(:roving_focus, :entry)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
on :trigger do
|
|
80
|
+
controller(:tabs) { action :activate, on: :click }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The operate surface: activate a tab by its value (registered per
|
|
85
|
+
# instance, opt-in - see poetry-agent).
|
|
86
|
+
tool :set_value,
|
|
87
|
+
description: "Activate the tab whose value matches and show its panel.",
|
|
88
|
+
params: { value: { type: "string", required: true, description: "The tab's value." } },
|
|
89
|
+
executes: %i[tabs set_value],
|
|
90
|
+
mutating: true
|
|
91
|
+
|
|
92
|
+
# The rendered instance knows its tab values: the payload's schema
|
|
93
|
+
# carries them as the enum, so an agent can only ask for a tab that
|
|
94
|
+
# exists (the class-level projection stays a plain string).
|
|
95
|
+
def webmcp_tool_definition(definition)
|
|
96
|
+
return definition unless definition["name"] == "set_value"
|
|
97
|
+
|
|
98
|
+
values = tab_defs.map(&:value)
|
|
99
|
+
return definition if values.empty?
|
|
100
|
+
|
|
101
|
+
schema = definition.fetch("inputSchema")
|
|
102
|
+
value = schema.fetch("properties").fetch("value").merge("enum" => values)
|
|
103
|
+
definition.merge("inputSchema" => schema.merge("properties" => schema["properties"].merge("value" => value)))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
option :default, :string,
|
|
107
|
+
doc: "The value of the server-rendered active tab; defaults to the first enabled tab. Raises when it " \
|
|
108
|
+
"matches no tab."
|
|
109
|
+
option :label, :string, doc: "The tablist's accessible name - recommended when a page has several tab sets."
|
|
110
|
+
option :orientation, :symbol, default: :horizontal,
|
|
111
|
+
doc: "The tab axis; :vertical stacks the triggers and flips the arrow keys."
|
|
112
|
+
option :variant, :symbol, default: :default,
|
|
113
|
+
doc: "The list's visual treatment: :default a filled capsule, :line an underline " \
|
|
114
|
+
"indicator."
|
|
115
|
+
|
|
116
|
+
validates :orientation, inclusion: { in: ORIENTATIONS }
|
|
117
|
+
validates :variant, inclusion: { in: VARIANTS }
|
|
118
|
+
|
|
119
|
+
part "tabs", "Root wrapper - the orientation rides here and flips the flex direction",
|
|
120
|
+
states: {
|
|
121
|
+
"data-orientation" => { condition: "the tab axis (matches aria-orientation on the list)",
|
|
122
|
+
values: %w[horizontal vertical] }
|
|
123
|
+
}
|
|
124
|
+
part "tabs-list", "The role=tablist row of triggers - the roving-focus keyboard group and " \
|
|
125
|
+
"the visual variant ride here",
|
|
126
|
+
states: {
|
|
127
|
+
"data-variant" => "the list treatment - default (filled capsule) or line (underline indicator)"
|
|
128
|
+
}
|
|
129
|
+
part "tabs-trigger", "One role=tab button per tab",
|
|
130
|
+
states: {
|
|
131
|
+
"data-active" => "the selected tab (the controller moves it with aria-selected on activation)",
|
|
132
|
+
"data-disabled" => "tab is disabled - also filters it from the roving-focus collection",
|
|
133
|
+
"data-value" => "the tab's value - the key the controller matches panels against"
|
|
134
|
+
}
|
|
135
|
+
part "tabs-content", "One role=tabpanel per tab - only the active panel is visible",
|
|
136
|
+
states: {
|
|
137
|
+
"data-hidden" => "panel is inactive (paired with the hidden property - the controller " \
|
|
138
|
+
"flips both)",
|
|
139
|
+
"data-value" => "the owning tab's value"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# @api private
|
|
143
|
+
def before_render
|
|
144
|
+
raise ArgumentError, "Tabs requires at least one with_tab" unless tabs?
|
|
145
|
+
|
|
146
|
+
return unless default.present? && tab_defs.none? { |tab| tab.value == default }
|
|
147
|
+
|
|
148
|
+
raise ArgumentError, "Tabs default: #{default.inspect} matches no tab value " \
|
|
149
|
+
"(#{tab_defs.map(&:value).inspect})"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# @api private
|
|
153
|
+
def tab_defs
|
|
154
|
+
@tab_defs ||= []
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# The server-rendered active tab: default: when given, else the
|
|
158
|
+
# first enabled tab.
|
|
159
|
+
# @api private
|
|
160
|
+
def active_value
|
|
161
|
+
@active_value ||= default.presence || tab_defs.reject(&:disabled).first&.value || tab_defs.first.value
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @api private
|
|
165
|
+
def active?(tab)
|
|
166
|
+
tab.value == active_value
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @api private
|
|
170
|
+
def trigger_id(tab) = "#{instance_id}-trigger-#{tab.value}"
|
|
171
|
+
# @api private
|
|
172
|
+
def panel_id(tab) = "#{instance_id}-panel-#{tab.value}"
|
|
173
|
+
|
|
174
|
+
# defer: swaps the panel body for a lazy turbo-frame - a
|
|
175
|
+
# hidden panel is not visible, so Turbo fetches on first
|
|
176
|
+
# activation with zero tabs-controller involvement. The panel
|
|
177
|
+
# block (if given) becomes the frame's placeholder.
|
|
178
|
+
# @api private
|
|
179
|
+
def panel_body(tab)
|
|
180
|
+
return capture(&tab.panel) unless tab.defer
|
|
181
|
+
|
|
182
|
+
render(Poetry::Ui::Deferred::Component.new(src: tab.defer)) { tab.panel ? capture(&tab.panel) : nil }
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# @api private
|
|
186
|
+
def root_attributes
|
|
187
|
+
html_attributes.merge_if_not_set(
|
|
188
|
+
{
|
|
189
|
+
"data-slot" => "tabs", "data-orientation" => orientation
|
|
190
|
+
}.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
191
|
+
)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @api private
|
|
195
|
+
def list_attributes
|
|
196
|
+
attrs = {
|
|
197
|
+
"role" => "tablist", "data-slot" => "tabs-list", "data-variant" => variant,
|
|
198
|
+
"aria-orientation" => orientation,
|
|
199
|
+
"class" => "#{css(:list)} #{css(:"list_#{variant}")}".strip
|
|
200
|
+
}
|
|
201
|
+
attrs["aria-label"] = label if label.present?
|
|
202
|
+
attrs.merge(stimulus_attributes_for(:list))
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# @api private
|
|
206
|
+
def trigger_attributes(tab)
|
|
207
|
+
attrs = {
|
|
208
|
+
"type" => "button", "role" => "tab", "id" => trigger_id(tab),
|
|
209
|
+
"data-slot" => "tabs-trigger", "data-value" => tab.value,
|
|
210
|
+
"data-poetry-collection-item" => "",
|
|
211
|
+
"aria-selected" => active?(tab).to_s,
|
|
212
|
+
"tabindex" => active?(tab) ? "0" : "-1",
|
|
213
|
+
"class" => css(:trigger)
|
|
214
|
+
}.merge(stimulus_attributes_for(:trigger))
|
|
215
|
+
attrs["aria-controls"] = panel_id(tab) unless tab.panel_less
|
|
216
|
+
attrs["data-active"] = "" if active?(tab)
|
|
217
|
+
if tab.disabled
|
|
218
|
+
attrs["disabled"] = true
|
|
219
|
+
attrs["data-disabled"] = "" # the roving-focus collection filter
|
|
220
|
+
end
|
|
221
|
+
attrs
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @api private
|
|
225
|
+
def panel_attributes(tab)
|
|
226
|
+
attrs = {
|
|
227
|
+
"role" => "tabpanel", "id" => panel_id(tab), "data-slot" => "tabs-content",
|
|
228
|
+
"data-value" => tab.value, "aria-labelledby" => trigger_id(tab),
|
|
229
|
+
"tabindex" => "0", "class" => css(:content)
|
|
230
|
+
}
|
|
231
|
+
unless active?(tab)
|
|
232
|
+
attrs["hidden"] = true
|
|
233
|
+
attrs["data-hidden"] = ""
|
|
234
|
+
end
|
|
235
|
+
attrs
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# One declared tab (built by with_tab).
|
|
239
|
+
# @api private
|
|
240
|
+
Tab = Data.define(:title, :value, :disabled, :panel, :defer, :panel_less)
|
|
241
|
+
|
|
242
|
+
private
|
|
243
|
+
|
|
244
|
+
def instance_id
|
|
245
|
+
@instance_id ||= poetry_instance_id("poetry-tabs")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
private :tab_defs, :active_value, :active?, :trigger_id, :panel_id, :panel_body, :root_attributes
|
|
249
|
+
private :list_attributes, :trigger_attributes, :panel_attributes
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Tabs
|
|
6
|
+
# The Tabs preview: the default boxed list, the line variant, and a
|
|
7
|
+
# vertical set with a disabled tab.
|
|
8
|
+
class Preview < Poetry::Core::Preview::Base
|
|
9
|
+
def default
|
|
10
|
+
render_component(label: "Account settings") do |tabs|
|
|
11
|
+
tabs.with_tab("Account", value: "account") { "Make changes to your account here." }
|
|
12
|
+
tabs.with_tab("Password", value: "password") { "Change your password here." }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def line_variant
|
|
17
|
+
render_component(variant: :line, label: "Docs sections", default: "usage") do |tabs|
|
|
18
|
+
tabs.with_tab("Overview", value: "overview") { "The component at a glance." }
|
|
19
|
+
tabs.with_tab("Usage", value: "usage") { "How to compose it." }
|
|
20
|
+
tabs.with_tab("API", value: "api") { "Options and slots." }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The list-only arrangement (panel: false): no tabpanels at all,
|
|
25
|
+
# triggers without aria-controls - upstream's line/disabled demos.
|
|
26
|
+
def list_only
|
|
27
|
+
render_component(label: "List-only demo") do |tabs|
|
|
28
|
+
tabs.with_tab("Home", value: "home", panel: false)
|
|
29
|
+
tabs.with_tab("Disabled", value: "settings", disabled: true, panel: false)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def vertical_with_disabled
|
|
34
|
+
render_component(orientation: :vertical, label: "Project areas") do |tabs|
|
|
35
|
+
tabs.with_tab("General", value: "general") { "Project defaults." }
|
|
36
|
+
tabs.with_tab("Members", value: "members") { "Who has access." }
|
|
37
|
+
tabs.with_tab("Billing", value: "billing", disabled: true) { "Plan and invoices." }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Tabs
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The group/tabs and
|
|
7
|
+
# group/tabs-list markers stay inline (the theme rules key on them);
|
|
8
|
+
# the trigger's whole text-color cluster moved theme-side TOGETHER
|
|
9
|
+
# (split-side rule: the base dims must lose to data-active in-layer).
|
|
10
|
+
# The after:* line-indicator geometry stays inline except its paint.
|
|
11
|
+
# The indicator's OPACITY PAIR (rest 0 / active 100) lives fully
|
|
12
|
+
# inline: the rest state is a utility, so a theme-side activation
|
|
13
|
+
# sits in layer(base) and loses to it unconditionally - splitting
|
|
14
|
+
# the pair leaves the line variant's indicator invisible.
|
|
15
|
+
class Style < Poetry::Core::Style
|
|
16
|
+
base "cn-tabs group/tabs flex data-horizontal:flex-col"
|
|
17
|
+
|
|
18
|
+
element :list, "cn-tabs-list group/tabs-list inline-flex w-fit items-center justify-center " \
|
|
19
|
+
"group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col"
|
|
20
|
+
element :list_default, "cn-tabs-list-variant-default"
|
|
21
|
+
element :list_line, "cn-tabs-list-variant-line"
|
|
22
|
+
|
|
23
|
+
element :trigger,
|
|
24
|
+
"cn-tabs-trigger relative inline-flex h-[calc(100%-1px)] flex-1 items-center " \
|
|
25
|
+
"justify-center whitespace-nowrap transition-all group-data-vertical/tabs:w-full " \
|
|
26
|
+
"group-data-vertical/tabs:justify-start focus-visible:border-ring " \
|
|
27
|
+
"focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 " \
|
|
28
|
+
"focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 " \
|
|
29
|
+
"aria-disabled:pointer-events-none aria-disabled:opacity-50 " \
|
|
30
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 after:absolute after:opacity-0 " \
|
|
31
|
+
"after:transition-opacity " \
|
|
32
|
+
"group-data-[variant=line]/tabs-list:data-active:after:opacity-100 " \
|
|
33
|
+
"after:bg-foreground dark:data-active:bg-input/30 dark:data-active:border-input " \
|
|
34
|
+
"dark:data-active:text-foreground " \
|
|
35
|
+
"dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent " \
|
|
36
|
+
"dark:group-data-[variant=line]/tabs-list:data-active:border-transparent " \
|
|
37
|
+
"dark:hover:text-foreground dark:text-muted-foreground data-active:bg-background " \
|
|
38
|
+
"data-active:text-foreground group-data-[variant=line]/tabs-list:bg-transparent " \
|
|
39
|
+
"group-data-[variant=line]/tabs-list:data-active:bg-transparent " \
|
|
40
|
+
"group-data-horizontal/tabs:after:bottom-[-5px] " \
|
|
41
|
+
"group-data-horizontal/tabs:after:h-0.5 group-data-horizontal/tabs:after:inset-x-0 " \
|
|
42
|
+
"group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:inset-y-0 " \
|
|
43
|
+
"group-data-vertical/tabs:after:w-0.5 hover:text-foreground text-foreground/60"
|
|
44
|
+
|
|
45
|
+
element :content, "cn-tabs-content flex-1 outline-none"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# Grid semantics: caption span (aria-labelledby - a grid is not a
|
|
2
|
+
labelable control), then the roving row collection. %>
|
|
3
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
4
|
+
<%= content_tag(:span, label, "id" => label_id, "data-slot" => "tag-group-label", "class" => css(:label)) %>
|
|
5
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(grid_attributes).to_attributes) do %>
|
|
6
|
+
<% tags.each do |tag_slot| %><%= tag_slot %><% end %>
|
|
7
|
+
<% end %>
|
|
8
|
+
<% end %>
|