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,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Carousel family: the scroll-snap slide strip and its paging controls.
|
|
6
|
+
module Carousel
|
|
7
|
+
# A slide carousel on native scroll-snap: the viewport is a real
|
|
8
|
+
# scroll container, so touch, momentum, and snapping work with no
|
|
9
|
+
# JS, and prev/next paging plus arrow keys are layered on top.
|
|
10
|
+
# Declare slides with with_item; the component owns the region and
|
|
11
|
+
# slide ARIA and renders the controls.
|
|
12
|
+
#
|
|
13
|
+
# Looping, autoplay, and plugins are not supported.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# render Poetry::Ui::Carousel::Component.new(label: "Featured") do |carousel|
|
|
17
|
+
# carousel.with_item { "Slide one" }
|
|
18
|
+
# carousel.with_item { "Slide two" }
|
|
19
|
+
# end
|
|
20
|
+
class Component < Poetry::Core::Component
|
|
21
|
+
# The closed vocabulary for the orientation axis.
|
|
22
|
+
ORIENTATIONS = %i[horizontal vertical].freeze
|
|
23
|
+
|
|
24
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
25
|
+
AGENT_RULES = [
|
|
26
|
+
"label: is REQUIRED - the carousel region's accessible name.",
|
|
27
|
+
"Declare slides with with_item - the component stamps the slide roles " \
|
|
28
|
+
"(role=group + aria-roledescription=slide).",
|
|
29
|
+
"Slides are REAL scroll content: they stay reachable by swipe, wheel, and keyboard even " \
|
|
30
|
+
"before JS - never gate content behind the buttons alone.",
|
|
31
|
+
"Size slides with item classes (basis-full default; basis-1/2 lg:basis-1/3 for a gallery).",
|
|
32
|
+
"Change slide spacing as a TRIO: track_classes: \"-ml-1\" plus item classes " \
|
|
33
|
+
"\"pl-1 -scroll-ml-1\" - the gutter padding and its snap scroll-margin move together."
|
|
34
|
+
].freeze
|
|
35
|
+
|
|
36
|
+
# States statically that with_item requires a content block, so
|
|
37
|
+
# static checks can flag the omission without rendering.
|
|
38
|
+
SLOT_REQUIRED_CONTENT = { item: "the slide" }.freeze
|
|
39
|
+
|
|
40
|
+
# The required slots, stated statically so static checks can flag
|
|
41
|
+
# a missing slide without rendering.
|
|
42
|
+
REQUIRED_SLOTS = { item: "at least one slide" }.freeze
|
|
43
|
+
|
|
44
|
+
renders_many :items,
|
|
45
|
+
doc: "Declares one slide. The content block is required; classes: sizes the slide (basis-full " \
|
|
46
|
+
"default).",
|
|
47
|
+
renders: lambda { |classes: nil, &block|
|
|
48
|
+
raise ArgumentError, "Carousel with_item requires a content block (the slide)" unless block
|
|
49
|
+
|
|
50
|
+
slides << Slide.new(classes: classes, block: block)
|
|
51
|
+
nil
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
use_stimulus do
|
|
55
|
+
on :root do
|
|
56
|
+
controller :carousel do
|
|
57
|
+
register
|
|
58
|
+
value :orientation
|
|
59
|
+
action :keydown, on: :keydown
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
on :viewport do
|
|
63
|
+
controller :carousel do
|
|
64
|
+
target :viewport
|
|
65
|
+
action :scrolled, on: :scroll
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
# One element per control direction, forwarded into Button
|
|
69
|
+
# kwargs (previously hand-written target + action strings).
|
|
70
|
+
on :previous do
|
|
71
|
+
controller :carousel do
|
|
72
|
+
target :previous
|
|
73
|
+
action :previous, on: :click
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
on :next do
|
|
77
|
+
controller :carousel do
|
|
78
|
+
target :next
|
|
79
|
+
action :next, on: :click
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
option :label, :string, required: true,
|
|
85
|
+
doc: "The carousel region's accessible name - required; rendering without it raises."
|
|
86
|
+
option :orientation, :symbol, default: :horizontal,
|
|
87
|
+
doc: "The scroll axis; snapping, controls, and arrow keys follow it."
|
|
88
|
+
option :show_controls, :boolean, default: true,
|
|
89
|
+
doc: "Renders the prev/next buttons; slides stay reachable by swipe, wheel, " \
|
|
90
|
+
"and keyboard without them."
|
|
91
|
+
option :track_classes, :string,
|
|
92
|
+
doc: "Utility classes for the slide track - change spacing as a trio: track_classes: \"-ml-1\" pairs " \
|
|
93
|
+
"with item classes \"pl-1 -scroll-ml-1\"."
|
|
94
|
+
|
|
95
|
+
validates :orientation, inclusion: { in: ORIENTATIONS }
|
|
96
|
+
|
|
97
|
+
part "carousel", "The role=region root - the controller (paging, button state, arrow keys) " \
|
|
98
|
+
"rides here",
|
|
99
|
+
states: {
|
|
100
|
+
"data-orientation" => { condition: "the scroll axis", values: ORIENTATIONS.map(&:to_s) }
|
|
101
|
+
}
|
|
102
|
+
part "carousel-content", "The viewport - a real scroll-snap container (tabindex=0); the " \
|
|
103
|
+
"platform owns the physics"
|
|
104
|
+
part "carousel-item", "One role=group slide - sized by item classes (basis-full default)"
|
|
105
|
+
|
|
106
|
+
# Enforces the required label and at least one slide.
|
|
107
|
+
# @api private
|
|
108
|
+
def before_render
|
|
109
|
+
raise ArgumentError, "Carousel requires label: (the region's accessible name)" if label.blank?
|
|
110
|
+
raise ArgumentError, "Carousel requires at least one with_item" unless items?
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The declared slides in render order.
|
|
114
|
+
# @api private
|
|
115
|
+
def slides
|
|
116
|
+
@slides ||= []
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Whether the scroll axis is vertical.
|
|
120
|
+
# @api private
|
|
121
|
+
def vertical? = orientation == :vertical
|
|
122
|
+
|
|
123
|
+
# Attributes for the role=region root.
|
|
124
|
+
# @api private
|
|
125
|
+
def root_attributes
|
|
126
|
+
html_attributes.merge_if_not_set(
|
|
127
|
+
{
|
|
128
|
+
"role" => "region", "aria-roledescription" => "carousel", "aria-label" => label,
|
|
129
|
+
"data-slot" => "carousel", "data-orientation" => orientation
|
|
130
|
+
}.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
131
|
+
)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Attributes for the scroll-snap viewport.
|
|
135
|
+
# @api private
|
|
136
|
+
def viewport_attributes
|
|
137
|
+
{
|
|
138
|
+
"data-slot" => "carousel-content",
|
|
139
|
+
# A REAL scroll region must be keyboard-reachable (the ScrollArea
|
|
140
|
+
# rule); the arrows then page it via the root's keydown.
|
|
141
|
+
"tabindex" => "0",
|
|
142
|
+
"class" => "#{css(:content)} #{css(vertical? ? :content_vertical : :content_horizontal)}"
|
|
143
|
+
}.merge(stimulus_attributes_for(:viewport))
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Attributes for one slide.
|
|
147
|
+
# @api private
|
|
148
|
+
def item_attributes(slide)
|
|
149
|
+
# class: rides the merger so caller classes WIN on conflicts -
|
|
150
|
+
# a raw join left basis-1/3 vs the dictionary's basis-full to
|
|
151
|
+
# the compiled sheet's cascade order (which picked basis-full,
|
|
152
|
+
# silently breaking the documented strip sizing).
|
|
153
|
+
{
|
|
154
|
+
"role" => "group", "aria-roledescription" => "slide", "data-slot" => "carousel-item",
|
|
155
|
+
"class" => css(:item, class: [css(vertical? ? :item_vertical : :item_horizontal),
|
|
156
|
+
slide.classes].compact)
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Button options for one prev/next control.
|
|
161
|
+
# @api private
|
|
162
|
+
def control_options(direction)
|
|
163
|
+
{
|
|
164
|
+
variant: :outline, size: :"icon-sm",
|
|
165
|
+
label: direction == :previous ? "Previous slide" : "Next slide",
|
|
166
|
+
class: "cn-carousel-#{direction} #{css(:control)} #{css(:"control_#{direction}_#{orientation}")}",
|
|
167
|
+
data: { slot: "carousel-#{direction == :previous ? "previous" : "next"}" }
|
|
168
|
+
}.merge(stimulus_attributes_for(direction))
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# One declared slide: its extra classes and content block.
|
|
172
|
+
# @api private
|
|
173
|
+
Slide = Data.define(:classes, :block)
|
|
174
|
+
|
|
175
|
+
private :slides, :vertical?, :root_attributes, :viewport_attributes, :item_attributes, :control_options
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Carousel
|
|
6
|
+
# The Carousel preview: full-width slides, a responsive gallery, the
|
|
7
|
+
# spacing trio, and the vertical stack. The -left-12/-right-12
|
|
8
|
+
# controls need gutter room (px-14).
|
|
9
|
+
class Preview < Poetry::Core::Preview::Base
|
|
10
|
+
def default
|
|
11
|
+
render_component(label: "Featured artwork", class: "mx-14 w-64") do |carousel|
|
|
12
|
+
3.times do |n|
|
|
13
|
+
carousel.with_item do
|
|
14
|
+
tag.div("Slide #{n + 1}",
|
|
15
|
+
class: "flex aspect-square items-center justify-center rounded-md border bg-muted text-2xl")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# The Sizes gallery (absorbs the old strip preview): responsive
|
|
22
|
+
# per-item bases, mirroring the docs example - the golden pins the
|
|
23
|
+
# rig-width rendering.
|
|
24
|
+
def sizes
|
|
25
|
+
render_component(label: "Gallery sizes", class: "mx-14 w-96") do |carousel|
|
|
26
|
+
5.times do |n|
|
|
27
|
+
carousel.with_item(classes: "basis-1/2 lg:basis-1/3") do
|
|
28
|
+
tag.div((n + 1).to_s,
|
|
29
|
+
class: "flex aspect-square items-center justify-center rounded-md border bg-muted text-2xl")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# The spacing trio (track_classes + per-item pl/-scroll-ml): the
|
|
36
|
+
# track margin, the gutter padding, and the snap scroll-margin
|
|
37
|
+
# move together - this preview pins the tightened geometry.
|
|
38
|
+
def spacing
|
|
39
|
+
render_component(label: "Tight gallery", track_classes: "-ml-1", class: "mx-14 w-80") do |carousel|
|
|
40
|
+
5.times do |n|
|
|
41
|
+
carousel.with_item(classes: "basis-1/3 pl-1 -scroll-ml-1") do
|
|
42
|
+
tag.div((n + 1).to_s,
|
|
43
|
+
class: "flex aspect-square items-center justify-center rounded-md border bg-muted text-xl")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Vertical stack, upstream's orientation proportions: fixed-height
|
|
50
|
+
# slides (the auto-height track cannot resolve percentage bases),
|
|
51
|
+
# two visible, enough roster to page. The -top-12/-bottom-12
|
|
52
|
+
# controls need gutter room (my-14).
|
|
53
|
+
def vertical
|
|
54
|
+
render_component(label: "Release milestones", orientation: :vertical,
|
|
55
|
+
class: "mx-auto my-14 grid h-64 w-52") do |carousel|
|
|
56
|
+
6.times do |n|
|
|
57
|
+
carousel.with_item do
|
|
58
|
+
tag.div("Week #{n + 1}",
|
|
59
|
+
class: "flex h-28 items-center justify-center rounded-md border bg-muted text-sm font-semibold")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Carousel
|
|
6
|
+
# Style dictionary for the Carousel family, on native scroll-snap:
|
|
7
|
+
# the content wrapper is the REAL scroll container
|
|
8
|
+
# (overflow + snap + hidden scrollbar) rather than an
|
|
9
|
+
# overflow-hidden + transform track; the gutter idiom (-ml-4 track,
|
|
10
|
+
# pl-4 items) and the control positions are kept as designed.
|
|
11
|
+
class Style < Poetry::Core::Style
|
|
12
|
+
base "relative"
|
|
13
|
+
|
|
14
|
+
element :content, "overflow-auto [scrollbar-width:none] snap-mandatory"
|
|
15
|
+
element :content_horizontal, "snap-x"
|
|
16
|
+
element :content_vertical, "snap-y"
|
|
17
|
+
|
|
18
|
+
element :track, "flex"
|
|
19
|
+
element :track_horizontal, "-ml-4"
|
|
20
|
+
element :track_vertical, "-mt-4 flex-col"
|
|
21
|
+
|
|
22
|
+
element :item, "min-w-0 shrink-0 grow-0 basis-full snap-start"
|
|
23
|
+
# The negative scroll-margin cancels the gutter from the snap area:
|
|
24
|
+
# native snap-start (and scrollIntoView) aligns the item's BORDER
|
|
25
|
+
# box, which includes the pl-4 gutter - without it, every slide
|
|
26
|
+
# after the first snaps 16px short and its trailing edge clips.
|
|
27
|
+
# An engine that translates by measured offsets never has this seam.
|
|
28
|
+
element :item_horizontal, "pl-4 -scroll-ml-4"
|
|
29
|
+
element :item_vertical, "pt-4 -scroll-mt-4"
|
|
30
|
+
|
|
31
|
+
element :control, "absolute touch-manipulation"
|
|
32
|
+
element :control_previous_horizontal, "inset-y-0 -left-12 my-auto"
|
|
33
|
+
element :control_previous_vertical, "-top-12 left-1/2 -translate-x-1/2 rotate-90"
|
|
34
|
+
element :control_next_horizontal, "inset-y-0 -right-12 my-auto"
|
|
35
|
+
element :control_next_vertical, "-bottom-12 left-1/2 -translate-x-1/2 rotate-90"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%# Fragment - button + input(s) as SIBLINGS, no wrapper: the source's
|
|
2
|
+
`peer` class contract (labels style via peer-*) breaks if poetry wraps.
|
|
3
|
+
The controller lives on the button; the input resolves by stable id. %>
|
|
4
|
+
<%= content_tag(:button, **root_attributes.to_attributes) do %>
|
|
5
|
+
<span data-slot="checkbox-indicator" <% if indeterminate? %>data-indeterminate=""<% elsif checked? %>data-checked=""<% else %>data-unchecked=""<% end %> aria-hidden="true" class="<%= css(:indicator) %>">
|
|
6
|
+
<%# MinusIcon on indeterminate is a POETRY ADDITION (shadcn renders a
|
|
7
|
+
check for mixed state - a real gap). %>
|
|
8
|
+
<%= render Poetry::Ui::Icon::Component.new(name: indeterminate? ? :minus : :check, class: css(:icon)) %>
|
|
9
|
+
</span>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% if form_participant? %>
|
|
12
|
+
<%# Rails parity hidden FIRST (last-wins ordering, Tags::CheckBox-exact)
|
|
13
|
+
so unchecked SUBMITS unchecked_value; disabled fields submit nothing. %>
|
|
14
|
+
<% if unchecked_value %>
|
|
15
|
+
<%= tag.input(type: "hidden", name: name, value: unchecked_value, disabled: disabled) %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<%# THE form participant + the store: input.indeterminate is a JS-only
|
|
18
|
+
property - the controller derives it from the checked attributes on connect. %>
|
|
19
|
+
<%= tag.input(type: "checkbox", id: input_id, name: name, value: value, checked: checked?,
|
|
20
|
+
disabled: disabled, "data-slot": "checkbox-input", "aria-hidden": true,
|
|
21
|
+
tabindex: "-1", class: css(:input)) %>
|
|
22
|
+
<% end %>
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Checkbox family: the form-participating tri-state toggle.
|
|
6
|
+
module Checkbox
|
|
7
|
+
# A checkbox. A hidden native <input type=checkbox> is the form
|
|
8
|
+
# participant and the source of truth (server-rendered
|
|
9
|
+
# name/value/checked, Rails "1"/"0" plus the unchecked-hidden
|
|
10
|
+
# pair), while the visual button[role=checkbox] only reflects it
|
|
11
|
+
# via aria-checked and the data-checked / data-unchecked /
|
|
12
|
+
# data-indeterminate triple. Toggling flips the input and lets the
|
|
13
|
+
# real change event bubble; a native form reset re-syncs the
|
|
14
|
+
# visual state from the input. checked: is tri-valued - true,
|
|
15
|
+
# false, or :indeterminate (for select-all parents).
|
|
16
|
+
#
|
|
17
|
+
# The button and inputs render as siblings with no wrapper
|
|
18
|
+
# element, so peer-* label styling keyed on the `peer` class works.
|
|
19
|
+
#
|
|
20
|
+
# @example A form checkbox
|
|
21
|
+
# render Poetry::Ui::Checkbox::Component.new(name: "terms", label: "Accept terms")
|
|
22
|
+
class Component < Poetry::Core::Component
|
|
23
|
+
# The closed vocabulary for the checked: axis.
|
|
24
|
+
STATES = [true, false, :indeterminate].freeze
|
|
25
|
+
|
|
26
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
27
|
+
AGENT_RULES = [
|
|
28
|
+
"A select-all run rides poetry_checkbox_group (wrapper) + poetry_checkbox_group_all " \
|
|
29
|
+
"(the mixed-state parent) + poetry_checkbox_group_item per member - toggles fan out " \
|
|
30
|
+
"and re-derive automatically.",
|
|
31
|
+
"Use poetry_checkbox (or f.check_box) - never a raw input[type=checkbox] with hand-written " \
|
|
32
|
+
"Tailwind, and never a hand-rolled button[role=checkbox].",
|
|
33
|
+
"Always give it a name: in forms - a checkbox without one submits nothing (visual-only mode " \
|
|
34
|
+
"is for controlled UI like DataTable row selection ONLY).",
|
|
35
|
+
"Every checkbox needs an accessible name: a Label/Field for= association (preferred) or label:.",
|
|
36
|
+
"Indeterminate is set programmatically/server-side only - no user gesture produces it; use it " \
|
|
37
|
+
"for select-all parents.",
|
|
38
|
+
"Select-all recipe: wrap parent + rows in data-controller=\"poetry--core--checkbox-group\" with " \
|
|
39
|
+
"data-action=\"poetry:checkbox:change->poetry--core--checkbox-group#changed\"; mark the parent " \
|
|
40
|
+
"box data: {\"poetry--core--checkbox-group-target\": \"all\"} and each row box target \"item\" - " \
|
|
41
|
+
"the parent fans out, rows re-derive checked/unchecked/indeterminate (DataTable's selectable: " \
|
|
42
|
+
"already does this for its own rows).",
|
|
43
|
+
"Instant-effect settings use Switch; pressed UI tools use Toggle; one-of-N uses RadioGroup.",
|
|
44
|
+
"NEVER write the checked attributes (data-checked/data-unchecked/data-indeterminate) without " \
|
|
45
|
+
"aria-checked and the input's checked property (the controller writes all three; agents " \
|
|
46
|
+
"patching DOM must too).",
|
|
47
|
+
"Don't suppress unchecked_value unless using the array idiom - an unchecked box that submits " \
|
|
48
|
+
"nothing silently keeps the old server value."
|
|
49
|
+
].freeze
|
|
50
|
+
|
|
51
|
+
use_stimulus do
|
|
52
|
+
on :root do
|
|
53
|
+
controller :checked do
|
|
54
|
+
register
|
|
55
|
+
# No input-id value -> pure visual mode: state lives on the
|
|
56
|
+
# button's checked attributes alone (discouraged; see AGENT_RULES).
|
|
57
|
+
value :input_id, if: :form_participant?
|
|
58
|
+
action :toggle, on: :click
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# The tri-valued checked: type - casts to exactly
|
|
64
|
+
# true | false | :indeterminate, so one option carries the whole
|
|
65
|
+
# state with no separate indeterminate: flag.
|
|
66
|
+
#
|
|
67
|
+
# @api private
|
|
68
|
+
class CheckedState < ActiveModel::Type::Value
|
|
69
|
+
def type
|
|
70
|
+
:checked_state
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def cast(value)
|
|
74
|
+
return :indeterminate if value.to_s == "indeterminate"
|
|
75
|
+
|
|
76
|
+
ActiveModel::Type::Boolean.new.cast(value) || false
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
option :checked, CheckedState.new, default: false,
|
|
81
|
+
doc: "The state as ONE tri-valued option (true, false, or :indeterminate) " \
|
|
82
|
+
"- there is no separate indeterminate: flag."
|
|
83
|
+
option :name, :string,
|
|
84
|
+
doc: "Form participation: present renders the hidden native input pair; absent leaves the checkbox " \
|
|
85
|
+
"visual-only (controlled UI)."
|
|
86
|
+
option :value, :string, default: "1", doc: "The value submitted when checked (the Rails check_box \"1\")."
|
|
87
|
+
option :unchecked_value, :string, default: "0",
|
|
88
|
+
doc: "The paired hidden input's value submitted when unchecked; nil " \
|
|
89
|
+
"suppresses the pair (the checkbox-array idiom)."
|
|
90
|
+
option :disabled, :boolean, default: false, doc: "Disables the visual button and the hidden input together."
|
|
91
|
+
option :required, :boolean, default: false,
|
|
92
|
+
doc: "aria-required ONLY, never native required - native required on the hidden " \
|
|
93
|
+
"input would make an unfocusable control invalid."
|
|
94
|
+
option :label, :string, doc: "aria-label fallback when no <label for>/Field association exists."
|
|
95
|
+
|
|
96
|
+
part "checkbox", "The visual button[role=checkbox] - reflects the hidden input via " \
|
|
97
|
+
"aria-checked plus the checked triple",
|
|
98
|
+
states: {
|
|
99
|
+
"data-checked" => "checked (the controller reflects every toggle here, " \
|
|
100
|
+
"aria-checked in step)",
|
|
101
|
+
"data-unchecked" => "unchecked - the indicator goes invisible",
|
|
102
|
+
"data-indeterminate" => "checked: :indeterminate (server/programmatic only; " \
|
|
103
|
+
"the first toggle resolves it to checked)"
|
|
104
|
+
}
|
|
105
|
+
part "checkbox-indicator", "Centering span around the check glyph (minus when " \
|
|
106
|
+
"indeterminate) - CSS-hidden while unchecked, never unmounted",
|
|
107
|
+
states: {
|
|
108
|
+
"data-checked" => "mirrors the control (the controller reflects state on " \
|
|
109
|
+
"every part wearing the triple)",
|
|
110
|
+
"data-unchecked" => "mirrors the control - the indicator is invisible",
|
|
111
|
+
"data-indeterminate" => "mirrors the control - the glyph swaps to minus"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Whether checked: is :indeterminate.
|
|
115
|
+
# @api private
|
|
116
|
+
def indeterminate?
|
|
117
|
+
checked == :indeterminate
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Whether checked: is exactly true.
|
|
121
|
+
# @api private
|
|
122
|
+
def checked?
|
|
123
|
+
checked == true
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# The state word behind the data-* stamp.
|
|
127
|
+
# @api private
|
|
128
|
+
def state
|
|
129
|
+
return "indeterminate" if indeterminate?
|
|
130
|
+
|
|
131
|
+
checked? ? "checked" : "unchecked"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# The aria-checked value ("mixed" for indeterminate).
|
|
135
|
+
# @api private
|
|
136
|
+
def aria_checked
|
|
137
|
+
indeterminate? ? "mixed" : checked?.to_s
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# The label-for target (Field-issued or auto) - server-stable so the
|
|
141
|
+
# sibling input resolves structurally by id, wrapper-free.
|
|
142
|
+
# @api private
|
|
143
|
+
def control_id
|
|
144
|
+
@control_id ||= poetry_instance_id("poetry-checkbox")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# The hidden input's id, derived from the control's.
|
|
148
|
+
# @api private
|
|
149
|
+
def input_id
|
|
150
|
+
"#{control_id}-input"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Whether the hidden input pair renders (name: present).
|
|
154
|
+
# @api private
|
|
155
|
+
def form_participant?
|
|
156
|
+
name.present?
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Attributes for the visual button[role=checkbox].
|
|
160
|
+
# @api private
|
|
161
|
+
def root_attributes
|
|
162
|
+
attrs = {
|
|
163
|
+
"type" => "button", "role" => "checkbox", "id" => control_id,
|
|
164
|
+
"aria-checked" => aria_checked, "data-#{state}" => "",
|
|
165
|
+
"data-slot" => "checkbox", "disabled" => disabled
|
|
166
|
+
}
|
|
167
|
+
attrs["aria-required"] = true if required
|
|
168
|
+
attrs["aria-label"] = label if label.present?
|
|
169
|
+
html_attributes.merge_if_not_set(
|
|
170
|
+
attrs.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
171
|
+
)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
private :indeterminate?, :checked?, :state, :aria_checked, :control_id, :input_id, :form_participant?
|
|
175
|
+
private :root_attributes
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Checkbox
|
|
6
|
+
# The Checkbox preview matrix: all three check-states x disabled x
|
|
7
|
+
# invalid, the Field-bound recipe, and the disabled+checked footgun
|
|
8
|
+
# (disabled fields don't submit - a checked box that submits nothing).
|
|
9
|
+
class Preview < Poetry::Core::Preview::Base
|
|
10
|
+
# @!group States
|
|
11
|
+
|
|
12
|
+
def default
|
|
13
|
+
render_component(name: "terms", label: "Accept terms and conditions")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def checked
|
|
17
|
+
render_component(name: "terms", checked: true, label: "Accept terms and conditions")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Server/programmatic only - the select-all parent over a partial
|
|
21
|
+
# selection. Announces as "mixed"; the first toggle resolves to
|
|
22
|
+
# checked (source-exact).
|
|
23
|
+
def indeterminate
|
|
24
|
+
render_component(name: "select_all", checked: :indeterminate, label: "Select all rows")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def disabled
|
|
28
|
+
render_component(name: "terms", disabled: true, label: "Accept terms and conditions")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The footgun preview: disabled inputs DON'T submit - a disabled
|
|
32
|
+
# checked checkbox submits nothing, not "1".
|
|
33
|
+
def disabled_checked
|
|
34
|
+
render_component(name: "terms", checked: true, disabled: true, label: "Locked on (submits nothing)")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def invalid
|
|
38
|
+
render_component(name: "terms", label: "Accept terms and conditions", "aria-invalid": true)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @!endgroup
|
|
42
|
+
|
|
43
|
+
# @!group Recipes
|
|
44
|
+
|
|
45
|
+
# Field-bound: control_attributes land the id (the label-for
|
|
46
|
+
# target), aria-describedby, and aria-required on the BUTTON.
|
|
47
|
+
def in_a_field
|
|
48
|
+
field = Field::Component.new(
|
|
49
|
+
id: "preview-newsletter", label_text: "Email newsletter",
|
|
50
|
+
hint: "Sent weekly. Unsubscribe anytime.", required: true
|
|
51
|
+
)
|
|
52
|
+
render_component(field) do
|
|
53
|
+
embed(Component.new(name: "newsletter", checked: true,
|
|
54
|
+
**field.control_attributes.transform_keys(&:to_sym)))
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Visual-only mode (no name:) - controlled UI like DataTable row
|
|
59
|
+
# selection; state lives on the checked attributes alone (discouraged in forms).
|
|
60
|
+
def visual_only
|
|
61
|
+
render_component(checked: true, label: "Row selected")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @!endgroup
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Checkbox
|
|
6
|
+
# Re-expressed through the cn-* theme layer: the well treatment
|
|
7
|
+
# rides .cn-checkbox in themes/default.css. Poetry mechanisms stay
|
|
8
|
+
# inline: data-unchecked:invisible keeps the indicator in the DOM
|
|
9
|
+
# CSS-hidden (nothing unmounts; there is no exit animation to
|
|
10
|
+
# await), the glyph keeps its designed size-3.5, and :input is the
|
|
11
|
+
# sr-only form store.
|
|
12
|
+
class Style < Poetry::Core::Style
|
|
13
|
+
base "cn-checkbox peer relative shrink-0 outline-none after:absolute " \
|
|
14
|
+
"after:-inset-x-3 after:-inset-y-2 " \
|
|
15
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
16
|
+
|
|
17
|
+
element :indicator, "cn-checkbox-indicator grid place-content-center text-current transition-none " \
|
|
18
|
+
"data-unchecked:invisible"
|
|
19
|
+
|
|
20
|
+
element :icon, ""
|
|
21
|
+
|
|
22
|
+
# The form participant + the store: visually hidden, out of the
|
|
23
|
+
# accessibility tree (the button is the accessible control).
|
|
24
|
+
element :input, "sr-only"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<%# InputGroup anatomy: the readonly mono control, trailing copy
|
|
2
|
+
affordance with stacked copy/check glyphs swapping on data-copied. %>
|
|
3
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
4
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(group_attributes).to_attributes) do %>
|
|
5
|
+
<%= tag.input(**input_attributes.to_attributes) %>
|
|
6
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(addon_attributes).to_attributes) do %>
|
|
7
|
+
<%= render copy_button do %>
|
|
8
|
+
<span class="<%= css(:icon_stack) %>">
|
|
9
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :copy, class: css(:icon_copy)) %>
|
|
10
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :check, class: css(:icon_check)) %>
|
|
11
|
+
</span>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|