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,263 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A numeric input with steppers and display formatting.
|
|
6
|
+
module NumberField
|
|
7
|
+
# A numeric field with stepper buttons and locale-aware display
|
|
8
|
+
# formatting. The anatomy is a formatted visible <input type=text>
|
|
9
|
+
# (announced as "Number field") beside a visually-hidden
|
|
10
|
+
# <input type=number> that is the form and validation truth: the
|
|
11
|
+
# raw number submits (a currency field showing $1,234.50 submits
|
|
12
|
+
# 1234.5), and native required/min/max validation rides the hidden
|
|
13
|
+
# input.
|
|
14
|
+
#
|
|
15
|
+
# Visuals compose from existing primitives - the group wears
|
|
16
|
+
# InputGroup's chrome and the steppers are ghost icon Buttons - so
|
|
17
|
+
# themes restyle it through those components. The server renders
|
|
18
|
+
# the raw number; the display formats on connect. Typed input
|
|
19
|
+
# parses Latin digits (locale separators and currency/percent
|
|
20
|
+
# symbols are handled).
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# render Poetry::Ui::NumberField::Component.new(
|
|
24
|
+
# name: "quantity", value: 2, min: 0, label: "Quantity"
|
|
25
|
+
# )
|
|
26
|
+
class Component < Poetry::Core::Component
|
|
27
|
+
include Poetry::Ui::InputGroupField
|
|
28
|
+
|
|
29
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
30
|
+
AGENT_RULES = [
|
|
31
|
+
"Use poetry_number_field / form.number_field - never a hand-rolled spinner or a bare " \
|
|
32
|
+
"input type=number.",
|
|
33
|
+
"The server reads params[<name>] as the raw number string - display formatting " \
|
|
34
|
+
"(format:) never changes what submits.",
|
|
35
|
+
"Steppers are mouse/touch affordances (tabindex -1); keyboard users step with " \
|
|
36
|
+
"ArrowUp/Down (Shift = large_step, Alt = small_step) on the input itself.",
|
|
37
|
+
"Pair it with a Label/Field for the accessible name - the component ships none.",
|
|
38
|
+
"format: takes Intl.NumberFormatOptions as a Hash ({ style: \"currency\", " \
|
|
39
|
+
"currency: \"USD\" }); pick locale: to pin parsing separators."
|
|
40
|
+
].freeze
|
|
41
|
+
|
|
42
|
+
use_stimulus do
|
|
43
|
+
on :root do
|
|
44
|
+
controller :number_field do
|
|
45
|
+
register
|
|
46
|
+
value :min, from: :min_number, if: -> { min.present? }
|
|
47
|
+
value :max, from: :max_number, if: -> { max.present? }
|
|
48
|
+
value :step, from: :step_number
|
|
49
|
+
value :large_step, from: :large_step_number
|
|
50
|
+
value :small_step, from: :small_step_number
|
|
51
|
+
value :snap, if: :snap
|
|
52
|
+
value :wheel, if: :wheel
|
|
53
|
+
value :format, from: :format_json, if: -> { format.present? }
|
|
54
|
+
value :locale, if: -> { locale.present? }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
on :input do
|
|
58
|
+
controller :number_field do
|
|
59
|
+
target :input
|
|
60
|
+
action :keydown, on: :keydown
|
|
61
|
+
action :input, on: :input
|
|
62
|
+
action :focus, on: :focus
|
|
63
|
+
action :blur, on: :blur
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
# The form/validation truth: the sr-only native number input.
|
|
67
|
+
on :hidden do
|
|
68
|
+
controller :number_field do
|
|
69
|
+
target :hidden
|
|
70
|
+
action :hiddenChanged, on: :change
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
# One element per stepper direction, so stepper(direction)
|
|
74
|
+
# forwards stimulus_attributes_for(direction) into Button kwargs.
|
|
75
|
+
%i[increment decrement].each do |direction|
|
|
76
|
+
on direction do
|
|
77
|
+
controller :number_field do
|
|
78
|
+
target direction
|
|
79
|
+
action :press, on: :pointerdown
|
|
80
|
+
action :tap, on: :click
|
|
81
|
+
action :leave, on: :pointerleave
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
option :name, :string, required: true, doc: "The submitted field name - rides the hidden number input."
|
|
88
|
+
option :value, ActiveModel::Type::Value.new,
|
|
89
|
+
doc: "Initial value - a number; nil renders empty (null semantics)."
|
|
90
|
+
option :min, :float, doc: "The lower clamp for stepping and native validation."
|
|
91
|
+
option :max, :float, doc: "The upper clamp for stepping and native validation."
|
|
92
|
+
option :step, :float, default: 1.0, doc: "The arrow-key / stepper increment."
|
|
93
|
+
option :large_step, :float, default: 10.0, doc: "The Shift-arrow step size (the coarse jump)."
|
|
94
|
+
option :small_step, :float, default: 0.1, doc: "The Alt-arrow step size (the fine adjustment)."
|
|
95
|
+
option :snap, :boolean, default: false, doc: "Snaps stepped values to step multiples counted from min:."
|
|
96
|
+
option :wheel, :boolean, default: false, doc: "Opt-in wheel stepping while the input is focused."
|
|
97
|
+
option :format, ActiveModel::Type::Value.new,
|
|
98
|
+
doc: "Intl.NumberFormatOptions for the DISPLAY (submission stays raw)."
|
|
99
|
+
option :locale, :string,
|
|
100
|
+
doc: "Locale tag pinning the display and parsing separators; the page locale otherwise."
|
|
101
|
+
option :placeholder, :string, doc: "Placeholder text for the empty input."
|
|
102
|
+
option :disabled, :boolean, default: false, doc: "Disables both inputs and the steppers; the group chrome dims."
|
|
103
|
+
option :readonly, :boolean, default: false,
|
|
104
|
+
doc: "Makes the visible input read-only (steppers and typing inert)."
|
|
105
|
+
option :required, :boolean, default: false, doc: "Requires a value - native validation rides the hidden input."
|
|
106
|
+
option :invalid, :boolean, default: false,
|
|
107
|
+
doc: "Marks the field invalid (aria-invalid on the visible input; the group wears " \
|
|
108
|
+
"the destructive ring)."
|
|
109
|
+
option :id, :string, doc: "The visible input's dom id - the seam a Label's for_id: points at."
|
|
110
|
+
option :label, :string,
|
|
111
|
+
doc: "Standalone accessible name -> aria-label on the visible input. Inside a form, the Field label " \
|
|
112
|
+
"wires ids instead - pass neither and pair with poetry_label/form."
|
|
113
|
+
option :described_by, :string, doc: "aria-describedby wiring for Field hint/error pairing."
|
|
114
|
+
|
|
115
|
+
validates :step, numericality: { greater_than: 0 }
|
|
116
|
+
|
|
117
|
+
part "number-field", "Root wrapper - the controller, disabled/invalid/filled state, " \
|
|
118
|
+
"and the two-input pair ride here",
|
|
119
|
+
states: {
|
|
120
|
+
"data-disabled" => "disabled: is set (steppers disable, the group chrome dims)",
|
|
121
|
+
"data-invalid" => "invalid: is set (the group wears the destructive ring via " \
|
|
122
|
+
"the control's aria-invalid)",
|
|
123
|
+
"data-filled" => "the value is non-null (the controller keeps it live)"
|
|
124
|
+
}
|
|
125
|
+
part "number-field-group", "The bordered field surface - wears InputGroup's chrome " \
|
|
126
|
+
"(cn-input-group), focus ring keyed on the control inside"
|
|
127
|
+
part "input-group-addon", "The two stepper cells - InputGroup's addon vocabulary, " \
|
|
128
|
+
"reused so the group paddings compose",
|
|
129
|
+
states: {
|
|
130
|
+
"data-align" => { condition: "always - inline-start holds the decrement, " \
|
|
131
|
+
"inline-end the increment",
|
|
132
|
+
values: %w[inline-start inline-end] }
|
|
133
|
+
}
|
|
134
|
+
part "input-group-control", "The visible formatted <input type=text> - InputGroup's " \
|
|
135
|
+
"control slot (the themes' focus-ring hook); " \
|
|
136
|
+
"aria-roledescription \"Number field\", never a spinbutton"
|
|
137
|
+
# The steppers render as composed ghost Buttons and carry
|
|
138
|
+
# data-slot=number-field-increment/-decrement on Button's root -
|
|
139
|
+
# ownership attributes them to Button (the date-picker-trigger
|
|
140
|
+
# pattern), so they are documented here in prose only.
|
|
141
|
+
|
|
142
|
+
# Rejects a non-numeric value: early.
|
|
143
|
+
# @api private
|
|
144
|
+
def initialize(attributes = {})
|
|
145
|
+
super
|
|
146
|
+
return unless value.present? && !numeric?(value)
|
|
147
|
+
|
|
148
|
+
raise ArgumentError, "value: must be a number (got #{value.inspect})"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Enforces the format: Hash contract.
|
|
152
|
+
# @api private
|
|
153
|
+
def before_render
|
|
154
|
+
return unless format.present? && !format.is_a?(Hash)
|
|
155
|
+
|
|
156
|
+
raise ArgumentError, "format: takes an Intl.NumberFormatOptions Hash"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @api private
|
|
160
|
+
def root_attributes
|
|
161
|
+
attrs = {
|
|
162
|
+
"data-slot" => "number-field",
|
|
163
|
+
"class" => css
|
|
164
|
+
}.merge(component_data_attributes)
|
|
165
|
+
attrs["data-disabled"] = "" if disabled
|
|
166
|
+
attrs["data-invalid"] = "" if invalid
|
|
167
|
+
attrs["data-filled"] = "" if value.present?
|
|
168
|
+
html_attributes.merge_if_not_set(attrs.merge(stimulus_attributes_for(:root)))
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @api private
|
|
172
|
+
def input_attributes
|
|
173
|
+
attrs = Poetry::Core::HTML::Attributes.new(
|
|
174
|
+
"type" => "text",
|
|
175
|
+
"id" => control_id,
|
|
176
|
+
"data-slot" => "input-group-control",
|
|
177
|
+
"class" => Input::Style.css(class: InputGroup::Style.css(:control_input)),
|
|
178
|
+
"inputmode" => inputmode,
|
|
179
|
+
"autocomplete" => "off",
|
|
180
|
+
"autocorrect" => "off",
|
|
181
|
+
"spellcheck" => "false",
|
|
182
|
+
"aria-roledescription" => t("poetry.number_field.roledescription")
|
|
183
|
+
)
|
|
184
|
+
attrs["placeholder"] = placeholder if placeholder.present?
|
|
185
|
+
attrs["value"] = number(value) if value.present?
|
|
186
|
+
attrs["aria-label"] = label if label.present?
|
|
187
|
+
attrs["aria-invalid"] = "true" if invalid && !disabled
|
|
188
|
+
attrs["aria-describedby"] = described_by if described_by.present?
|
|
189
|
+
attrs["disabled"] = "" if disabled
|
|
190
|
+
attrs["readonly"] = "" if readonly
|
|
191
|
+
attrs["required"] = "" if required
|
|
192
|
+
attrs.merge!(stimulus_attributes_for(:input))
|
|
193
|
+
attrs
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# The form/validation truth: raw number out, native constraint
|
|
197
|
+
# validation on. Focus never lands here (tabindex -1, aria-hidden).
|
|
198
|
+
# @api private
|
|
199
|
+
def hidden_attributes
|
|
200
|
+
attrs = Poetry::Core::HTML::Attributes.new(
|
|
201
|
+
"type" => "number",
|
|
202
|
+
"name" => name,
|
|
203
|
+
"class" => "sr-only",
|
|
204
|
+
"tabindex" => "-1",
|
|
205
|
+
"aria-hidden" => "true"
|
|
206
|
+
)
|
|
207
|
+
attrs["value"] = number(value) if value.present?
|
|
208
|
+
attrs["min"] = number(min) if min.present?
|
|
209
|
+
attrs["max"] = number(max) if max.present?
|
|
210
|
+
attrs["step"] = number(step)
|
|
211
|
+
attrs["disabled"] = "" if disabled
|
|
212
|
+
attrs["required"] = "" if required
|
|
213
|
+
attrs.merge!(stimulus_attributes_for(:hidden))
|
|
214
|
+
attrs
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# The stepper Buttons (ghost, icon-xs, InputGroup's tiny-button
|
|
218
|
+
# chrome): tabindex -1 keeps them off the Tab order - keyboard
|
|
219
|
+
# users step on the input. aria-hidden is deliberately NOT applied,
|
|
220
|
+
# so touch screen readers can still activate them.
|
|
221
|
+
# @api private
|
|
222
|
+
def stepper(direction)
|
|
223
|
+
group_tool_button(slot: "number-field-#{direction}",
|
|
224
|
+
label: t("poetry.number_field.#{direction}"),
|
|
225
|
+
wiring: stimulus_attributes_for(direction))
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# @api private
|
|
229
|
+
def stepper_icon(direction)
|
|
230
|
+
direction == :increment ? :plus : :minus
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
private
|
|
234
|
+
|
|
235
|
+
def numeric?(candidate)
|
|
236
|
+
candidate.is_a?(Numeric) || candidate.to_s.match?(/\A-?\d+(\.\d+)?\z/)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Integer ranges starting at zero take the digit keyboard; decimals
|
|
240
|
+
# or open/negative ranges need the full layout.
|
|
241
|
+
def inputmode
|
|
242
|
+
whole = step == step.to_i && (!min.present? || min == min.to_i)
|
|
243
|
+
min.present? && min >= 0 && whole && format.blank? ? "numeric" : "decimal"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Trailing-zero-free numeric strings (5.0 -> "5"), the slider idiom.
|
|
247
|
+
def number(numeric)
|
|
248
|
+
float = Float(numeric)
|
|
249
|
+
float == float.to_i ? float.to_i.to_s : float.to_s
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def min_number = number(min)
|
|
253
|
+
def max_number = number(max)
|
|
254
|
+
def step_number = number(step)
|
|
255
|
+
def large_step_number = number(large_step)
|
|
256
|
+
def small_step_number = number(small_step)
|
|
257
|
+
def format_json = format.to_json
|
|
258
|
+
|
|
259
|
+
private :root_attributes, :input_attributes, :hidden_attributes, :stepper, :stepper_icon
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module NumberField
|
|
6
|
+
# @label Number Field
|
|
7
|
+
class Preview < Poetry::Core::Preview::Base
|
|
8
|
+
# @!group Basics
|
|
9
|
+
|
|
10
|
+
def default
|
|
11
|
+
render_component({ name: "quantity", label: "Quantity", value: 5, min: 0, max: 100 })
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def empty
|
|
15
|
+
render_component({ name: "amount", label: "Amount", placeholder: "0" })
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def decimal_steps
|
|
19
|
+
render_component({ name: "opacity", label: "Opacity", value: 0.5, min: 0, max: 1, step: 0.1 })
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def snapped
|
|
23
|
+
render_component({ name: "duration", label: "Duration", value: 15, min: 0, max: 120, step: 15, snap: true })
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# wheel: opts the focused input into scroll-to-step (off by
|
|
27
|
+
# default - a page-scroll trap otherwise).
|
|
28
|
+
def wheel_stepping
|
|
29
|
+
render_component({ name: "zoom", label: "Zoom", value: 100, min: 25, max: 400, step: 25, wheel: true })
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @!endgroup
|
|
33
|
+
|
|
34
|
+
# @!group Formatted
|
|
35
|
+
|
|
36
|
+
def currency
|
|
37
|
+
render_component({ name: "price", label: "Price", value: 1234.5, min: 0, step: 0.5,
|
|
38
|
+
format: { style: "currency", currency: "USD" }, locale: "en-US" })
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def percent
|
|
42
|
+
render_component({ name: "ratio", label: "Ratio", value: 0.25, min: 0, max: 1, step: 0.05,
|
|
43
|
+
format: { style: "percent" }, locale: "en-US" })
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @!endgroup
|
|
47
|
+
|
|
48
|
+
# @!group States
|
|
49
|
+
|
|
50
|
+
def disabled
|
|
51
|
+
render_component({ name: "locked", label: "Locked quantity", value: 42, disabled: true })
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def invalid
|
|
55
|
+
render_component({ name: "faulty", label: "Faulty quantity", value: 999, invalid: true })
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def readonly
|
|
59
|
+
render_component({ name: "fixed", label: "Fixed quantity", value: 7, readonly: true })
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @!endgroup
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module NumberField
|
|
6
|
+
# Deliberately near-empty (the composition decision): the
|
|
7
|
+
# group wears InputGroup's chrome, the control wears Input's, the
|
|
8
|
+
# steppers wear Button's - zero new theme CSS. The root only stacks.
|
|
9
|
+
class Style < Poetry::Core::Style
|
|
10
|
+
base "flex w-full flex-col"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<%= content_tag(:nav, **root_attributes.to_attributes) do %>
|
|
2
|
+
<ul data-slot="pagination-content" class="<%= css(:content) %>">
|
|
3
|
+
<% if show_edges? %>
|
|
4
|
+
<li data-slot="pagination-item">
|
|
5
|
+
<%= render Poetry::Ui::Button::Component.new(**previous_options) do |button| %>
|
|
6
|
+
<% if icon_edges? %>
|
|
7
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :"chevron-left", class: "cn-rtl-flip") %>
|
|
8
|
+
<% else %>
|
|
9
|
+
<% button.with_leading { render Poetry::Ui::Icon::Component.new(name: :"chevron-left", class: "cn-rtl-flip") } %>
|
|
10
|
+
<span class="<%= css(:label) %>"><%= previous_label %></span>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
</li>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% if pages %><% items.each do |item| %>
|
|
16
|
+
<li data-slot="pagination-item">
|
|
17
|
+
<% if item == :gap %>
|
|
18
|
+
<span aria-hidden="true" data-slot="pagination-ellipsis" class="<%= css(:ellipsis) %>">
|
|
19
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :ellipsis) %>
|
|
20
|
+
<span class="sr-only">More pages</span>
|
|
21
|
+
</span>
|
|
22
|
+
<% else %>
|
|
23
|
+
<%= render(Poetry::Ui::Button::Component.new(**page_options(item))) { item.to_s } %>
|
|
24
|
+
<% end %>
|
|
25
|
+
</li>
|
|
26
|
+
<% end %><% end %>
|
|
27
|
+
<% if show_edges? %>
|
|
28
|
+
<li data-slot="pagination-item">
|
|
29
|
+
<%= render Poetry::Ui::Button::Component.new(**next_options) do |button| %>
|
|
30
|
+
<% if icon_edges? %>
|
|
31
|
+
<%= render Poetry::Ui::Icon::Component.new(name: :"chevron-right", class: "cn-rtl-flip") %>
|
|
32
|
+
<% else %>
|
|
33
|
+
<% button.with_trailing { render Poetry::Ui::Icon::Component.new(name: :"chevron-right", class: "cn-rtl-flip") } %>
|
|
34
|
+
<span class="<%= css(:label) %>"><%= next_label %></span>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% end %>
|
|
37
|
+
</li>
|
|
38
|
+
<% end %>
|
|
39
|
+
</ul>
|
|
40
|
+
<% end %>
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Numbered page navigation.
|
|
6
|
+
module Pagination
|
|
7
|
+
# Numbered page navigation, data-driven: give it current + total
|
|
8
|
+
# and a path: callable (page -> url) and it owns the truncation
|
|
9
|
+
# math instead of making you compose every <li> - first and last
|
|
10
|
+
# always shown, a window of siblings around the current page,
|
|
11
|
+
# ellipses for the gaps. Renders a <nav> landmark of Button-styled
|
|
12
|
+
# links with the current page marked aria-current=page.
|
|
13
|
+
#
|
|
14
|
+
# @example Paginating a product list
|
|
15
|
+
# render Poetry::Ui::Pagination::Component.new(current: 3, total: 12,
|
|
16
|
+
# path: ->(page) { products_path(page: page) })
|
|
17
|
+
class Component < Poetry::Core::Component
|
|
18
|
+
# The closed vocabulary for the current_variant axis - how the
|
|
19
|
+
# current page link renders.
|
|
20
|
+
CURRENT_VARIANTS = %i[outline filled].freeze
|
|
21
|
+
|
|
22
|
+
# The closed vocabulary for the edges axis - the Previous/Next
|
|
23
|
+
# treatment.
|
|
24
|
+
EDGES = %i[labeled icons none].freeze
|
|
25
|
+
|
|
26
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
27
|
+
AGENT_RULES = [
|
|
28
|
+
"poetry_pagination(current:, total:, path:) - never hand-build the <nav>/<ul>/<li> list.",
|
|
29
|
+
"path: is a callable ->(page) { url } (e.g. ->(p) { products_path(page: p) }).",
|
|
30
|
+
"The current page is aria-current=page; current_variant: :outline (the " \
|
|
31
|
+
"default) or :filled (the primary treatment - unambiguous active state); the rest are " \
|
|
32
|
+
"ghost links.",
|
|
33
|
+
"edges: :icons renders chevron-only Previous/Next (the table-footer posture); " \
|
|
34
|
+
":none drops them for a bare page list; pages: false drops the numbers " \
|
|
35
|
+
"(pair with edges: :icons for the compact pager).",
|
|
36
|
+
"Host paginates with kaminari, pagy (v43+), or will_paginate? Run " \
|
|
37
|
+
"bin/rails g poetry:pagination (no argument = detect and install an adapter for " \
|
|
38
|
+
"each loaded gem) and keep calling paginate / poetry_pagy_nav / " \
|
|
39
|
+
"will_paginate(renderer: PoetryLinkRenderer) - never hand-wire poetry_pagination " \
|
|
40
|
+
"around a paginator gem."
|
|
41
|
+
].freeze
|
|
42
|
+
|
|
43
|
+
option :current, :integer, required: true, doc: "The current page number (1-based)."
|
|
44
|
+
option :total, :integer, required: true, doc: "The total page count."
|
|
45
|
+
option :siblings, :integer, default: 1,
|
|
46
|
+
doc: "How many page links flank the current page before gaps elide to ellipses."
|
|
47
|
+
option :edges, :symbol, default: :labeled,
|
|
48
|
+
doc: "The Previous/Next treatment: :labeled (chevron + responsive text), :icons " \
|
|
49
|
+
"(chevron only - table footers), :none (no edge links)."
|
|
50
|
+
option :pages, :boolean, default: true,
|
|
51
|
+
doc: "Set false to drop the numbered links - the compact two-button pager (pair " \
|
|
52
|
+
"with edges: :icons)."
|
|
53
|
+
option :current_variant, :symbol, default: :outline,
|
|
54
|
+
doc: "How the current page link renders: :outline, or :filled for the " \
|
|
55
|
+
"primary Button treatment (an unambiguous active state)."
|
|
56
|
+
option :label, :string, default: "pagination", doc: "The nav landmark's accessible name."
|
|
57
|
+
option :previous_label, :string, default: "Previous",
|
|
58
|
+
doc: "The Previous link's visible text (hidden on narrow viewports)."
|
|
59
|
+
option :next_label, :string, default: "Next", doc: "The Next link's visible text (hidden on narrow viewports)."
|
|
60
|
+
|
|
61
|
+
validates :current_variant, inclusion: { in: CURRENT_VARIANTS }
|
|
62
|
+
validates :edges, inclusion: { in: EDGES }
|
|
63
|
+
|
|
64
|
+
# (pagination-link rides the composed Buttons, so those elements
|
|
65
|
+
# belong to Button's anatomy, not this contract.)
|
|
66
|
+
part "pagination", "The <nav> landmark (role=navigation, aria-label) around the page list"
|
|
67
|
+
part "pagination-content", "The <ul> holding every entry as one horizontal row"
|
|
68
|
+
part "pagination-item", "One <li> per entry - previous/next, a page link, or a gap"
|
|
69
|
+
part "pagination-ellipsis", "The elided-pages marker between windows - aria-hidden with an " \
|
|
70
|
+
"sr-only 'More pages'"
|
|
71
|
+
|
|
72
|
+
# Rejects the empty-nav combination.
|
|
73
|
+
# @api private
|
|
74
|
+
def before_render
|
|
75
|
+
return if pages || edges != :none
|
|
76
|
+
|
|
77
|
+
raise ArgumentError, "pagination with pages: false needs edges (:labeled or :icons) - " \
|
|
78
|
+
"edges: :none would render an empty nav"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @api private
|
|
82
|
+
def show_edges? = edges != :none
|
|
83
|
+
# @api private
|
|
84
|
+
def icon_edges? = edges == :icons
|
|
85
|
+
|
|
86
|
+
# The page sequence with :gap markers where pages are elided. Small
|
|
87
|
+
# ranges show every page; larger ones show first, last, and a window
|
|
88
|
+
# of +/- siblings around current.
|
|
89
|
+
# @api private
|
|
90
|
+
def items
|
|
91
|
+
return (1..total).to_a if total <= 5 + (siblings * 2)
|
|
92
|
+
|
|
93
|
+
window = ((current - siblings)..(current + siblings)).select { |page| page > 1 && page < total }
|
|
94
|
+
with_gaps([1, *window, total])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @api private
|
|
98
|
+
def current?(page) = page == current
|
|
99
|
+
# @api private
|
|
100
|
+
def path_for(page) = @path.call(page)
|
|
101
|
+
|
|
102
|
+
# Ghost for other pages; the current page renders per
|
|
103
|
+
# current_variant (:outline, or :filled for the primary Button).
|
|
104
|
+
# @api private
|
|
105
|
+
def page_variant(page)
|
|
106
|
+
return :ghost unless current?(page)
|
|
107
|
+
|
|
108
|
+
current_variant == :filled ? :default : :outline
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# A numbered page link: aria-current for the current page, ghost
|
|
112
|
+
# otherwise; icon-sized. data-slot + data-active are the restyle hooks.
|
|
113
|
+
# @api private
|
|
114
|
+
def page_options(page)
|
|
115
|
+
{
|
|
116
|
+
tag: :a, href: path_for(page), size: :icon,
|
|
117
|
+
# A descriptive accessible name that still contains the visible
|
|
118
|
+
# number (WCAG label-in-name); the icon-sized Button requires it.
|
|
119
|
+
label: "Go to page #{page}",
|
|
120
|
+
variant: page_variant(page),
|
|
121
|
+
"aria-current": current?(page) ? "page" : nil,
|
|
122
|
+
data: { slot: "pagination-link", active: current?(page) }
|
|
123
|
+
}.compact
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Prev/Next: default-sized ghost links with the edge padding tweak;
|
|
127
|
+
# disabled (aria-disabled, no navigation) at the boundary.
|
|
128
|
+
# @api private
|
|
129
|
+
def edge_options(page, aria_label, padding)
|
|
130
|
+
options = {
|
|
131
|
+
tag: :a, href: path_for(page), variant: :ghost,
|
|
132
|
+
disabled: page < 1 || page > total,
|
|
133
|
+
data: { slot: "pagination-link" }
|
|
134
|
+
}
|
|
135
|
+
if icon_edges?
|
|
136
|
+
# Icon-sized Buttons take label: (the accessible-name contract).
|
|
137
|
+
options[:size] = :icon
|
|
138
|
+
options[:label] = aria_label
|
|
139
|
+
else
|
|
140
|
+
options[:size] = :default
|
|
141
|
+
options[:"aria-label"] = aria_label
|
|
142
|
+
options[:class] = padding
|
|
143
|
+
end
|
|
144
|
+
options
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @api private
|
|
148
|
+
def previous_options = edge_options(current - 1, "Go to previous page", css(:edge_previous))
|
|
149
|
+
# @api private
|
|
150
|
+
def next_options = edge_options(current + 1, "Go to next page", css(:edge_next))
|
|
151
|
+
|
|
152
|
+
# @api private
|
|
153
|
+
def root_attributes
|
|
154
|
+
html_attributes.merge_if_not_set(
|
|
155
|
+
{ "role" => "navigation", "aria-label" => label, "data-slot" => "pagination" }
|
|
156
|
+
.merge(component_data_attributes)
|
|
157
|
+
)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
|
|
162
|
+
# path: is passed as a keyword but held as a callable, not an option
|
|
163
|
+
# (options are typed data; a proc is behavior).
|
|
164
|
+
def initialize(path:, **)
|
|
165
|
+
super(**)
|
|
166
|
+
@path = path
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def with_gaps(pages)
|
|
170
|
+
pages.each_with_object([]) do |page, sequence|
|
|
171
|
+
previous = sequence.reject { |item| item == :gap }.last
|
|
172
|
+
sequence << :gap if previous && page - previous > 1
|
|
173
|
+
sequence << page
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private :show_edges?, :icon_edges?, :current?, :path_for, :page_variant, :page_options, :edge_options
|
|
178
|
+
private :previous_options, :next_options, :root_attributes
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Pagination
|
|
6
|
+
# The Pagination preview: a middle page of a long range (both ellipses
|
|
7
|
+
# show), a short range (every page, no truncation), and the first page
|
|
8
|
+
# (Previous disabled).
|
|
9
|
+
class Preview < Poetry::Core::Preview::Base
|
|
10
|
+
PATH = ->(page) { "?page=#{page}" }
|
|
11
|
+
|
|
12
|
+
def default
|
|
13
|
+
render_component(current: 4, total: 10, path: PATH)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def long_range_both_ellipses
|
|
17
|
+
render_component(current: 8, total: 20, path: PATH)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def short_range_no_truncation
|
|
21
|
+
render_component(current: 2, total: 4, path: PATH)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def first_page
|
|
25
|
+
render_component(current: 1, total: 10, path: PATH)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The filled current-page treatment: the primary
|
|
29
|
+
# Button as the active marker - the data-index block's choice.
|
|
30
|
+
def filled_current
|
|
31
|
+
render_component(current: 4, total: 10, current_variant: :filled, path: PATH)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# edges: :none - the bare page list (upstream pagination-simple).
|
|
35
|
+
def simple_numbers_only
|
|
36
|
+
render_component(current: 2, total: 5, edges: :none, path: PATH)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The compact two-button pager (upstream pagination-icons-only):
|
|
40
|
+
# chevron-only edges, no numbers.
|
|
41
|
+
def icons_only
|
|
42
|
+
render_component(current: 3, total: 10, edges: :icons, pages: false, path: PATH)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Pagination
|
|
6
|
+
# Re-expressed through the cn-* theme layer. The page links
|
|
7
|
+
# reuse Button styling; the nav root and the responsive label pair
|
|
8
|
+
# (hidden sm:block - a split-side responsive pair, kept together
|
|
9
|
+
# inline) stay utility-only.
|
|
10
|
+
class Style < Poetry::Core::Style
|
|
11
|
+
base "mx-auto flex w-full justify-center"
|
|
12
|
+
|
|
13
|
+
element :content, "cn-pagination-content flex items-center"
|
|
14
|
+
element :ellipsis, "cn-pagination-ellipsis flex items-center justify-center"
|
|
15
|
+
# The label span on prev/next: hidden below sm (icon-only on mobile).
|
|
16
|
+
element :label, "hidden sm:block"
|
|
17
|
+
# The edge-padding trim (upstream parity): the chevron side pulls
|
|
18
|
+
# in so the glyph's optical whitespace doesn't read as extra
|
|
19
|
+
# hover-box padding. Lives HERE because safelists harvest Style
|
|
20
|
+
# dictionaries and templates - a class string inside component.rb
|
|
21
|
+
# never compiles in any host.
|
|
22
|
+
element :edge_previous, "cn-pagination-previous"
|
|
23
|
+
element :edge_next, "cn-pagination-next"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<%= anchor %>
|
|
3
|
+
<%= trigger %>
|
|
4
|
+
<%= content_tag(:div, **Poetry::Core::HTML::Attributes.new(content_attributes).to_attributes) do %>
|
|
5
|
+
<% if title? || description? %>
|
|
6
|
+
<div data-slot="popover-header" class="<%= css(:header) %>">
|
|
7
|
+
<% if title? %>
|
|
8
|
+
<div data-slot="popover-title" id="<%= title_id %>" class="<%= css(:title) %>"><%= title %></div>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% if description? %>
|
|
11
|
+
<p data-slot="popover-description" id="<%= description_id %>" class="<%= css(:description) %>"><%= description %></p>
|
|
12
|
+
<% end %>
|
|
13
|
+
</div>
|
|
14
|
+
<% end %>
|
|
15
|
+
<%= content %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|