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,366 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
|
|
5
|
+
module Poetry
|
|
6
|
+
module Ui
|
|
7
|
+
# Server-rendered month-grid date pickers.
|
|
8
|
+
module Calendar
|
|
9
|
+
# A month grid for picking a date, computed server-side with Ruby
|
|
10
|
+
# date math: the initial month renders correctly with no JS, and
|
|
11
|
+
# the controller adds navigation and selection on top. Selection is
|
|
12
|
+
# a real form value - name: posts the chosen date as an ISO string
|
|
13
|
+
# in a hidden input (range mode posts name[start] and name[end]).
|
|
14
|
+
# A bare Calendar is the always-visible grid; DatePicker wraps it
|
|
15
|
+
# in a popover behind a text field.
|
|
16
|
+
#
|
|
17
|
+
# @example A form-posting date pick
|
|
18
|
+
# render Poetry::Ui::Calendar::Component.new(name: "event[date]", selected: "2026-07-04")
|
|
19
|
+
class Component < Poetry::Core::Component
|
|
20
|
+
# The date-valued keywords, parsed to Date (or nil) for the template.
|
|
21
|
+
# @api private
|
|
22
|
+
attr_reader :selected, :today, :min, :max, :range_start, :range_end
|
|
23
|
+
|
|
24
|
+
# The closed vocabulary for the mode axis.
|
|
25
|
+
MODES = %i[single range].freeze
|
|
26
|
+
# The closed vocabulary for the caption_layout axis.
|
|
27
|
+
CAPTION_LAYOUTS = %i[label dropdown].freeze
|
|
28
|
+
|
|
29
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
30
|
+
AGENT_RULES = [
|
|
31
|
+
"name: makes it a form control (the chosen date posts as an ISO string in a hidden input; " \
|
|
32
|
+
"range mode posts name[start] + name[end]).",
|
|
33
|
+
"month:/selected:/today accept a Date or an ISO string; min:/max: bound the selectable range.",
|
|
34
|
+
"mode: :range selects a span - selected: takes a Date..Date Range, [start, end], or " \
|
|
35
|
+
"{start:, end:}; the second click completes, click-before-start swaps, re-click clears.",
|
|
36
|
+
"The grid is server-rendered - it shows a valid month with no JS; the controller adds " \
|
|
37
|
+
"navigation + selection.",
|
|
38
|
+
"For a text-field + popover, use DatePicker (it composes this) - a bare Calendar is the " \
|
|
39
|
+
"always-visible grid.",
|
|
40
|
+
"caption_layout: :dropdown swaps the month label for month + year selects (jump " \
|
|
41
|
+
"navigation); the year list derives from min:/max: when both are set, else ten years " \
|
|
42
|
+
"around the initial month.",
|
|
43
|
+
"week_numbers: true adds the ISO week column (each row's Thursday decides the number)."
|
|
44
|
+
].freeze
|
|
45
|
+
|
|
46
|
+
use_stimulus do
|
|
47
|
+
on :root do
|
|
48
|
+
controller :calendar do
|
|
49
|
+
register
|
|
50
|
+
value :month, from: :month_key
|
|
51
|
+
value :selected, from: :selected_iso
|
|
52
|
+
value :mode, "range", if: :range?
|
|
53
|
+
value :range_start, from: :range_start_iso, if: :range?
|
|
54
|
+
value :range_end, from: :range_end_iso, if: :range?
|
|
55
|
+
value :week_start
|
|
56
|
+
value :min, from: :min_iso
|
|
57
|
+
value :max, from: :max_iso
|
|
58
|
+
# Localized month names (I18n) so JS month navigation needs
|
|
59
|
+
# no locale API of its own - app-locale correct everywhere.
|
|
60
|
+
value :month_names, from: :month_names_list
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
on :day do
|
|
64
|
+
controller :calendar do
|
|
65
|
+
target :day
|
|
66
|
+
action :select, on: :click
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
on :nav_previous do
|
|
70
|
+
controller(:calendar) { action :previousMonth, on: :click }
|
|
71
|
+
end
|
|
72
|
+
on :nav_next do
|
|
73
|
+
controller(:calendar) { action :nextMonth, on: :click }
|
|
74
|
+
end
|
|
75
|
+
# Elements consumed by the template:
|
|
76
|
+
on :dropdown do
|
|
77
|
+
controller(:calendar) { action :jump, on: :change }
|
|
78
|
+
end
|
|
79
|
+
on :grid do
|
|
80
|
+
controller(:calendar) { action :keydown, on: :keydown }
|
|
81
|
+
end
|
|
82
|
+
on :caption do
|
|
83
|
+
controller(:calendar) { target :caption }
|
|
84
|
+
end
|
|
85
|
+
on :start_input do
|
|
86
|
+
controller(:calendar) { target :startInput }
|
|
87
|
+
end
|
|
88
|
+
on :end_input do
|
|
89
|
+
controller(:calendar) { target :endInput }
|
|
90
|
+
end
|
|
91
|
+
on :hidden_input do
|
|
92
|
+
controller(:calendar) { target :input }
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
option :name, :string,
|
|
97
|
+
doc: "Makes the calendar a form control: the pick posts as an ISO string in a hidden input; range " \
|
|
98
|
+
"mode posts name[start] + name[end]."
|
|
99
|
+
option :mode, :symbol, default: :single,
|
|
100
|
+
doc: "Picks one date (:single) or a span (:range). Range selection completes on the " \
|
|
101
|
+
"second click; a click before the start swaps, a re-click clears."
|
|
102
|
+
option :week_start, :integer, default: 0,
|
|
103
|
+
doc: "The first weekday column (0 = Sunday .. 6 = Saturday)."
|
|
104
|
+
option :caption_layout, :symbol, default: :label,
|
|
105
|
+
doc: ":label shows the month text; :dropdown swaps it for month + year " \
|
|
106
|
+
"selects (jump navigation)."
|
|
107
|
+
option :week_numbers, :boolean, default: false,
|
|
108
|
+
doc: "Adds the ISO week-number column (each row's Thursday decides the number)."
|
|
109
|
+
|
|
110
|
+
part "calendar", "Root wrapper - the calendar controller (navigation, selection, roving " \
|
|
111
|
+
"arrow keys) rides here"
|
|
112
|
+
part "calendar-nav", "The header row - previous/next month Buttons around the caption"
|
|
113
|
+
part "calendar-caption", "The month label ('July 2026') - the controller rewrites it on " \
|
|
114
|
+
"navigation from the localized month names; under " \
|
|
115
|
+
"caption_layout: :dropdown it holds the month/year NativeSelect " \
|
|
116
|
+
"pair instead (the controller reflects navigation into them)"
|
|
117
|
+
part "calendar-week-number", "The ISO week column (week_numbers:) - a columnheader stub " \
|
|
118
|
+
"plus one muted rowheader number per week; non-interactive"
|
|
119
|
+
part "calendar-dropdown", "One caption dropdown unit (caption_layout: :dropdown) - the " \
|
|
120
|
+
"visible label with the real <select> stretched invisibly over " \
|
|
121
|
+
"it (the invisible-overlay pattern)",
|
|
122
|
+
states: {
|
|
123
|
+
"data-calendar-unit" => { condition: "always - which unit this select drives",
|
|
124
|
+
values: %w[month year] }
|
|
125
|
+
}
|
|
126
|
+
part "calendar-caption-label", "The visible text + chevron of a caption dropdown " \
|
|
127
|
+
"(aria-hidden - the overlaid select carries the value)"
|
|
128
|
+
part "calendar-dropdown-value", "The label's text span - the controller rewrites it on " \
|
|
129
|
+
"navigation (month name or year)"
|
|
130
|
+
part "calendar-grid", "The role=grid - the weekday header row plus six week rows " \
|
|
131
|
+
"(42 cells, always full weeks)"
|
|
132
|
+
part "calendar-weekdays", "The role=row of weekday column headers"
|
|
133
|
+
part "calendar-weekday", "One role=columnheader two-letter day label"
|
|
134
|
+
part "calendar-week", "One role=row of seven day cells"
|
|
135
|
+
part "calendar-day-cell", "The role=gridcell wrapper - aria-selected lives HERE (the " \
|
|
136
|
+
"ARIA grid contract; it is not valid on the button)"
|
|
137
|
+
part "calendar-day", "One day <button> - the selection vocabulary and the roving tab " \
|
|
138
|
+
"stop ride here",
|
|
139
|
+
states: {
|
|
140
|
+
"data-date" => "always - the day's ISO date (the controller's selection key)",
|
|
141
|
+
"data-selected" => "the day is the single-mode pick, or a start-only range pick " \
|
|
142
|
+
"(bare; a complete range wears the range-* trio instead)",
|
|
143
|
+
"data-range-start" => "the day starts a COMPLETE range",
|
|
144
|
+
"data-range-end" => "the day ends a COMPLETE range",
|
|
145
|
+
"data-range-middle" => "the day sits strictly inside a complete range",
|
|
146
|
+
"data-today" => "the day is today (aria-current=date rides along)",
|
|
147
|
+
"data-outside" => "the day belongs to a neighbouring month (leading/trailing fill)"
|
|
148
|
+
}
|
|
149
|
+
part "calendar-day-label", "The day-number span inside the button"
|
|
150
|
+
|
|
151
|
+
# Parses the date-valued keywords (month:, selected:, min:, max:, today:) -
|
|
152
|
+
# each accepts a Date or an ISO string; selected: in range mode also takes
|
|
153
|
+
# a Date..Date Range, an [start, end] pair, or a {start:, end:} hash.
|
|
154
|
+
# @api private
|
|
155
|
+
def initialize(month: nil, selected: nil, min: nil, max: nil, today: nil, **)
|
|
156
|
+
super(**)
|
|
157
|
+
raise ArgumentError, "unknown mode #{mode.inspect} (one of #{MODES.join(", ")})" unless MODES.include?(mode)
|
|
158
|
+
unless CAPTION_LAYOUTS.include?(caption_layout)
|
|
159
|
+
raise ArgumentError, "unknown caption_layout #{caption_layout.inspect} " \
|
|
160
|
+
"(one of #{CAPTION_LAYOUTS.join(", ")})"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
if range?
|
|
164
|
+
@range_start, @range_end = parse_range(selected)
|
|
165
|
+
else
|
|
166
|
+
@selected = to_date(selected)
|
|
167
|
+
end
|
|
168
|
+
@today = to_date(today) || Date.today
|
|
169
|
+
@min = to_date(min)
|
|
170
|
+
@max = to_date(max)
|
|
171
|
+
@month = to_date(month) || @selected || @range_start || @today
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# @api private
|
|
175
|
+
def range? = mode == :range
|
|
176
|
+
# @api private
|
|
177
|
+
def range_complete? = !!(@range_start && @range_end)
|
|
178
|
+
|
|
179
|
+
# Whether the date falls inside the current range selection.
|
|
180
|
+
# @api private
|
|
181
|
+
def in_span?(date)
|
|
182
|
+
return false unless range?
|
|
183
|
+
return date == @range_start unless range_complete?
|
|
184
|
+
|
|
185
|
+
date.between?(@range_start, @range_end)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# The 42 cells (6 weeks) for the visible month, leading/trailing
|
|
189
|
+
# days from the neighbours so every week is full.
|
|
190
|
+
# @api private
|
|
191
|
+
def cells
|
|
192
|
+
first = Date.new(@month.year, @month.month, 1)
|
|
193
|
+
lead = (first.wday - week_start) % 7
|
|
194
|
+
start = first - lead
|
|
195
|
+
(0...42).map { |offset| start + offset }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# @api private
|
|
199
|
+
# Two-letter column labels from the locale's abbreviated day
|
|
200
|
+
# names, rotated to week_start.
|
|
201
|
+
def weekday_labels
|
|
202
|
+
I18n.t("date.abbr_day_names").rotate(week_start).map { |name| name[0, 2] }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# @api private
|
|
206
|
+
def in_month?(date) = date.month == @month.month
|
|
207
|
+
# @api private
|
|
208
|
+
def selected?(date) = @selected && date == @selected
|
|
209
|
+
# @api private
|
|
210
|
+
def today?(date) = date == @today
|
|
211
|
+
# @api private
|
|
212
|
+
def disabled?(date) = (@min && date < @min) || (@max && date > @max)
|
|
213
|
+
|
|
214
|
+
# @api private
|
|
215
|
+
# Mirrors the controller's #captionText exactly (localized month
|
|
216
|
+
# name + year), so server render and client navigation agree in
|
|
217
|
+
# every locale.
|
|
218
|
+
def caption
|
|
219
|
+
"#{month_names_list[@month.month - 1]} #{@month.year}"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# @api private
|
|
223
|
+
def dropdown_caption? = caption_layout == :dropdown
|
|
224
|
+
|
|
225
|
+
# @api private
|
|
226
|
+
def month_options
|
|
227
|
+
month_names_list.each_with_index.map { |label, index| [label, index + 1] }
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# min:/max: pin the year list when both are given; otherwise ten
|
|
231
|
+
# years either side of the initial month (the demo-friendly default;
|
|
232
|
+
# bound it deliberately via min:/max: in real pickers).
|
|
233
|
+
# @api private
|
|
234
|
+
def year_options
|
|
235
|
+
years = @min && @max ? (@min.year..@max.year) : ((@month.year - 10)..(@month.year + 10))
|
|
236
|
+
years.map { |year| [year.to_s, year] }
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# The ISO week of a displayed row: its Thursday decides (ISO 8601),
|
|
240
|
+
# which stays correct under any week_start.
|
|
241
|
+
# @api private
|
|
242
|
+
def iso_week(week)
|
|
243
|
+
week.find { |date| date.cwday == 4 }.cweek
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Exactly one day is the tab stop: the selection (the range start
|
|
247
|
+
# in range mode), else today (in view), else the first enabled day.
|
|
248
|
+
# @api private
|
|
249
|
+
def tab_stop
|
|
250
|
+
anchor = range? ? @range_start : @selected
|
|
251
|
+
@tab_stop ||= (anchor if anchor && in_month?(anchor)) ||
|
|
252
|
+
(@today if in_month?(@today)) ||
|
|
253
|
+
cells.find { |date| in_month?(date) && !disabled?(date) }
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# @api private
|
|
257
|
+
def root_attributes
|
|
258
|
+
html_attributes.merge_if_not_set(
|
|
259
|
+
{ "data-slot" => "calendar", "class" => css }.merge(stimulus_attributes_for(:root))
|
|
260
|
+
.merge(component_data_attributes)
|
|
261
|
+
)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# aria-selected lives on the role=gridcell (the ARIA grid contract -
|
|
265
|
+
# it is not a valid attribute on a plain button). Range mode marks
|
|
266
|
+
# the whole span.
|
|
267
|
+
# @api private
|
|
268
|
+
def cell_attributes(date)
|
|
269
|
+
selected = range? ? in_span?(date) : selected?(date)
|
|
270
|
+
{
|
|
271
|
+
"role" => "gridcell", "data-slot" => "calendar-day-cell",
|
|
272
|
+
"class" => css(:day_cell), "aria-selected" => selected.to_s
|
|
273
|
+
}
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# @api private
|
|
277
|
+
def day_attributes(date)
|
|
278
|
+
iso = date.iso8601
|
|
279
|
+
attrs = {
|
|
280
|
+
"type" => "button", "data-slot" => "calendar-day",
|
|
281
|
+
"data-date" => iso, "class" => css(:day),
|
|
282
|
+
"aria-label" => date.strftime("%B %-d, %Y"),
|
|
283
|
+
"tabindex" => date == tab_stop ? "0" : "-1"
|
|
284
|
+
}.merge(stimulus_attributes_for(:day))
|
|
285
|
+
merge_selection_attributes(attrs, date)
|
|
286
|
+
attrs["data-today"] = "" if today?(date)
|
|
287
|
+
attrs["data-outside"] = "" unless in_month?(date)
|
|
288
|
+
attrs["aria-current"] = "date" if today?(date)
|
|
289
|
+
if disabled?(date)
|
|
290
|
+
attrs["disabled"] = true
|
|
291
|
+
attrs["aria-disabled"] = "true"
|
|
292
|
+
end
|
|
293
|
+
attrs
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# @api private
|
|
297
|
+
def previous_options
|
|
298
|
+
nav_options("Previous month", :nav_previous)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# @api private
|
|
302
|
+
def next_options
|
|
303
|
+
nav_options("Next month", :nav_next)
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
private
|
|
307
|
+
|
|
308
|
+
def nav_options(label, element)
|
|
309
|
+
{
|
|
310
|
+
variant: :ghost, size: :icon, label: label, class: css(:nav_button)
|
|
311
|
+
}.merge(stimulus_attributes_for(element))
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def to_date(value)
|
|
315
|
+
return if value.nil?
|
|
316
|
+
return value if value.is_a?(Date)
|
|
317
|
+
|
|
318
|
+
Date.parse(value.to_s)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# A preselected range: Date..Date, [start, end], or {start:, end:}.
|
|
322
|
+
def parse_range(value)
|
|
323
|
+
case value
|
|
324
|
+
when nil then [nil, nil]
|
|
325
|
+
when Range then [to_date(value.first), to_date(value.last)]
|
|
326
|
+
when Array then [to_date(value[0]), to_date(value[1])]
|
|
327
|
+
when Hash
|
|
328
|
+
pair = value.symbolize_keys
|
|
329
|
+
[to_date(pair[:start]), to_date(pair[:end])]
|
|
330
|
+
else
|
|
331
|
+
[to_date(value), nil] # a single value starts the range
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# The selection vocabulary per day: a COMPLETE range wears
|
|
336
|
+
# range-start/middle/end; a start-only pick is a plain selected
|
|
337
|
+
# single day; single mode keeps data-selected.
|
|
338
|
+
def merge_selection_attributes(attrs, date)
|
|
339
|
+
if range?
|
|
340
|
+
if range_complete?
|
|
341
|
+
attrs["data-range-start"] = "" if date == @range_start
|
|
342
|
+
attrs["data-range-end"] = "" if date == @range_end
|
|
343
|
+
attrs["data-range-middle"] = "" if date > @range_start && date < @range_end
|
|
344
|
+
elsif @range_start && date == @range_start
|
|
345
|
+
attrs["data-selected"] = ""
|
|
346
|
+
end
|
|
347
|
+
elsif selected?(date)
|
|
348
|
+
attrs["data-selected"] = ""
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def month_key = @month.strftime("%Y-%m")
|
|
353
|
+
def selected_iso = @selected&.iso8601 || ""
|
|
354
|
+
def range_start_iso = @range_start&.iso8601 || ""
|
|
355
|
+
def range_end_iso = @range_end&.iso8601 || ""
|
|
356
|
+
def min_iso = @min&.iso8601 || ""
|
|
357
|
+
def max_iso = @max&.iso8601 || ""
|
|
358
|
+
def month_names_list = I18n.t("date.month_names").drop(1)
|
|
359
|
+
|
|
360
|
+
private :range?, :range_complete?, :in_span?, :cells, :weekday_labels, :in_month?, :selected?, :today?
|
|
361
|
+
private :disabled?, :caption, :dropdown_caption?, :month_options, :year_options, :iso_week, :tab_stop
|
|
362
|
+
private :root_attributes, :cell_attributes, :day_attributes, :previous_options, :next_options
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Calendar
|
|
6
|
+
# The Calendar preview: a fixed month (deterministic screenshots) with
|
|
7
|
+
# a selected day and today, and a range-bounded variant.
|
|
8
|
+
class Preview < Poetry::Core::Preview::Base
|
|
9
|
+
def default
|
|
10
|
+
render_component(month: "2026-06-01", selected: "2026-06-12", today: "2026-06-15",
|
|
11
|
+
class: "rounded-md border")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def bounded
|
|
15
|
+
render_component(month: "2026-06-01", today: "2026-06-15",
|
|
16
|
+
min: "2026-06-08", max: "2026-06-22", class: "rounded-md border")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def range
|
|
20
|
+
render_component(mode: :range, month: "2026-06-01", today: "2026-06-15",
|
|
21
|
+
selected: Date.new(2026, 6, 9)..Date.new(2026, 6, 18),
|
|
22
|
+
class: "rounded-md border")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# caption_layout: :dropdown - the month/year NativeSelect pair;
|
|
26
|
+
# min/max pin the year list (deterministic options).
|
|
27
|
+
def dropdown_caption
|
|
28
|
+
render_component(month: "2026-06-01", selected: "2026-06-12", today: "2026-06-15",
|
|
29
|
+
caption_layout: :dropdown, min: "2024-01-01", max: "2028-12-31",
|
|
30
|
+
class: "rounded-md border")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# week_numbers: the ISO week column (June 2026 = weeks 23-28).
|
|
34
|
+
def week_numbers
|
|
35
|
+
render_component(month: "2026-06-01", selected: "2026-06-12", today: "2026-06-15",
|
|
36
|
+
week_numbers: true, class: "rounded-md border")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# name: makes the calendar a form participant - the hidden input
|
|
40
|
+
# the controller keeps in sync submits the ISO date.
|
|
41
|
+
def form_participant
|
|
42
|
+
render_component(name: "event[on]", month: "2026-06-01", selected: "2026-06-12",
|
|
43
|
+
today: "2026-06-15", class: "rounded-md border")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Range + name: submits <name>[start] / <name>[end] hidden inputs.
|
|
47
|
+
def form_participant_range
|
|
48
|
+
render_component(mode: :range, name: "stay", month: "2026-06-01", today: "2026-06-15",
|
|
49
|
+
range_start: "2026-06-08", range_end: "2026-06-12",
|
|
50
|
+
class: "rounded-md border")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Calendar
|
|
6
|
+
# poetry's OWN calendar engine, re-expressed through the cn-*
|
|
7
|
+
# theme layer. The cell-size var + grid geometry stay inline
|
|
8
|
+
# (mechanism); the day-button's whole state chain (selected / today /
|
|
9
|
+
# outside / range tints) rides .cn-calendar-day-button TOGETHER
|
|
10
|
+
# (split-side rule - the tints override each other in-layer). The
|
|
11
|
+
# in-popover bg override stays inline per upstream's own root split.
|
|
12
|
+
class Style < Poetry::Core::Style
|
|
13
|
+
# group/calendar stays dropped (no consumer; the compiled-CSS gate
|
|
14
|
+
# flags markers nothing consumes). It returns with a consumer.
|
|
15
|
+
base "cn-calendar bg-background [--cell-size:--spacing(8)] w-fit " \
|
|
16
|
+
"in-data-[slot=popover-content]:bg-transparent group/calendar " \
|
|
17
|
+
"in-data-[slot=card-content]:bg-transparent"
|
|
18
|
+
|
|
19
|
+
element :nav, "flex items-center justify-between gap-1 pb-2"
|
|
20
|
+
element :nav_button, "size-(--cell-size) p-0 select-none aria-disabled:opacity-50"
|
|
21
|
+
element :caption, "cn-calendar-caption flex-1 text-center select-none"
|
|
22
|
+
# The dropdown caption (caption_layout: :dropdown), upstream's
|
|
23
|
+
# overlay pattern: the visible part is TEXT + a small chevron; the
|
|
24
|
+
# real <select> stretches invisibly over it. Most themes leave the
|
|
25
|
+
# root chromeless (maia/lyra add a border via
|
|
26
|
+
# .cn-calendar-dropdown-root); the focus ring here is poetry's
|
|
27
|
+
# structural a11y floor - an invisible select still needs a
|
|
28
|
+
# visible focus.
|
|
29
|
+
element :caption_dropdowns, "flex flex-1 items-center justify-center gap-1.5 text-sm font-medium"
|
|
30
|
+
# (No cn-calendar-dropdown-root/caption-label names: only maia/lyra
|
|
31
|
+
# theme this surface upstream - the breadcrumb doctrine, a cn name
|
|
32
|
+
# the other themes cannot compile does not ship; maia/lyra restyle
|
|
33
|
+
# via the data-slot hooks instead.)
|
|
34
|
+
element :dropdown_root, "relative rounded-md " \
|
|
35
|
+
"has-[select:focus-visible]:ring-[3px] has-[select:focus-visible]:ring-ring/50"
|
|
36
|
+
element :dropdown_select, "absolute inset-0 opacity-0"
|
|
37
|
+
element :dropdown_label, "flex select-none items-center gap-1 text-sm " \
|
|
38
|
+
"font-medium [&>svg]:size-3.5 [&>svg]:text-muted-foreground"
|
|
39
|
+
|
|
40
|
+
element :grid, "w-full border-collapse"
|
|
41
|
+
element :weekdays, "flex"
|
|
42
|
+
element :weekday, "cn-calendar-weekday flex-1 select-none flex items-center justify-center " \
|
|
43
|
+
"h-(--cell-size)"
|
|
44
|
+
element :week, "mt-2 flex w-full"
|
|
45
|
+
element :day_cell, "relative aspect-square h-full w-full flex-1 p-0 text-center select-none"
|
|
46
|
+
|
|
47
|
+
# The day button: ghost, with the selected/today/outside/range
|
|
48
|
+
# states - the whole treatment in the theme rule.
|
|
49
|
+
element :day, "cn-calendar-day-button relative isolate z-10 flex aspect-square size-auto " \
|
|
50
|
+
"w-full min-w-(--cell-size) items-center justify-center border-0 outline-none " \
|
|
51
|
+
"disabled:pointer-events-none"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<% if header? %>
|
|
3
|
+
<div data-slot="card-header" class="<%= css(:header, class: header_class) %>">
|
|
4
|
+
<% if title? %><%= content_tag(title_tag, title, "data-slot" => "card-title", class: css(:title)) %><% end %>
|
|
5
|
+
<% if description? %><div data-slot="card-description" class="<%= css(:description) %>"><%= description %></div><% end %>
|
|
6
|
+
<% if action? %><div data-slot="card-action" class="<%= css(:action) %>"><%= action %></div><% end %>
|
|
7
|
+
</div>
|
|
8
|
+
<% end %>
|
|
9
|
+
<div data-slot="card-content" class="<%= css(:content, class: content_class) %>"><%= content %></div>
|
|
10
|
+
<% if footer? %><%= content_tag(:div, footer_attributes) do %><%= capture(&footer_block) if footer_block %><% end %><% end %>
|
|
11
|
+
<% end %>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
# Content surface cards.
|
|
6
|
+
module Card
|
|
7
|
+
# A content surface composed from slots: a header (title,
|
|
8
|
+
# description, and a trailing corner action), the body content
|
|
9
|
+
# block, and a footer row. The header grid gains its trailing
|
|
10
|
+
# column automatically when an action is present, and the title
|
|
11
|
+
# renders as a real heading (h3 by default - set title_tag: to fit
|
|
12
|
+
# the page outline).
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# render Poetry::Ui::Card::Component.new do |card|
|
|
16
|
+
# card.with_title { "Team" }
|
|
17
|
+
# card.with_description { "Invite and manage members." }
|
|
18
|
+
# "Body content"
|
|
19
|
+
# end
|
|
20
|
+
class Component < Poetry::Core::Component
|
|
21
|
+
# Projected into the registry, llms.txt, and the agent surface.
|
|
22
|
+
AGENT_RULES = [
|
|
23
|
+
"Compose with the slots (title/description/action/footer) - never rebuild the header grid by hand.",
|
|
24
|
+
"The card body is the content block; use CardAction for the header-corner control.",
|
|
25
|
+
"The title renders as a real heading (h3 default) - set title_tag: to fit the page outline."
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
renders_one :title, doc: "The heading line, rendered as a real heading element (title_tag:)."
|
|
29
|
+
renders_one :description, doc: "Muted one-liner under the title."
|
|
30
|
+
renders_one :action, doc: "The header's trailing corner control (a button, menu, or link)."
|
|
31
|
+
renders_one :footer,
|
|
32
|
+
doc: "The bottom row (actions/meta). class: merges into the footer div (a border-t divider is " \
|
|
33
|
+
"the canonical use); every other option (id:, data:, ...) rides onto the footer div " \
|
|
34
|
+
"verbatim.",
|
|
35
|
+
renders: lambda { |**options, &block|
|
|
36
|
+
@footer_options = options
|
|
37
|
+
@footer_block = block
|
|
38
|
+
nil
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
option :title_tag, :symbol, default: :h3,
|
|
42
|
+
doc: "The heading element for the title - pick it to fit the page outline."
|
|
43
|
+
|
|
44
|
+
option :content_class, :string,
|
|
45
|
+
doc: "Extra classes merged into the body cell (caller classes win). A chat-in-a-card layout passes " \
|
|
46
|
+
"min-h-0 flex-1 p-0 so the transcript can flex and scroll."
|
|
47
|
+
|
|
48
|
+
option :header_class, :string,
|
|
49
|
+
doc: "Extra classes merged into the header row - border-b rules the title off from the body."
|
|
50
|
+
|
|
51
|
+
validates :title_tag, inclusion: { in: %i[h1 h2 h3 h4 h5 h6] }
|
|
52
|
+
|
|
53
|
+
part "card", "Root container - the vertical flex stack"
|
|
54
|
+
part "card-header", "The title row grid - gains a trailing auto column when " \
|
|
55
|
+
"card-action is present"
|
|
56
|
+
part "card-title", "The heading (title_tag, h3 by default)"
|
|
57
|
+
part "card-description", "Muted one-liner under the title"
|
|
58
|
+
part "card-action", "The header's trailing corner control"
|
|
59
|
+
part "card-content", "The body - the content block renders here"
|
|
60
|
+
part "card-footer", "The bottom row (actions/meta)"
|
|
61
|
+
|
|
62
|
+
# The caller's footer block, captured by with_footer.
|
|
63
|
+
# @api private
|
|
64
|
+
attr_reader :footer_block
|
|
65
|
+
|
|
66
|
+
# @api private
|
|
67
|
+
def footer_attributes
|
|
68
|
+
options = (@footer_options || {}).dup
|
|
69
|
+
{ "data-slot" => "card-footer",
|
|
70
|
+
class: css(:footer, class: options.delete(:class)) }.merge(options)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Whether any header slot is set.
|
|
74
|
+
# @api private
|
|
75
|
+
def header?
|
|
76
|
+
title? || description? || action?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @api private
|
|
80
|
+
def root_attributes
|
|
81
|
+
html_attributes.merge_if_not_set(
|
|
82
|
+
{ "data-slot" => "card" }.merge(component_data_attributes)
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private :footer_attributes, :header?, :root_attributes
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Card
|
|
6
|
+
# The Card preview: the title/description default and the full
|
|
7
|
+
# header-action + footer composition.
|
|
8
|
+
class Preview < Poetry::Core::Preview::Base
|
|
9
|
+
def default
|
|
10
|
+
render_component do |card|
|
|
11
|
+
card.with_title { "Revenue" }
|
|
12
|
+
card.with_description { "Last 30 days" }
|
|
13
|
+
"$12,345"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def with_action_and_footer
|
|
18
|
+
render_component do |card|
|
|
19
|
+
card.with_title { "Team" }
|
|
20
|
+
card.with_description { "Active members" }
|
|
21
|
+
card.with_action { embed(Poetry::Ui::Button::Component.new(size: :sm, variant: :outline).with_content("Invite")) }
|
|
22
|
+
card.with_footer { "Updated hourly" }
|
|
23
|
+
"24 members"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Ui
|
|
5
|
+
module Card
|
|
6
|
+
# Re-expressed through the cn-* theme layer: grid machinery
|
|
7
|
+
# stays inline (upstream's split), the surface treatment + spacing
|
|
8
|
+
# ride themes/default.css.
|
|
9
|
+
class Style < Poetry::Core::Style
|
|
10
|
+
base "cn-card flex flex-col group/card"
|
|
11
|
+
|
|
12
|
+
element :header, "cn-card-header grid auto-rows-min items-start " \
|
|
13
|
+
"has-data-[slot=card-action]:grid-cols-[1fr_auto] @container/card-header " \
|
|
14
|
+
"group/card-header has-data-[slot=card-description]:grid-rows-[auto_auto]"
|
|
15
|
+
element :title, "cn-card-title"
|
|
16
|
+
element :description, "cn-card-description"
|
|
17
|
+
element :action, "col-start-2 row-span-2 row-start-1 self-start justify-self-end"
|
|
18
|
+
element :content, "cn-card-content"
|
|
19
|
+
element :footer, "cn-card-footer flex items-center"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%= content_tag(:div, **root_attributes.to_attributes) do %>
|
|
2
|
+
<%= content_tag(:div, viewport_attributes) do %>
|
|
3
|
+
<div class="<%= css(:track, class: [css(vertical? ? :track_vertical : :track_horizontal), track_classes].compact) %>">
|
|
4
|
+
<% slides.each do |slide| %>
|
|
5
|
+
<%= content_tag(:div, capture(&slide.block), item_attributes(slide)) %>
|
|
6
|
+
<% end %>
|
|
7
|
+
</div>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% if show_controls %>
|
|
10
|
+
<%= render Poetry::Ui::Button::Component.new(**control_options(:previous)) do |button| %>
|
|
11
|
+
<% button.with_leading { render Poetry::Ui::Icon::Component.new(name: :"chevron-left") } %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%= render Poetry::Ui::Button::Component.new(**control_options(:next)) do |button| %>
|
|
14
|
+
<% button.with_leading { render Poetry::Ui::Icon::Component.new(name: :"chevron-right") } %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|