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,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Sidebar
|
|
6
|
+
# Style dictionary for the Sidebar family. The collapse / rail /
|
|
7
|
+
# inset geometry chains (width vars, offcanvas math, icon-mode
|
|
8
|
+
# size! pads, peer-size action tops) stay ENTIRELY inline - the
|
|
9
|
+
# machinery a swapped theme must never break; surfaces, tints, and
|
|
10
|
+
# type ride the theme. The mobile <dialog> keeps m-0 and the side
|
|
11
|
+
# margins BOTH inline so the class merger keeps collapsing them.
|
|
12
|
+
class Style < Poetry::Core::Style
|
|
13
|
+
base ""
|
|
14
|
+
|
|
15
|
+
# The provider wrapper carries the width custom properties.
|
|
16
|
+
# group/sidebar-wrapper has an in-repo consumer: the app-shell
|
|
17
|
+
# block's topbar answers the collapsed state
|
|
18
|
+
# (group-has-data-[collapsible=icon]/sidebar-wrapper)
|
|
19
|
+
# - the upstream site-header pattern. Two upstream markers stay
|
|
20
|
+
# dropped: group/menu-button's upstream consumer is a collapsible
|
|
21
|
+
# menu-button composition poetry does not ship yet, and
|
|
22
|
+
# group/menu-sub-item has no consumer anywhere in the current
|
|
23
|
+
# upstream tree.
|
|
24
|
+
element :wrapper, "group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar"
|
|
25
|
+
|
|
26
|
+
# The peer group (the desktop shell; below md the mobile <dialog>
|
|
27
|
+
# takes over).
|
|
28
|
+
element :peer, "group peer hidden text-sidebar-foreground md:block"
|
|
29
|
+
|
|
30
|
+
# The mobile sheet: open:flex not flex (the Dialog lesson).
|
|
31
|
+
element :mobile, "cn-sidebar-mobile relative m-0 open:flex h-full max-h-none " \
|
|
32
|
+
"w-(--sidebar-width) max-w-none flex-col md:hidden"
|
|
33
|
+
element :mobile_left, "cn-sidebar-mobile-left mr-auto"
|
|
34
|
+
element :mobile_right, "cn-sidebar-mobile-right ml-auto"
|
|
35
|
+
element :mobile_inner, "flex h-full w-full flex-col"
|
|
36
|
+
|
|
37
|
+
# The mobile side's edge classes for the <dialog>.
|
|
38
|
+
def self.mobile_side(value)
|
|
39
|
+
resolver.render(:"mobile_#{value}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# The desktop gap that pushes the inset over.
|
|
43
|
+
element :gap, "cn-sidebar-gap relative w-(--sidebar-width) bg-transparent " \
|
|
44
|
+
"group-data-[collapsible=offcanvas]:w-0 group-data-[side=right]:rotate-180 " \
|
|
45
|
+
"group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
|
|
46
|
+
element :gap_inset, "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
|
|
47
|
+
|
|
48
|
+
element :container,
|
|
49
|
+
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] " \
|
|
50
|
+
"duration-200 ease-linear data-[side=left]:left-0 " \
|
|
51
|
+
"data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] " \
|
|
52
|
+
"data-[side=right]:right-0 " \
|
|
53
|
+
"data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] " \
|
|
54
|
+
"md:flex group-data-[collapsible=icon]:w-(--sidebar-width-icon) " \
|
|
55
|
+
"group-data-[side=left]:border-r group-data-[side=right]:border-l"
|
|
56
|
+
element :container_inset,
|
|
57
|
+
"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
|
|
58
|
+
|
|
59
|
+
element :inner, "cn-sidebar-inner flex size-full flex-col"
|
|
60
|
+
|
|
61
|
+
element :inset, "cn-sidebar-inset relative flex w-full flex-1 flex-col"
|
|
62
|
+
|
|
63
|
+
# The rail (desktop-only click strip).
|
|
64
|
+
element :rail,
|
|
65
|
+
"cn-sidebar-rail absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear " \
|
|
66
|
+
"group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 " \
|
|
67
|
+
"after:start-1/2 after:w-[2px] sm:flex " \
|
|
68
|
+
"group-data-[collapsible=offcanvas]:translate-x-0 " \
|
|
69
|
+
"group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar"
|
|
70
|
+
|
|
71
|
+
element :header, "cn-sidebar-header flex flex-col"
|
|
72
|
+
element :footer, "cn-sidebar-footer flex flex-col"
|
|
73
|
+
element :separator, "cn-sidebar-separator w-auto"
|
|
74
|
+
element :content, "cn-sidebar-content no-scrollbar flex min-h-0 flex-1 flex-col overflow-auto " \
|
|
75
|
+
"group-data-[collapsible=icon]:overflow-hidden"
|
|
76
|
+
|
|
77
|
+
element :group, "cn-sidebar-group relative flex w-full min-w-0 flex-col"
|
|
78
|
+
element :group_label, "cn-sidebar-group-label flex shrink-0 items-center outline-hidden " \
|
|
79
|
+
"transition-[margin,opacity] duration-200 ease-linear " \
|
|
80
|
+
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 " \
|
|
81
|
+
"[&>svg]:shrink-0"
|
|
82
|
+
element :group_content, "cn-sidebar-group-content w-full"
|
|
83
|
+
|
|
84
|
+
element :menu, "cn-sidebar-menu flex w-full min-w-0 flex-col"
|
|
85
|
+
element :menu_item, "group/menu-item relative"
|
|
86
|
+
element :menu_button,
|
|
87
|
+
"cn-sidebar-menu-button peer/menu-button flex w-full items-center overflow-hidden " \
|
|
88
|
+
"text-left outline-hidden transition-[width,height,padding] " \
|
|
89
|
+
"group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! " \
|
|
90
|
+
"disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none " \
|
|
91
|
+
"aria-disabled:opacity-50 [&_svg]:shrink-0 [&>span:last-child]:truncate " \
|
|
92
|
+
"[&_svg]:size-4 group/menu-button"
|
|
93
|
+
element :menu_button_default, "cn-sidebar-menu-button-size-default"
|
|
94
|
+
|
|
95
|
+
# The item-corner action + badge - positions and
|
|
96
|
+
# reveal machinery inline, tints/type themed.
|
|
97
|
+
element :menu_action,
|
|
98
|
+
"cn-sidebar-menu-action absolute top-1.5 right-1 flex aspect-square items-center " \
|
|
99
|
+
"justify-center outline-hidden transition-transform " \
|
|
100
|
+
"group-data-[collapsible=icon]:hidden " \
|
|
101
|
+
"peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 " \
|
|
102
|
+
"peer-data-[size=sm]/menu-button:top-1 after:absolute after:-inset-2 " \
|
|
103
|
+
"md:after:hidden [&>svg]:shrink-0"
|
|
104
|
+
element :menu_action_hover,
|
|
105
|
+
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 " \
|
|
106
|
+
"peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 " \
|
|
107
|
+
"md:opacity-0"
|
|
108
|
+
# Dictionary-held surfaces so the safelist harvests the classes
|
|
109
|
+
# (helper strings are invisible to it).
|
|
110
|
+
element :group_action_button, "cn-sidebar-group-action"
|
|
111
|
+
element :input_control, "cn-sidebar-input"
|
|
112
|
+
element :menu_skeleton, "cn-sidebar-menu-skeleton flex items-center"
|
|
113
|
+
element :menu_skeleton_icon, "cn-sidebar-menu-skeleton-icon"
|
|
114
|
+
element :menu_skeleton_text, "cn-sidebar-menu-skeleton-text max-w-(--skeleton-width) flex-1"
|
|
115
|
+
|
|
116
|
+
element :menu_badge,
|
|
117
|
+
"cn-sidebar-menu-badge pointer-events-none absolute right-1 flex items-center " \
|
|
118
|
+
"justify-center select-none group-data-[collapsible=icon]:hidden " \
|
|
119
|
+
"peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 " \
|
|
120
|
+
"peer-data-[size=sm]/menu-button:top-1 tabular-nums"
|
|
121
|
+
element :menu_button_sm, "cn-sidebar-menu-button-size-sm"
|
|
122
|
+
element :menu_button_lg, "cn-sidebar-menu-button-size-lg group-data-[collapsible=icon]:p-0!"
|
|
123
|
+
|
|
124
|
+
element :menu_sub, "cn-sidebar-menu-sub mx-3.5 flex min-w-0 translate-x-px flex-col " \
|
|
125
|
+
"group-data-[collapsible=icon]:hidden"
|
|
126
|
+
element :menu_sub_item, "relative"
|
|
127
|
+
element :menu_sub_button, "cn-sidebar-menu-sub-button flex min-w-0 -translate-x-px items-center " \
|
|
128
|
+
"overflow-hidden outline-hidden disabled:pointer-events-none " \
|
|
129
|
+
"disabled:opacity-50 aria-disabled:pointer-events-none " \
|
|
130
|
+
"aria-disabled:opacity-50 [&>svg]:shrink-0 [&>span:last-child]:truncate"
|
|
131
|
+
|
|
132
|
+
# The size-variant classes for a menu button.
|
|
133
|
+
def self.menu_button_size(value)
|
|
134
|
+
css(:"menu_button_#{value}")
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A pulsing placeholder box shown while content loads.
|
|
6
|
+
module Skeleton
|
|
7
|
+
# A pulsing placeholder while content loads. Size it with
|
|
8
|
+
# utility classes (h-4 w-32, size-10 rounded-full, ...); the content
|
|
9
|
+
# block is optional (usually empty - the box IS the placeholder).
|
|
10
|
+
#
|
|
11
|
+
# @example An avatar-and-line placeholder pair
|
|
12
|
+
# render Poetry::Ui::Skeleton::Component.new(class: "size-10 rounded-full")
|
|
13
|
+
# render Poetry::Ui::Skeleton::Component.new(class: "h-4 w-32")
|
|
14
|
+
class Component < Poetry::Core::Component
|
|
15
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
16
|
+
AGENT_RULES = [
|
|
17
|
+
"Skeleton is a loading placeholder - size it with classes (h-4 w-32); it has no content of its own.",
|
|
18
|
+
"Mark the live region that will replace it (aria-busy on the container), not the skeleton."
|
|
19
|
+
].freeze
|
|
20
|
+
|
|
21
|
+
part "skeleton", "The pulsing placeholder box itself - sized entirely by utility classes"
|
|
22
|
+
|
|
23
|
+
# @api private
|
|
24
|
+
def call
|
|
25
|
+
content_tag(:div, content, **root_attributes.to_attributes)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @api private
|
|
29
|
+
def root_attributes
|
|
30
|
+
html_attributes.merge_if_not_set(
|
|
31
|
+
{ "data-slot" => "skeleton" }.merge(component_data_attributes)
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private :root_attributes
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Skeleton
|
|
6
|
+
# The Skeleton preview: placeholders in the common shapes.
|
|
7
|
+
class Preview < Poetry::Core::Preview::Base
|
|
8
|
+
def line
|
|
9
|
+
render_component(class: "h-4 w-48")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def avatar
|
|
13
|
+
render_component(class: "size-12 rounded-full")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def block
|
|
17
|
+
render_component(class: "h-24 w-full rounded-xl")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Skeleton
|
|
6
|
+
# Style dictionary for the Skeleton family: the pulse is the
|
|
7
|
+
# mechanism (inline), the box treatment is the theme's.
|
|
8
|
+
class Style < Poetry::Core::Style
|
|
9
|
+
base "cn-skeleton animate-pulse"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<%# Track + range ride the geometry vars; each thumb sits in an
|
|
2
|
+
absolutely positioned anchor (Radix's thumb-wrapper span, poetry
|
|
3
|
+
edition) with its hidden input alongside - thumbs and inputs stay
|
|
4
|
+
index-aligned with the value array. %>
|
|
5
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
6
|
+
<%= content_tag(:div, content_tag(:div, nil, **range_attributes), **track_attributes) %>
|
|
7
|
+
<% thumb_values.each_index do |index| %>
|
|
8
|
+
<%= content_tag(:span, **anchor_attributes(index)) do %>
|
|
9
|
+
<%= content_tag(:div, nil, **thumb_attributes(index)) %>
|
|
10
|
+
<%= tag.input(**input_attributes(index)) %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% end %>
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# A draggable numeric value (or range) on a continuous track.
|
|
6
|
+
module Slider
|
|
7
|
+
# A numeric value (or a [low, high] range - two thumbs) picked by
|
|
8
|
+
# dragging along a continuous track. Reach for it when the value is
|
|
9
|
+
# approximate by nature; precise known-number entry belongs in a
|
|
10
|
+
# number input. Every thumb is its own Tab stop, and arrow keys move
|
|
11
|
+
# the focused thumb by step:.
|
|
12
|
+
#
|
|
13
|
+
# The server renders everything the controller would: aria-value*
|
|
14
|
+
# per thumb (range bounds clamped to the neighboring thumb), the
|
|
15
|
+
# --slider-start/--slider-end geometry vars (no first-paint jump),
|
|
16
|
+
# and one hidden <input type=hidden> per thumb - name single,
|
|
17
|
+
# name[] range, which is precisely Rails' array-param convention
|
|
18
|
+
# (params: "50" / ["200", "800"]). Change fires per mutation,
|
|
19
|
+
# commit once per gesture; native input/change fire on COMMIT only.
|
|
20
|
+
#
|
|
21
|
+
# @example
|
|
22
|
+
# render Poetry::Ui::Slider::Component.new(name: "volume", value: 50, label: "Volume")
|
|
23
|
+
class Component < Poetry::Core::Component
|
|
24
|
+
# The closed vocabulary for the axis option.
|
|
25
|
+
ORIENTATIONS = %i[horizontal vertical].freeze
|
|
26
|
+
|
|
27
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
28
|
+
AGENT_RULES = [
|
|
29
|
+
"Use poetry_slider / form.slider - never hand-roll a draggable div.",
|
|
30
|
+
"Every thumb MUST have a distinct accessible name (label: - array of two for ranges). " \
|
|
31
|
+
"ArgumentError otherwise.",
|
|
32
|
+
"Give value_text: whenever the number alone is meaningless ('$200', '80%') - SR users hear " \
|
|
33
|
+
"aria-valuetext.",
|
|
34
|
+
"Range mode: values must be sorted [low, high]; use min_steps_between_thumbs to keep a " \
|
|
35
|
+
"meaningful gap.",
|
|
36
|
+
"Do not use Slider for precise known-number entry (use Input type=number) or in " \
|
|
37
|
+
"no-JS-required forms (native input type=range).",
|
|
38
|
+
"Debounce on poetry:slider:commit, never on :change (change fires every drag frame).",
|
|
39
|
+
"Never transition the thumb/range position with CSS - geometry must track the pointer."
|
|
40
|
+
].freeze
|
|
41
|
+
|
|
42
|
+
# One dedicated controller on purpose: slider keys move VALUES on
|
|
43
|
+
# one focused thumb - value-math no focus-moving primitive covers.
|
|
44
|
+
use_stimulus do
|
|
45
|
+
on :root do
|
|
46
|
+
controller :slider do
|
|
47
|
+
register
|
|
48
|
+
value :min, from: :min_number
|
|
49
|
+
value :max, from: :max_number
|
|
50
|
+
value :step, from: :step_number
|
|
51
|
+
value :value, from: :value_numbers
|
|
52
|
+
value :min_steps_between_thumbs
|
|
53
|
+
value :orientation
|
|
54
|
+
value :inverted
|
|
55
|
+
action :pointerdown, on: :pointerdown
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
on :track do
|
|
59
|
+
controller(:slider) { target :track }
|
|
60
|
+
end
|
|
61
|
+
on :range do
|
|
62
|
+
controller(:slider) { target :range }
|
|
63
|
+
end
|
|
64
|
+
on :thumb do
|
|
65
|
+
controller :slider do
|
|
66
|
+
target :thumb
|
|
67
|
+
action :keydown, on: :keydown
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
# The form bridge: hidden inputs submit the server value even
|
|
71
|
+
# when disabled.
|
|
72
|
+
on :input do
|
|
73
|
+
controller(:slider) { target :input }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
option :name, :string, required: true,
|
|
78
|
+
doc: "Form name; single thumb -> name; range -> name + \"[]\" per input (the Rails " \
|
|
79
|
+
"array-param convention)."
|
|
80
|
+
option :value, ActiveModel::Type::Value.new, doc: "Single-thumb value. ArgumentError if given with values:."
|
|
81
|
+
option :values, ActiveModel::Type::Value.new,
|
|
82
|
+
doc: "Range mode: [low, high] -> two thumbs, sorted. ArgumentError if given with value:, unsorted, or " \
|
|
83
|
+
"length != 2."
|
|
84
|
+
option :min, :float, default: 0.0, doc: "The track's lower bound."
|
|
85
|
+
option :max, :float, default: 100.0, doc: "The track's upper bound; must exceed min:."
|
|
86
|
+
option :step, :float, default: 1.0,
|
|
87
|
+
doc: "Snap increment; decimal steps supported (precision-aware rounding lives in the " \
|
|
88
|
+
"controller's math core)."
|
|
89
|
+
option :min_steps_between_thumbs, :integer, default: 0,
|
|
90
|
+
doc: "Range-mode minimum gap in STEPS: high - low >= n*step; " \
|
|
91
|
+
"thumbs can never cross."
|
|
92
|
+
option :orientation, :symbol, default: :horizontal, doc: "The track axis."
|
|
93
|
+
option :inverted, :boolean, default: false,
|
|
94
|
+
doc: "Flips the value direction along the axis; composes with RTL (both = ltr " \
|
|
95
|
+
"math)."
|
|
96
|
+
option :disabled, :boolean, default: false,
|
|
97
|
+
doc: "Renders the control inert; the hidden inputs still submit the server value."
|
|
98
|
+
option :label, ActiveModel::Type::Value.new,
|
|
99
|
+
doc: "Per-thumb accessible names -> aria-label; range REQUIRES two. Alternatively labelled_by " \
|
|
100
|
+
"(external wiring). Enforced."
|
|
101
|
+
option :labelled_by, :string,
|
|
102
|
+
doc: "aria-labelledby for the thumb(s) - the Field-wrapped single slider derives its name from the " \
|
|
103
|
+
"field label this way."
|
|
104
|
+
option :value_text, ActiveModel::Type::Value.new,
|
|
105
|
+
doc: "aria-valuetext formatter: a proc (v -> \"$200\") or an i18n key " \
|
|
106
|
+
"with %{value}; optional - falls back to the bare number." # rubocop:disable Style/FormatStringToken
|
|
107
|
+
option :described_by, :string, doc: "Field hint/error wiring -> aria-describedby on EACH thumb."
|
|
108
|
+
|
|
109
|
+
validates :orientation, inclusion: { in: ORIENTATIONS }
|
|
110
|
+
|
|
111
|
+
part "slider", "Root - the controller, the geometry vars, and pointer capture ride here",
|
|
112
|
+
states: {
|
|
113
|
+
"data-orientation" => { condition: "always - the axis",
|
|
114
|
+
values: ORIENTATIONS.map(&:to_s) },
|
|
115
|
+
"data-disabled" => "disabled: is set (the control is inert; the hidden inputs " \
|
|
116
|
+
"still submit)",
|
|
117
|
+
"data-dragging" => "a pointer drag is in flight (the controller sets it for the " \
|
|
118
|
+
"gesture; never rendered server-side)"
|
|
119
|
+
},
|
|
120
|
+
vars: {
|
|
121
|
+
"--slider-start" => "the filled range's start edge as a percentage - " \
|
|
122
|
+
"server-rendered (no first-paint jump), rewritten by the " \
|
|
123
|
+
"controller on every move",
|
|
124
|
+
"--slider-end" => "the filled range's end edge as a percentage (the single-thumb " \
|
|
125
|
+
"value rides here)"
|
|
126
|
+
}
|
|
127
|
+
part "slider-track", "The full-length rail the range paints over",
|
|
128
|
+
states: {
|
|
129
|
+
"data-orientation" => { condition: "always - mirrors the root",
|
|
130
|
+
values: ORIENTATIONS.map(&:to_s) }
|
|
131
|
+
}
|
|
132
|
+
part "slider-range", "The filled span between --slider-start and --slider-end",
|
|
133
|
+
states: {
|
|
134
|
+
"data-orientation" => { condition: "always - mirrors the root",
|
|
135
|
+
values: ORIENTATIONS.map(&:to_s) }
|
|
136
|
+
}
|
|
137
|
+
part "slider-anchor", "Absolutely positioned thumb wrapper (one per thumb, with its " \
|
|
138
|
+
"hidden input alongside) seated on the geometry vars",
|
|
139
|
+
states: {
|
|
140
|
+
"data-orientation" => { condition: "always - mirrors the root",
|
|
141
|
+
values: ORIENTATIONS.map(&:to_s) }
|
|
142
|
+
}
|
|
143
|
+
part "slider-thumb", "The role=slider handle - its own Tab stop, carrying the " \
|
|
144
|
+
"aria-value* surface (bounds neighbor-clamped in range mode)",
|
|
145
|
+
states: {
|
|
146
|
+
"data-orientation" => { condition: "always - mirrors the root",
|
|
147
|
+
values: ORIENTATIONS.map(&:to_s) },
|
|
148
|
+
"data-disabled" => "disabled: is set (tabindex drops to -1)",
|
|
149
|
+
"data-dragging" => "this thumb is the one being dragged (the controller pairs it " \
|
|
150
|
+
"with the root's)"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# @api private
|
|
154
|
+
def initialize(attributes = {})
|
|
155
|
+
if attributes.values_at(:value, "value").any? && attributes.values_at(:values, "values").any?
|
|
156
|
+
raise ArgumentError, "value: is the single-thumb API and values: the range API - pass one"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
super
|
|
160
|
+
|
|
161
|
+
validate_numbers!
|
|
162
|
+
validate_labels!
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Always an array internally: [v] single, [low, high] range.
|
|
166
|
+
# @api private
|
|
167
|
+
def thumb_values
|
|
168
|
+
@thumb_values ||= if values.present?
|
|
169
|
+
Array(values).map { |item| numeric(item, "values") }
|
|
170
|
+
else
|
|
171
|
+
# No value at all -> ONE thumb at min.
|
|
172
|
+
[numeric(value.presence || min, "value")]
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# @api private
|
|
177
|
+
def range?
|
|
178
|
+
thumb_values.length > 1
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# @api private
|
|
182
|
+
def input_name
|
|
183
|
+
range? ? "#{name}[]" : name
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# @api private
|
|
187
|
+
def control_id
|
|
188
|
+
@control_id ||= poetry_instance_id("poetry-slider")
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# @api private
|
|
192
|
+
def thumb_id(index)
|
|
193
|
+
"#{control_id}-thumb-#{index}"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# The thumb's EFFECTIVE bounds (the high thumb's min is the low
|
|
197
|
+
# thumb's value + the gap) - server-rendered, then rewritten by
|
|
198
|
+
# the controller on every neighbor move.
|
|
199
|
+
# @api private
|
|
200
|
+
def thumb_min(index)
|
|
201
|
+
index.zero? ? number(min) : number(thumb_values[index - 1] + gap)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# @api private
|
|
205
|
+
def thumb_max(index)
|
|
206
|
+
index == thumb_values.length - 1 ? number(max) : number(thumb_values[index + 1] - gap)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# @api private
|
|
210
|
+
def thumb_label(index)
|
|
211
|
+
Array(label)[index]
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @api private
|
|
215
|
+
def thumb_text(index)
|
|
216
|
+
return unless value_text.present?
|
|
217
|
+
|
|
218
|
+
value = number(thumb_values[index])
|
|
219
|
+
value_text.respond_to?(:call) ? value_text.call(value) : I18n.t(value_text, value: value)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# @api private
|
|
223
|
+
def root_attributes
|
|
224
|
+
attrs = {
|
|
225
|
+
"data-slot" => "slider", "id" => control_id,
|
|
226
|
+
"data-orientation" => orientation, "style" => geometry_style
|
|
227
|
+
}
|
|
228
|
+
attrs["data-disabled"] = "" if disabled
|
|
229
|
+
html_attributes.merge_if_not_set(
|
|
230
|
+
attrs.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
|
|
231
|
+
)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# @api private
|
|
235
|
+
def track_attributes
|
|
236
|
+
{ class: css(:track), "data-slot" => "slider-track", "data-orientation" => orientation }
|
|
237
|
+
.merge(stimulus_attributes_for(:track))
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# @api private
|
|
241
|
+
def range_attributes
|
|
242
|
+
{ class: css(:range), "data-slot" => "slider-range", "data-orientation" => orientation }
|
|
243
|
+
.merge(stimulus_attributes_for(:range))
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# @api private
|
|
247
|
+
def anchor_attributes(index)
|
|
248
|
+
anchor = if range? && index.zero? then :anchor_start
|
|
249
|
+
elsif index == thumb_values.length - 1 then :anchor_end
|
|
250
|
+
else :anchor_mid
|
|
251
|
+
end
|
|
252
|
+
attrs = { class: classnames(css(:anchor), css(anchor)), "data-slot" => "slider-anchor",
|
|
253
|
+
"data-orientation" => orientation }
|
|
254
|
+
attrs[:style] = "--slider-mid: #{number(percent(thumb_values[index]).to_f)}%;" if anchor == :anchor_mid
|
|
255
|
+
attrs
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# @api private
|
|
259
|
+
def thumb_attributes(index)
|
|
260
|
+
attrs = {
|
|
261
|
+
role: "slider", id: thumb_id(index), class: css(:thumb),
|
|
262
|
+
tabindex: disabled ? "-1" : "0",
|
|
263
|
+
"data-slot" => "slider-thumb", "data-orientation" => orientation,
|
|
264
|
+
"aria-valuemin" => thumb_min(index), "aria-valuemax" => thumb_max(index),
|
|
265
|
+
"aria-valuenow" => number(thumb_values[index]),
|
|
266
|
+
"aria-orientation" => orientation
|
|
267
|
+
}
|
|
268
|
+
attrs["aria-valuetext"] = thumb_text(index) if value_text.present?
|
|
269
|
+
attrs["aria-label"] = thumb_label(index) if thumb_label(index).present?
|
|
270
|
+
attrs["aria-labelledby"] = labelled_by if labelled_by.present?
|
|
271
|
+
attrs["aria-describedby"] = described_by if described_by.present?
|
|
272
|
+
attrs["data-disabled"] = "" if disabled
|
|
273
|
+
attrs.merge(stimulus_attributes_for(:thumb))
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# The form bridge: hidden inputs submit the server value even when
|
|
277
|
+
# disabled (a slider always HAS a value; the control is inert, the
|
|
278
|
+
# datum is not) - contrast native disabled fields.
|
|
279
|
+
# @api private
|
|
280
|
+
def input_attributes(index)
|
|
281
|
+
{ type: "hidden", name: input_name, value: number(thumb_values[index]) }
|
|
282
|
+
.merge(stimulus_attributes_for(:input))
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Trailing-zero-free rendering: 50.0 -> "50", 0.5 -> "0.5" (aria
|
|
286
|
+
# announcements and params never carry float noise).
|
|
287
|
+
# @api private
|
|
288
|
+
def number(value)
|
|
289
|
+
value == value.to_i ? value.to_i : value
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
private
|
|
293
|
+
|
|
294
|
+
def gap
|
|
295
|
+
min_steps_between_thumbs * step
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def percent(value)
|
|
299
|
+
span = max - min
|
|
300
|
+
return 0 if span <= 0
|
|
301
|
+
|
|
302
|
+
((value - min) / span * 100).round(4)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def geometry_style
|
|
306
|
+
start = range? ? percent(thumb_values.first) : 0
|
|
307
|
+
"--slider-start: #{number(start.to_f)}%; --slider-end: #{number(percent(thumb_values.last).to_f)}%;"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def numeric(value, option_name)
|
|
311
|
+
Float(value)
|
|
312
|
+
rescue ArgumentError, TypeError
|
|
313
|
+
raise ArgumentError, "Slider #{option_name}: must be numeric - got #{value.inspect}"
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def validate_numbers!
|
|
317
|
+
raise ArgumentError, "Slider max: must be greater than min:" unless max > min
|
|
318
|
+
raise ArgumentError, "Slider step: must be positive" unless step.positive?
|
|
319
|
+
|
|
320
|
+
if values.present?
|
|
321
|
+
list = thumb_values
|
|
322
|
+
raise ArgumentError, "Slider values: takes two or more thumbs" unless list.length >= 2
|
|
323
|
+
raise ArgumentError, "Slider values: must be sorted ascending" unless list.each_cons(2).all? do |a, b|
|
|
324
|
+
a <= b
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
return if thumb_values.all? { |item| item.between?(min, max) }
|
|
328
|
+
|
|
329
|
+
raise ArgumentError, "Slider value(s) #{thumb_values.inspect} outside #{number(min)}..#{number(max)}"
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# Per-thumb accessible names, ENFORCED: a range announcing
|
|
333
|
+
# "slider, 200" twice is useless to AT.
|
|
334
|
+
def validate_labels!
|
|
335
|
+
if range?
|
|
336
|
+
labels = Array(label)
|
|
337
|
+
return if labels.length == thumb_values.length && labels.all?(&:present?)
|
|
338
|
+
|
|
339
|
+
raise ArgumentError, "a multi-thumb Slider requires one distinct name per thumb - " \
|
|
340
|
+
"label: ['Minimum price', 'Maximum price']"
|
|
341
|
+
else
|
|
342
|
+
return if Array(label).first.present? || labelled_by.present?
|
|
343
|
+
|
|
344
|
+
raise ArgumentError, "Slider requires an accessible name - label: (aria-label) or " \
|
|
345
|
+
"labelled_by: (aria-labelledby)"
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def min_number = number(min)
|
|
350
|
+
def max_number = number(max)
|
|
351
|
+
def step_number = number(step)
|
|
352
|
+
def value_numbers = thumb_values.map { |item| number(item) }
|
|
353
|
+
|
|
354
|
+
private :thumb_values, :range?, :input_name, :control_id, :thumb_id, :thumb_min, :thumb_max, :thumb_label
|
|
355
|
+
private :thumb_text, :root_attributes, :track_attributes, :range_attributes, :anchor_attributes
|
|
356
|
+
private :thumb_attributes, :input_attributes, :number
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Slider
|
|
6
|
+
# The Slider preview matrix: modes (single, range, range+gap) x
|
|
7
|
+
# orientation x states, the slider-demo port, and the edge
|
|
8
|
+
# geometries (pinned at min/max, decimal step, inverted).
|
|
9
|
+
class Preview < Poetry::Core::Preview::Base
|
|
10
|
+
# @!group Modes
|
|
11
|
+
|
|
12
|
+
# The slider-demo port: defaultValue [50], max 100, step 1,
|
|
13
|
+
# constrained width.
|
|
14
|
+
def default
|
|
15
|
+
render_component(name: "progress", value: 50, label: "Progress", class: "w-[60%]")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Range mode (field-slider parity): two thumbs, name[] array
|
|
19
|
+
# params, TWO distinct thumb names (enforced).
|
|
20
|
+
def range
|
|
21
|
+
render_component(name: "price_range", values: [200, 800], min: 0, max: 1000, step: 10,
|
|
22
|
+
label: ["Minimum price", "Maximum price"],
|
|
23
|
+
value_text: ->(value) { "$#{value}" })
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# min_steps_between_thumbs: the thumbs can never close under
|
|
27
|
+
# 10 steps - Home/End clamp at the neighbor's gap.
|
|
28
|
+
def range_with_gap
|
|
29
|
+
render_component(name: "hours", values: [9, 17], min: 0, max: 24,
|
|
30
|
+
min_steps_between_thumbs: 4,
|
|
31
|
+
label: %w[Start End])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @!endgroup
|
|
35
|
+
|
|
36
|
+
# @!group Geometry
|
|
37
|
+
|
|
38
|
+
# Vertical grows BOTTOM-up (APG); ArrowUp still increments.
|
|
39
|
+
def vertical
|
|
40
|
+
render_component(name: "volume", value: 65, orientation: :vertical, label: "Volume",
|
|
41
|
+
value_text: ->(value) { "#{value}%" }, class: "h-48")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# inverted: the value direction flips along the axis (increment
|
|
45
|
+
# keys decrement); composes with RTL (both = ltr math).
|
|
46
|
+
def inverted
|
|
47
|
+
render_component(name: "depth", value: 30, inverted: true, label: "Depth")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Decimal step: the controller's precision-aware rounding keeps
|
|
51
|
+
# 0.1 grids exact (0.3, never 0.30000000000000004).
|
|
52
|
+
def decimal_step
|
|
53
|
+
render_component(name: "opacity", value: 0.5, min: 0, max: 1, step: 0.1, label: "Opacity")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Pinned at the edges: range renders 0%/100% deterministically.
|
|
57
|
+
def at_the_edges
|
|
58
|
+
render_component(name: "bounds", values: [0, 100], label: %w[Low High])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @!endgroup
|
|
62
|
+
|
|
63
|
+
# @!group States
|
|
64
|
+
|
|
65
|
+
def disabled
|
|
66
|
+
render_component(name: "volume", value: 40, disabled: true, label: "Volume")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @!endgroup
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|