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,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module FileInput
|
|
6
|
+
# Utility-only (the Separator/Spinner rule): the input variant wears
|
|
7
|
+
# the Input component's own chrome; the dropzone is structural
|
|
8
|
+
# utilities on semantic tokens, with the controller's data-dragging /
|
|
9
|
+
# data-populated (on the ROOT) driving the zone's states through
|
|
10
|
+
# group-data variants. data-slot selectors are the restyle seam.
|
|
11
|
+
class Style < Poetry::Core::Style
|
|
12
|
+
base "group/file-input flex w-full min-w-0 flex-col gap-2"
|
|
13
|
+
|
|
14
|
+
element :dropzone,
|
|
15
|
+
"flex min-h-32 w-full cursor-pointer flex-col items-center justify-center gap-1.5 " \
|
|
16
|
+
"rounded-lg border border-dashed border-input bg-transparent px-6 py-8 text-center " \
|
|
17
|
+
"transition-colors outline-none hover:bg-accent/30 " \
|
|
18
|
+
"has-focus-visible:border-ring has-focus-visible:ring-[3px] has-focus-visible:ring-ring/50 " \
|
|
19
|
+
"group-data-[dragging]/file-input:border-primary " \
|
|
20
|
+
"group-data-[dragging]/file-input:bg-accent/40"
|
|
21
|
+
element :dropzone_disabled, "pointer-events-none cursor-not-allowed opacity-50"
|
|
22
|
+
element :icon, "size-5 text-muted-foreground"
|
|
23
|
+
element :prompt, "text-sm font-medium"
|
|
24
|
+
element :hint, "text-xs text-muted-foreground"
|
|
25
|
+
element :list, "flex flex-col gap-1 text-sm empty:hidden " \
|
|
26
|
+
"[&>li]:flex [&>li]:items-baseline [&>li]:justify-between [&>li]:gap-4 " \
|
|
27
|
+
"[&>li]:rounded-md [&>li]:border [&>li]:px-3 [&>li]:py-1.5 " \
|
|
28
|
+
"[&_[data-slot=file-input-item-size]]:text-xs " \
|
|
29
|
+
"[&_[data-slot=file-input-item-size]]:text-muted-foreground"
|
|
30
|
+
element :clear, "self-start text-sm font-medium text-muted-foreground underline-offset-4 " \
|
|
31
|
+
"hover:text-foreground hover:underline"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<%= trigger %>
|
|
3
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(content_attributes).to_attributes) do %>
|
|
4
|
+
<%= defer ? render(Poetry::Ui::Deferred::Component.new(src: defer)) { content } : content %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<% end %>
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# The HoverCard family - the pointer-hover link preview.
|
|
6
|
+
module HoverCard
|
|
7
|
+
# The placement vocabularies - shared with every popup surface.
|
|
8
|
+
SIDES = Poetry::Ui::PopperConsumer::SIDES
|
|
9
|
+
# The closed vocabulary for the align axis.
|
|
10
|
+
ALIGNS = Poetry::Ui::PopperConsumer::ALIGNS
|
|
11
|
+
|
|
12
|
+
# A rich preview that opens when a pointer hovers a LINK - for
|
|
13
|
+
# sighted pointer users, BY DESIGN not an interaction path. Focus
|
|
14
|
+
# never moves into the card, and it presents NO aria surface (no
|
|
15
|
+
# haspopup/expanded/describedby, role-less content): advertising a
|
|
16
|
+
# keyboard-unreachable surface to assistive technology is worse
|
|
17
|
+
# than silence.
|
|
18
|
+
#
|
|
19
|
+
# THE REACHABLE-ELSEWHERE RULE (non-negotiable): everything in a
|
|
20
|
+
# hover card must exist at the trigger link's destination - the
|
|
21
|
+
# trigger stays an <a href> because it is simultaneously the no-JS
|
|
22
|
+
# fallback, the touch path, and the keyboard path.
|
|
23
|
+
#
|
|
24
|
+
# @example A profile preview behind a real link
|
|
25
|
+
# render Poetry::Ui::HoverCard::Component.new do |card|
|
|
26
|
+
# card.with_trigger(href: "/users/nextjs") { "@nextjs" }
|
|
27
|
+
# "Joined December 2021."
|
|
28
|
+
# end
|
|
29
|
+
class Component < Poetry::Core::Component
|
|
30
|
+
include Poetry::Ui::ComposableTrigger
|
|
31
|
+
include Poetry::Ui::PopperConsumer
|
|
32
|
+
|
|
33
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
34
|
+
AGENT_RULES = [
|
|
35
|
+
ComposableTrigger::AGENT_RULE,
|
|
36
|
+
"Use poetry_hover_card - never hand-roll hover-div previews.",
|
|
37
|
+
"THE REACHABLE-ELSEWHERE RULE (non-negotiable): every piece of information in a hover card " \
|
|
38
|
+
"MUST exist at the trigger link's destination (or another keyboard/touch-reachable surface). " \
|
|
39
|
+
"The card is pointer-only enrichment - keyboard and touch users never see inside it.",
|
|
40
|
+
"The trigger must be a REAL link with a real href - it is the fallback, the touch path, and " \
|
|
41
|
+
"the keyboard path all at once. For a button LOOK, pass variant:/size: (renders through " \
|
|
42
|
+
"Button, still an <a> via href:) - never swap the tag to :button.",
|
|
43
|
+
"NO interactive elements inside the card - they get tabindex=-1 stripped and become " \
|
|
44
|
+
"pointer-only traps. Actions belong in a Popover or at the destination.",
|
|
45
|
+
"Don't add aria-expanded/haspopup to the trigger - advertising an unreachable surface is " \
|
|
46
|
+
"worse than silence.",
|
|
47
|
+
"Never use HoverCard for hints (Tooltip) or for content users act on (Popover).",
|
|
48
|
+
"Prefer defer: for expensive previews - a lazy turbo-frame that fetches on first open."
|
|
49
|
+
].freeze
|
|
50
|
+
|
|
51
|
+
# The slots before_render enforces, stated statically for render-free checks.
|
|
52
|
+
REQUIRED_SLOTS = { trigger: "the enriched link" }.freeze
|
|
53
|
+
|
|
54
|
+
renders_one :trigger,
|
|
55
|
+
doc: "The enriched LINK: a real navigable <a> - THE no-JS fallback. tag: passthrough exists but " \
|
|
56
|
+
"change it knowingly (an <a> is the contract's fallback story). NO " \
|
|
57
|
+
"aria-haspopup/expanded/describedby - the card is invisible to the accessibility tree on " \
|
|
58
|
+
"purpose. Built as a lazy anatomy part (rendered at render time, not at with_trigger " \
|
|
59
|
+
"time). variant:/size: route through Button::Component - Button's href-implies-anchor " \
|
|
60
|
+
"keeps the trigger a REAL <a> wearing button styling, so the reachable-elsewhere contract " \
|
|
61
|
+
"holds.",
|
|
62
|
+
renders: lambda { |href: nil, tag: :a, **options, &block|
|
|
63
|
+
@trigger_href = href
|
|
64
|
+
attrs = {
|
|
65
|
+
"id" => trigger_id, "data-slot" => "hover-card-trigger"
|
|
66
|
+
}.merge(stimulus_attributes_for(:trigger))
|
|
67
|
+
# Trigger state: bare data-popup-open while open, NO attribute
|
|
68
|
+
# while closed (absence IS the state).
|
|
69
|
+
attrs["data-popup-open"] = "" if open
|
|
70
|
+
next composed_trigger(attrs, options, &block) if options[:compose]
|
|
71
|
+
if options.key?(:variant) || options.key?(:size)
|
|
72
|
+
next Button::Component.new(href: href, **attrs, **options, &block)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
attrs["href"] = href if href.present?
|
|
76
|
+
Trigger.new(tag_name: tag, attributes: Poetry::Core::HTML::Attributes.merged(attrs, options))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
use_stimulus do
|
|
80
|
+
on :root do
|
|
81
|
+
controller :hover_card do
|
|
82
|
+
register
|
|
83
|
+
value :open
|
|
84
|
+
value :open_delay
|
|
85
|
+
value :close_delay
|
|
86
|
+
end
|
|
87
|
+
controller :popper do
|
|
88
|
+
register
|
|
89
|
+
value :side
|
|
90
|
+
value :align
|
|
91
|
+
value :side_offset
|
|
92
|
+
value :align_offset
|
|
93
|
+
value :avoid_collisions
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
# The trigger handlers: pointerenter/leave pair
|
|
97
|
+
# timers (touch excluded), focus opens immediately / blur closes,
|
|
98
|
+
# and the touchstart guard (a tap navigates, never focus-opens).
|
|
99
|
+
on :trigger do
|
|
100
|
+
controller :hover_card do
|
|
101
|
+
action :pointer_enter, on: :pointerenter
|
|
102
|
+
action :pointer_leave, on: :pointerleave
|
|
103
|
+
action :focus_open, on: :focus
|
|
104
|
+
action :blur_close, on: :blur
|
|
105
|
+
action :touch_guard, on: :touchstart
|
|
106
|
+
end
|
|
107
|
+
controller(:popper) { target :anchor }
|
|
108
|
+
end
|
|
109
|
+
on :content do
|
|
110
|
+
controller(:popper) { target :content }
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
option :open, :boolean, default: false, doc: "Renders the card already open on page load."
|
|
115
|
+
option :defer, :string,
|
|
116
|
+
doc: "Defer the card body to a lazy turbo-frame. The panel is hidden until hover, so the fetch fires " \
|
|
117
|
+
"on first open for free; the component block (if any) becomes the frame's placeholder."
|
|
118
|
+
option :open_delay, :integer, default: 600, doc: "Hover-intent delay in ms before the card opens."
|
|
119
|
+
option :close_delay, :integer, default: 300,
|
|
120
|
+
doc: "Close-grace window in ms over the trigger+content pair."
|
|
121
|
+
# Placement defaults: bottom / center, 4px side offset.
|
|
122
|
+
popper_placement_options(side: :bottom, side_offset: 4)
|
|
123
|
+
option :content_class, :string,
|
|
124
|
+
doc: "The panel's class merge seam - e.g. content_class: \"w-80\" widens the card."
|
|
125
|
+
|
|
126
|
+
part "hover-card", "Root wrapper around the trigger link and the panel"
|
|
127
|
+
part "hover-card-trigger", "The enriched link itself - simultaneously the no-JS " \
|
|
128
|
+
"fallback, the touch path, and the keyboard path",
|
|
129
|
+
states: {
|
|
130
|
+
"data-popup-open" => "bare while the card is open; absent while closed " \
|
|
131
|
+
"(absence IS the closed state)"
|
|
132
|
+
}
|
|
133
|
+
part "hover-card-content", "The role-less preview panel (invisible to AT on purpose) - " \
|
|
134
|
+
"positioning, animation, and the open state ride here",
|
|
135
|
+
states: {
|
|
136
|
+
"data-open" => "card is open (the controller flips the pair at runtime)",
|
|
137
|
+
"data-closed" => "card is closed (the server-rendered state; hidden rides along)",
|
|
138
|
+
"data-side" => { condition: "always - the side (initial placement, re-resolved " \
|
|
139
|
+
"live by popper after flip)",
|
|
140
|
+
values: SIDES.map(&:to_s) },
|
|
141
|
+
"data-align" => { condition: "always - the alignment (re-resolved live by popper)",
|
|
142
|
+
values: ALIGNS.map(&:to_s) }
|
|
143
|
+
},
|
|
144
|
+
vars: Poetry::Ui::PopperConsumer.content_vars
|
|
145
|
+
|
|
146
|
+
# Enforces the required trigger; warns when it has no href.
|
|
147
|
+
# @api private
|
|
148
|
+
def before_render
|
|
149
|
+
raise ArgumentError, "HoverCard requires with_trigger (the enriched link)" unless trigger?
|
|
150
|
+
|
|
151
|
+
return if @trigger_href.present?
|
|
152
|
+
|
|
153
|
+
# Lint-level warning, not an error (anchors-without-href exist in
|
|
154
|
+
# legacy hosts): a trigger without a real destination defeats the
|
|
155
|
+
# reachable-elsewhere contract.
|
|
156
|
+
Rails.logger&.warn(
|
|
157
|
+
"poetry HoverCard: trigger has no href - the link IS the keyboard/touch/no-JS path " \
|
|
158
|
+
"(the reachable-elsewhere rule)"
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# The preview panel's attributes.
|
|
163
|
+
# @api private
|
|
164
|
+
def content_attributes
|
|
165
|
+
attrs = {
|
|
166
|
+
"id" => content_id,
|
|
167
|
+
"data-slot" => "hover-card-content", (open ? "data-open" : "data-closed") => "",
|
|
168
|
+
# Initial placement, re-resolved live by popper on open.
|
|
169
|
+
"data-side" => side, "data-align" => align,
|
|
170
|
+
"class" => css(:content, class: content_class)
|
|
171
|
+
}.merge(stimulus_attributes_for(:content))
|
|
172
|
+
attrs["hidden"] = true unless open
|
|
173
|
+
attrs
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
private :content_attributes
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# The trigger anatomy part - renders the chosen tag carrying
|
|
180
|
+
# pre-built wiring. internal_component!: full machinery, no
|
|
181
|
+
# registry entry (the trigger is anatomy, not a component).
|
|
182
|
+
#
|
|
183
|
+
# @api private
|
|
184
|
+
class Trigger < Poetry::Core::Component
|
|
185
|
+
internal_component!
|
|
186
|
+
|
|
187
|
+
# Carries pre-built wiring only. (@attributes is Component's
|
|
188
|
+
# ActiveModel storage - the wiring rides its own ivar.)
|
|
189
|
+
def initialize(tag_name:, attributes:)
|
|
190
|
+
super({})
|
|
191
|
+
@tag_name = tag_name
|
|
192
|
+
@trigger_attributes = attributes
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def call
|
|
196
|
+
content_tag(@tag_name, content, @trigger_attributes)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module HoverCard
|
|
6
|
+
# The HoverCard preview matrix: the ported hover-card-demo profile
|
|
7
|
+
# preview (the @nextjs card, w-80 override), the server-pinned open
|
|
8
|
+
# state, a placement sample, and custom delays. Every preview's card
|
|
9
|
+
# content is reachable at the trigger's href - the
|
|
10
|
+
# reachable-elsewhere audit runs against real destinations.
|
|
11
|
+
class Preview < Poetry::Core::Preview::Base
|
|
12
|
+
# The hover-card-demo port: a real profile link enriched with the
|
|
13
|
+
# profile preview. The trigger text is the link; the card is pure
|
|
14
|
+
# enhancement over navigation.
|
|
15
|
+
def default
|
|
16
|
+
profile_example
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Server-pinned open (controllable-state; the controller
|
|
20
|
+
# reconciles the layer + the tabindex strip on connect).
|
|
21
|
+
def open
|
|
22
|
+
profile_example(open: true)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Placement sample (data-side re-resolves live on collision).
|
|
26
|
+
def side_right
|
|
27
|
+
render_component(side: :right, align: :start) do |card|
|
|
28
|
+
card.with_trigger(href: "https://github.com/vercel") { "@vercel" }
|
|
29
|
+
"Develop. Preview. Ship."
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Snappier delays for preview-dense surfaces (the docs recommend
|
|
34
|
+
# keeping open_delay >= ~300ms - accidental opens while mousing
|
|
35
|
+
# across text feel broken).
|
|
36
|
+
def fast
|
|
37
|
+
render_component(open_delay: 300, close_delay: 150) do |card|
|
|
38
|
+
card.with_trigger(href: "https://github.com/rails") { "@rails" }
|
|
39
|
+
"Ruby on Rails - the full-stack web framework."
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def profile_example(**)
|
|
46
|
+
render_component(content_class: "w-80", **) do |card|
|
|
47
|
+
card.with_trigger(href: "https://github.com/nextjs", class: "text-sm font-medium underline-offset-4 hover:underline") { "@nextjs" }
|
|
48
|
+
# No text size here - the card's type scale is theme-owned
|
|
49
|
+
# (.cn-hover-card-content; mira/lyra run text-xs/relaxed).
|
|
50
|
+
tag.div(class: "flex flex-col gap-1") do
|
|
51
|
+
tag.h4("@nextjs", class: "font-semibold") +
|
|
52
|
+
tag.p("The React Framework - created and maintained by @vercel.") +
|
|
53
|
+
tag.div("Joined December 2021", class: "text-xs text-muted-foreground")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module HoverCard
|
|
6
|
+
# Re-expressed through the cn-* theme layer. One element: the
|
|
7
|
+
# preview panel on the popover token scheme; the origin class binds
|
|
8
|
+
# through tokens/aliases.css and stays inline. Width is theme-side
|
|
9
|
+
# (mira/rhea widen to w-72; every fragment owns it) -
|
|
10
|
+
# caller w-* classes still win from the utilities layer.
|
|
11
|
+
class Style < Poetry::Core::Style
|
|
12
|
+
element :content, "cn-hover-card-content z-50 " \
|
|
13
|
+
"origin-(--transform-origin) outline-hidden"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# The Icon family - inline SVG icons from the configured icon set.
|
|
6
|
+
module Icon
|
|
7
|
+
# The Icon component: template-less, rendering an icon's vendored,
|
|
8
|
+
# pre-sanitized inner markup from the configured icon set
|
|
9
|
+
# (`config.icon_library`, Lucide by default via poetry-lucide;
|
|
10
|
+
# override per render with `library:`).
|
|
11
|
+
#
|
|
12
|
+
# The ARIA contract:
|
|
13
|
+
# - `label:` given -> standalone/informative: role="img" + aria-label
|
|
14
|
+
# - no `label:` -> decorative: aria-hidden="true" + focusable="false"
|
|
15
|
+
#
|
|
16
|
+
# @example A decorative icon inside a labeled control
|
|
17
|
+
# render Poetry::Ui::Icon::Component.new(name: :plus)
|
|
18
|
+
class Component < Poetry::Core::Component
|
|
19
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
20
|
+
AGENT_RULES = [
|
|
21
|
+
"Icons are decorative by default (aria-hidden); pass label: when the icon stands alone.",
|
|
22
|
+
"Never inline raw <svg> markup where an icon exists - use poetry_icon."
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
25
|
+
option :name, :symbol, required: true, format: :"icon-name",
|
|
26
|
+
doc: "The icon's name in the active set. format: :\"icon-name\" is the " \
|
|
27
|
+
"machine-readable value contract: the registry carries it, and literal names are " \
|
|
28
|
+
"validated against the icon set statically - a misspelled name is caught before " \
|
|
29
|
+
"it can crash a render."
|
|
30
|
+
option :label, :string,
|
|
31
|
+
doc: "The accessible name - given, the icon is standalone (role=img); absent, it is decorative " \
|
|
32
|
+
"(aria-hidden)."
|
|
33
|
+
option :library, :symbol, doc: "Per-render icon set override (defaults to config.icon_library)."
|
|
34
|
+
|
|
35
|
+
validate :icon_must_exist
|
|
36
|
+
|
|
37
|
+
part "icon", "The <svg> root itself - the vendored icon markup renders inside; " \
|
|
38
|
+
"ARIA (label: vs decorative) rides here"
|
|
39
|
+
|
|
40
|
+
# Renders the <svg> with the icon's inner markup.
|
|
41
|
+
# @api private
|
|
42
|
+
def call
|
|
43
|
+
# Vendored + sanitized at vendor time (the fetch pipeline) - the
|
|
44
|
+
# inner markup is trusted by construction; render never parses.
|
|
45
|
+
content_tag(:svg, resolved_markup.html_safe, **svg_attributes.to_attributes)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def icon_set
|
|
51
|
+
Poetry::Core::Icons.set(library)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The missing-icon policy. poetry check catches literal
|
|
55
|
+
# names statically; a DYNAMIC name (a DB value, a user setting) only
|
|
56
|
+
# surfaces here - and a bad one should not 500 production. Dev/test
|
|
57
|
+
# keep the raise (config.raise_on_missing_icon nil = auto via
|
|
58
|
+
# Rails.env.local?); elsewhere the configured fallback renders and
|
|
59
|
+
# config.on_missing_icon fires (per render - dedup is the app's
|
|
60
|
+
# concern). A nil or itself-missing fallback re-raises the original.
|
|
61
|
+
def resolved_markup
|
|
62
|
+
icon_set.fetch(name)
|
|
63
|
+
rescue Poetry::Core::IconNotFound => e
|
|
64
|
+
raise if raise_on_missing_icon?
|
|
65
|
+
|
|
66
|
+
config = self.class.config
|
|
67
|
+
config.on_missing_icon&.call(name: name, library: library || config.icon_library, error: e)
|
|
68
|
+
fallback = config.icon_fallback
|
|
69
|
+
raise if fallback.nil?
|
|
70
|
+
|
|
71
|
+
begin
|
|
72
|
+
icon_set.fetch(fallback)
|
|
73
|
+
rescue Poetry::Core::IconNotFound
|
|
74
|
+
raise e
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def raise_on_missing_icon?
|
|
79
|
+
configured = self.class.config.raise_on_missing_icon
|
|
80
|
+
return configured unless configured.nil?
|
|
81
|
+
|
|
82
|
+
!defined?(Rails.env) || Rails.env.local?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def icon_must_exist
|
|
86
|
+
return if name.blank? || icon_set.include?(name)
|
|
87
|
+
|
|
88
|
+
suggestion = Poetry::Core::Icons.suggest(name, icon_set.names)
|
|
89
|
+
hint = suggestion ? " - did you mean #{suggestion.to_sym.inspect}?" : ""
|
|
90
|
+
errors.add(:name, "unknown icon #{name.inspect} in the " \
|
|
91
|
+
"#{library || self.class.config.icon_library} set#{hint}")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def svg_attributes
|
|
95
|
+
html_attributes.merge_if_not_set(default_svg_attributes.merge(aria_attributes))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def default_svg_attributes
|
|
99
|
+
{
|
|
100
|
+
"xmlns" => "http://www.w3.org/2000/svg",
|
|
101
|
+
# Lucide's intrinsic box. Without it a standalone icon fills its
|
|
102
|
+
# container (a standalone icon once rendered 352px wide);
|
|
103
|
+
# inside components the [&_svg]:size-4 rules still win
|
|
104
|
+
# (CSS beats presentation attributes).
|
|
105
|
+
"width" => "24",
|
|
106
|
+
"height" => "24",
|
|
107
|
+
"viewBox" => "0 0 24 24",
|
|
108
|
+
"fill" => "none",
|
|
109
|
+
"stroke" => "currentColor",
|
|
110
|
+
"stroke-width" => "2",
|
|
111
|
+
"stroke-linecap" => "round",
|
|
112
|
+
"stroke-linejoin" => "round",
|
|
113
|
+
"data-slot" => "icon"
|
|
114
|
+
}.merge(component_data_attributes)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def aria_attributes
|
|
118
|
+
if label.present?
|
|
119
|
+
{ "role" => "img", "aria-label" => label }
|
|
120
|
+
else
|
|
121
|
+
{ "aria-hidden" => "true", "focusable" => "false" }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Icon
|
|
6
|
+
class Preview < Poetry::Core::Preview::Base
|
|
7
|
+
def decorative
|
|
8
|
+
render_component(name: :plus)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def standalone_labeled
|
|
12
|
+
render_component(name: :trash, label: "Delete")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def chevron
|
|
16
|
+
render_component(name: :"chevron-right")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# The Input family - the single-line native text control.
|
|
6
|
+
module Input
|
|
7
|
+
# The text Input - the styled native <input>. Template-less; error
|
|
8
|
+
# state is carried by aria-invalid (set by the Field/FormBuilder from
|
|
9
|
+
# model errors), which the classes style directly - state IS the
|
|
10
|
+
# accessibility attribute, never a parallel class.
|
|
11
|
+
#
|
|
12
|
+
# @example An email field
|
|
13
|
+
# render Poetry::Ui::Input::Component.new(type: "email", name: "email",
|
|
14
|
+
# placeholder: "you@example.com")
|
|
15
|
+
class Component < Poetry::Core::Component
|
|
16
|
+
# The mask controller identifier: masking is an Input OPTION,
|
|
17
|
+
# not a separate component.
|
|
18
|
+
MASK = %i[poetry core mask].freeze
|
|
19
|
+
|
|
20
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
21
|
+
AGENT_RULES = [
|
|
22
|
+
"Inside a form, never render Input directly - use the FormBuilder's field (it wires ids, errors, and aria).",
|
|
23
|
+
"Error styling comes from aria-invalid, set from model errors - never hand-toggle error classes.",
|
|
24
|
+
"mask: formats as the user types ('(999) 999-9999'; 9=digit, a=letter, A=upper, " \
|
|
25
|
+
"*=alnum, #=sign/digit, \\\\ escapes, ? makes the rest optional) - the MASKED text " \
|
|
26
|
+
"submits; read data-raw for the bare value."
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
option :type, :string, default: "text", doc: "The native type attribute (text, email, password, file, ...)."
|
|
30
|
+
option :name, :string, doc: "The submitted param name."
|
|
31
|
+
option :value, :string, doc: "The current value."
|
|
32
|
+
option :placeholder, :string, doc: "Native placeholder text - not a substitute for a Label."
|
|
33
|
+
option :disabled, :boolean, default: false, doc: "Disables the native input."
|
|
34
|
+
option :invalid, :boolean, default: false,
|
|
35
|
+
doc: "Marks the input aria-invalid - the error skin keys on the attribute."
|
|
36
|
+
option :mask, :string,
|
|
37
|
+
doc: "Format-as-you-type mask descriptor ('(999) 999-9999'). Extra knobs (slot char, always-show, " \
|
|
38
|
+
"auto-clear) ride Stimulus values via data: - one declarative option covers the common case."
|
|
39
|
+
|
|
40
|
+
part "input", "The <input> element itself - no inner anatomy; error state is " \
|
|
41
|
+
"aria-invalid (set by Field/FormBuilder), never a parallel class",
|
|
42
|
+
states: {
|
|
43
|
+
"data-raw" => "mask: is set - the unmasked value, kept live by the mask " \
|
|
44
|
+
"controller (the masked text is what submits)"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Renders the <input> element.
|
|
48
|
+
# @api private
|
|
49
|
+
def call
|
|
50
|
+
tag.input(**root_attributes.to_attributes)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The <input> element's attributes.
|
|
54
|
+
# @api private
|
|
55
|
+
def root_attributes
|
|
56
|
+
attrs = { "type" => type, "data-slot" => "input" }.merge(component_data_attributes)
|
|
57
|
+
attrs["name"] = name if name.present?
|
|
58
|
+
attrs["value"] = value if value.present?
|
|
59
|
+
attrs["placeholder"] = placeholder if placeholder.present?
|
|
60
|
+
attrs["disabled"] = true if disabled
|
|
61
|
+
attrs["aria-invalid"] = true if invalid
|
|
62
|
+
attrs.merge!(mask_attributes) if mask.present?
|
|
63
|
+
html_attributes.merge_if_not_set(attrs)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def mask_attributes
|
|
69
|
+
attrs = Poetry::Core::HTML::Attributes.new
|
|
70
|
+
masked = Poetry::Core::Stimulus::Builder.new(MASK, attrs)
|
|
71
|
+
masked.register_controller
|
|
72
|
+
masked.with_value(:mask, mask)
|
|
73
|
+
attrs.to_attributes
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private :root_attributes
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Input
|
|
6
|
+
# The Input preview matrix. Standalone inputs carry an aria-label so
|
|
7
|
+
# each state is accessible on its own; real forms wire the name via
|
|
8
|
+
# Field/FormBuilder instead (see the Field previews).
|
|
9
|
+
class Preview < Poetry::Core::Preview::Base
|
|
10
|
+
def default
|
|
11
|
+
render_component(type: "email", name: "email", placeholder: "you@example.com",
|
|
12
|
+
"aria-label" => "Email")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def with_value
|
|
16
|
+
render_component(name: "city", value: "Lisbon", "aria-label" => "City")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def disabled
|
|
20
|
+
render_component(name: "plan", value: "Enterprise", disabled: true, "aria-label" => "Plan")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def invalid
|
|
24
|
+
render_component(type: "email", name: "email", value: "not-an-email", invalid: true,
|
|
25
|
+
"aria-label" => "Email")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def masked
|
|
29
|
+
render_component(type: "tel", name: "phone", mask: "(999) 999-9999",
|
|
30
|
+
placeholder: "(555) 000-0000", "aria-label" => "Phone")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Input
|
|
6
|
+
# Re-expressed through the cn-* theme layer: the field chrome
|
|
7
|
+
# (border, ring, invalid, dark treatments) rides themes/default.css.
|
|
8
|
+
# Placeholder color is theme-side: rhea's tinted field
|
|
9
|
+
# surface (bg-input/50) needs a darkened placeholder to hold AA, and
|
|
10
|
+
# an inline color would beat any theme's (layer order).
|
|
11
|
+
class Style < Poetry::Core::Style
|
|
12
|
+
base "cn-input w-full min-w-0 outline-none file:inline-flex file:border-0 " \
|
|
13
|
+
"file:bg-transparent file:text-foreground disabled:pointer-events-none " \
|
|
14
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%# A trailing action inside the field surface. %>
|
|
2
|
+
<div class="w-80 p-4">
|
|
3
|
+
<%= poetry_label(for_id: "input-group-url", class: "sr-only") { "Page URL" } %>
|
|
4
|
+
<%= poetry_input_group do %>
|
|
5
|
+
<%= poetry_input_group_input(id: "input-group-url", name: "url", value: "https://poetry.example") %>
|
|
6
|
+
<%= poetry_input_group_addon(align: :"inline-end") do %>
|
|
7
|
+
<%= poetry_input_group_button(size: :"icon-xs", label: "Copy URL") do %>
|
|
8
|
+
<%= poetry_icon(name: :copy) %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|