@povio/ui 5.0.0-rc.9 → 6.0.0-rc.1
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.
- package/MIGRATION.md +645 -0
- package/README.md +207 -29
- package/dist/{Accordion-BzwO4_ml.js → Accordion-DQRdeDs1.js} +5 -5
- package/dist/{Alert-DfiJbKH0.d.ts → Alert-Cee_nKWj.d.ts} +3 -3
- package/dist/{AlertDialog-OWTbR4km.d.ts → AlertDialog-uNDUIyng.d.ts} +3 -3
- package/dist/Autocomplete-CWU9Ev3J.js +142 -0
- package/dist/Autocomplete-D_4gEL7D.d.ts +23 -0
- package/dist/Autocomplete.bound-CqhZtdd8.d.ts +9 -0
- package/dist/Autocomplete.bound-D0pgmsHB.js +28 -0
- package/dist/{Badge-CBNpj823.d.ts → Badge-C4HI9XX4.d.ts} +2 -2
- package/dist/{BadgeButton-Ccgt3oGO.d.ts → BadgeButton-h3MeQYcp.d.ts} +2 -2
- package/dist/{BottomSheet-DbQuzfAB.d.ts → BottomSheet-BQXSdxoX.d.ts} +1 -1
- package/dist/{BottomSheet-BXLE3161.js → BottomSheet-z5brMtDt.js} +6 -80
- package/dist/{BottomSheet.lazy-D9LCEo7s.d.ts → BottomSheet.lazy-BzvLg8Ea.d.ts} +1 -1
- package/dist/{Breadcrumbs-FF8hMfXd.js → Breadcrumbs-AbUBqBTq.js} +9 -9
- package/dist/{Breadcrumbs-CUV6CU8Q.d.ts → Breadcrumbs-B9O0_VSN.d.ts} +1 -1
- package/dist/{Button-D6KlWSFL.js → Button-C1YB5dOw.js} +3 -3
- package/dist/Button-DER_6cxv.js +16 -0
- package/dist/Button-f7FPTaiN.d.ts +13 -0
- package/dist/ButtonBase-CYTFS-xK.d.ts +32 -0
- package/dist/ButtonBase-CeFSNcVs.js +86 -0
- package/dist/{Calendar-BTjajO6i.js → Calendar-DRQ536wk.js} +20 -16
- package/dist/{Checkbox-CV1ILXXO.js → Checkbox-BI3DQPLa.js} +19 -36
- package/dist/{Checkbox-DVTWaMKa.d.ts → Checkbox-CCvC7OVT.d.ts} +9 -8
- package/dist/Checkbox.bound-CMZnF2_d.js +33 -0
- package/dist/Checkbox.bound-DBt33Inx.d.ts +9 -0
- package/dist/CheckboxCheckmark-BzT6MwH5.js +47 -0
- package/dist/CheckboxGroup-DQw4hsFa.js +139 -0
- package/dist/CheckboxGroup-MJ6crCZk.d.ts +30 -0
- package/dist/CheckboxGroup.bound-CTCdezUN.js +32 -0
- package/dist/CheckboxGroup.bound-j2Sc8QtU.d.ts +9 -0
- package/dist/ComboBox-DFlz6HJ8.js +212 -0
- package/dist/{DatePicker-DOLL7mkc.js → DatePicker-CSm9c37c.js} +38 -48
- package/dist/{DatePicker-8xSs_jNd.d.ts → DatePicker-umTISfvn.d.ts} +21 -10
- package/dist/DatePicker.bound-KLyoWNcX.d.ts +9 -0
- package/dist/DatePicker.bound-Yqckg7Mk.js +36 -0
- package/dist/{DatePickerInput-BLBcySA2.js → DatePickerInput-Cs9RwZfy.js} +41 -29
- package/dist/{DatePickerInput-D81ZJ3fT.d.ts → DatePickerInput-DwHQvLzi.d.ts} +3 -3
- package/dist/{DateRangePicker-Bfq-yDm7.d.ts → DateRangePicker-hV_U1IK0.d.ts} +30 -10
- package/dist/{DateRangePicker-BF-1CztH.js → DateRangePicker-s_4n-F_P.js} +75 -64
- package/dist/DateRangePicker.bound-C1klxYW0.js +35 -0
- package/dist/DateRangePicker.bound-D-GPENNe.d.ts +9 -0
- package/dist/{DateTimePicker-Cj0qvJUz.js → DateTimePicker-411pU7VF.js} +38 -42
- package/dist/{DateTimePicker-D4lHyf6P.d.ts → DateTimePicker-wgV0SUeZ.d.ts} +21 -11
- package/dist/DateTimePicker.bound-BDyUzidV.js +32 -0
- package/dist/DateTimePicker.bound-cF2X_ncj.d.ts +9 -0
- package/dist/{Dialog-9manOgMA.js → Dialog-DSl1Fkqi.js} +10 -7
- package/dist/Dialog-V-2cgGk1.d.ts +21 -0
- package/dist/{Dialog-CKLkS00H.js → Dialog-lFYX-7Ax.js} +22 -27
- package/dist/DropdownMenu-Bl_C5W_E.d.ts +25 -0
- package/dist/{DropdownMenu-5jmtgLXd.js → DropdownMenu-DH7E2aXb.js} +6 -6
- package/dist/{DropdownMenuDesktop-Cl9gZVq0.js → DropdownMenuDesktop-nMoCa6N5.js} +3 -3
- package/dist/{FileInput-Br5DQaGQ.js → FileInput-CqRrQRM-.js} +25 -39
- package/dist/{FileInput-C4CE5kuP.d.ts → FileInput-Q72yXorH.d.ts} +24 -20
- package/dist/FileInput.bound-BZ7-g-dq.js +30 -0
- package/dist/FileInput.bound-CG2G5E2K.d.ts +8 -0
- package/dist/{FileTrigger-Cthk5_Wp.js → FileTrigger-DBX1Io6E.js} +36 -7
- package/dist/FileUpload-B4ibHWQn.d.ts +11 -0
- package/dist/{FileUpload--7ub3EZO.js → FileUpload-CG60c6wM.js} +251 -140
- package/dist/FileUpload.bound-C-Zy1n5Y.d.ts +16 -0
- package/dist/FileUpload.bound-DQ6uuH2W.js +30 -0
- package/dist/{FileUploadContainer-042ztsaL.d.ts → FileUploadContainer-CtUhDntB.d.ts} +1 -1
- package/dist/{Form-DlQcyN1f.js → Form-CqF1SaVw.js} +2 -2
- package/dist/{FormField-Byiehm9y.d.ts → FormField-BIRMlgu4.d.ts} +4 -2
- package/dist/{FormField-B99dLt8o.js → FormField-D7KKJ6kG.js} +13 -104
- package/dist/{FormFieldError-DeOHHLo2.js → FormFieldError-Bqjg9cMb.js} +2 -13
- package/dist/FormFieldHeaderTooltip-k8Snf_oM.js +47 -0
- package/dist/{Heading-nI1_VOaE.js → Heading-D4XFYv__.js} +2 -2
- package/dist/IconButton-BM2DUNtN.d.ts +25 -0
- package/dist/{InlineTooltipWrapper-BpApaGXV.js → InlineTooltipWrapper-DBuQX2yo.js} +1 -1
- package/dist/{Input-BsbLZDtC.js → Input-BG0Xjw5X.js} +2 -2
- package/dist/{Input-DOanwj3l.d.ts → Input-BX3sZBEp.d.ts} +13 -9
- package/dist/Input-CG4Irgae.js +229 -0
- package/dist/Input.bound-BE-espm0.d.ts +9 -0
- package/dist/Input.bound-jZx8gJro.js +31 -0
- package/dist/{InputContent-CXuP1ghQ.d.ts → InputContent-DDFr0kml.d.ts} +4 -4
- package/dist/{useFieldAccessibility-ScC6Mtd5.js → InputContent-KhD4_YvO.js} +12 -25
- package/dist/{Label-B2-B-uFY.js → Label-BGvF9vWx.js} +2 -2
- package/dist/{Link-Ow9H7kNv.d.ts → Link-Bw2m9W4B.d.ts} +3 -3
- package/dist/{Link-FupWOW1f.js → Link-Chux-Clm.js} +2 -2
- package/dist/{ListBox-CL8Ar4Q_.js → ListBox-CoUk0kkt.js} +10 -11
- package/dist/{MenuItem-DHyqOqln.d.ts → MenuItem-DPZzOqp2.d.ts} +1 -1
- package/dist/{Modal-w60dVQcb.js → Modal-B4p1zFqi.js} +58 -20
- package/dist/NumberField-CxwTlqud.js +225 -0
- package/dist/{NumberField-Cb9Gf6QJ.d.ts → NumberField-qjvHhCfN.d.ts} +13 -9
- package/dist/NumberField.bound-DXPGF5YK.d.ts +9 -0
- package/dist/NumberField.bound-zySl-v_q.js +32 -0
- package/dist/{NumberFormatter-CLDS_LRZ.js → NumberFormatter-DYarfm5F.js} +2 -36
- package/dist/{NumberRangeInput-B8-LHfg3.js → NumberRangeInput-BrW03wC6.js} +15 -43
- package/dist/{NumberRangeInput-BfbJQqzn.d.ts → NumberRangeInput-CS4Kn427.d.ts} +13 -8
- package/dist/NumberRangeInput.bound-C8I7m1cW.d.ts +9 -0
- package/dist/NumberRangeInput.bound-CKywKEKI.js +32 -0
- package/dist/{OverlayArrow-D8z7cCsw.js → OverlayArrow-DF0jMwul.js} +2 -2
- package/dist/{Pagination-CwQu5Py8.d.ts → Pagination-DkpAg2x6.d.ts} +1 -1
- package/dist/{PaginationList-DMRUGtf8.d.ts → PaginationList-DNmZRcS6.d.ts} +1 -1
- package/dist/{PaginationList-DtvuP63b.js → PaginationList-PjOxNQwB.js} +93 -94
- package/dist/PasswordInput-BHPFkVbM.d.ts +11 -0
- package/dist/PasswordInput.bound-CrXKvfil.js +23 -0
- package/dist/{PasswordInput-CLwFUgl0.d.ts → PasswordInput.bound-DC57m4NT.d.ts} +5 -6
- package/dist/{Popover-BTHPteIh.d.ts → Popover-pjd0Hu61.d.ts} +2 -2
- package/dist/{Progress-CjWOR38H.d.ts → Progress-1WGRZE8l.d.ts} +3 -3
- package/dist/{Progress-B3mY9rIP.js → Progress-De76pCfX.js} +2 -27
- package/dist/{RadioGroup-DOw3PRoX.js → RadioGroup-BPSvcre6.js} +12 -116
- package/dist/RadioGroup-DEwQ6B1F.d.ts +26 -0
- package/dist/RadioGroup.bound-CN4K9dV2.js +32 -0
- package/dist/RadioGroup.bound-Dj6CEG6M.d.ts +9 -0
- package/dist/{RichTextEditor-D4yN7Wj7.js → RichTextEditor-BYIQW8QA.js} +147 -78
- package/dist/RichTextEditor-hJtuB7Y6.d.ts +28 -0
- package/dist/{staticSelect.utils-uHa8f_c6.js → Select-Br_3eecr.js} +195 -236
- package/dist/{SelectBase-Omiq2D3M.d.ts → Select-DHYddedn.d.ts} +32 -11
- package/dist/Select.bound-CJ-tCsmX.d.ts +17 -0
- package/dist/Select.bound-CgLKMzLn.js +34 -0
- package/dist/{SelectionIndicator-JblvLKCu.js → SelectionIndicator-B7C5Y0JM.js} +1 -1
- package/dist/{SharedElementTransition-Da1c_cOO.js → SharedElementTransition-DJ9CCbEa.js} +1 -1
- package/dist/{Slider-EYlGCLWe.d.ts → Slider-CcoNTFVN.d.ts} +9 -8
- package/dist/{Slider-CzEmKYBF.js → Slider-CqB2TPTR.js} +12 -35
- package/dist/Slider.bound-8B5qzQ-8.d.ts +9 -0
- package/dist/Slider.bound-Bp7Zrs9_.js +31 -0
- package/dist/{Spinner-DbXeDOa2.d.ts → Spinner-B-crRcdG.d.ts} +2 -2
- package/dist/{SplitButton-D9ngY1rJ.d.ts → SplitButton-BzhbtpFA.d.ts} +3 -3
- package/dist/{Stepper-Cp5vbL5g.js → Stepper-CMw6QnCu.js} +2 -2
- package/dist/{Stepper-TATlHZhQ.d.ts → Stepper-LORgYAJr.d.ts} +8 -8
- package/dist/Switch-CSitpm4o.d.ts +24 -0
- package/dist/{Switch-CqnGEdeD.js → Switch-R0kAicgM.js} +7 -56
- package/dist/Switch.bound-DVjqsum1.d.ts +9 -0
- package/dist/Switch.bound-Dk-BmxJd.js +33 -0
- package/dist/{Tag-AHfV_XSf.d.ts → Tag-CoqCTZRm.d.ts} +6 -6
- package/dist/{Text-D2MPZ3sY.js → Text-D72yc4S6.js} +1 -1
- package/dist/{TextArea-D8WkKsGn.js → TextArea-DCnqXuHC.js} +30 -33
- package/dist/{TextArea-l_keyLK7.d.ts → TextArea-e8sQm205.d.ts} +11 -9
- package/dist/TextArea.bound-BJZ9m_FE.js +28 -0
- package/dist/TextArea.bound-DEZuRYm_.d.ts +9 -0
- package/dist/TextArea.cva-Bb73hriz.js +5 -0
- package/dist/{TimePicker-C4taAOFQ.js → TimePicker-BwF-Crbg.js} +54 -46
- package/dist/TimePicker-Zi7B6VTr.d.ts +45 -0
- package/dist/TimePicker.bound-B-BVLNbk.js +32 -0
- package/dist/TimePicker.bound-Bxtb6uJL.d.ts +9 -0
- package/dist/{Toast-ruXqONDA.d.ts → Toast-Dl6KMa58.d.ts} +1 -1
- package/dist/{ToastContainer-qgpzMFD4.js → ToastContainer-BDvta6st.js} +3 -3
- package/dist/ToggleButton-Cce9bnBw.d.ts +17 -0
- package/dist/{ToggleButton-BW1ensey.js → ToggleButton-DUQ8nwKY.js} +5 -5
- package/dist/{toggleGroup.types-Bp43zbSQ.d.ts → ToggleGroup-BJ8cqXaO.d.ts} +14 -13
- package/dist/{ToggleGroup-DOk27fgI.js → ToggleGroup-s5sDSB6l.js} +132 -158
- package/dist/ToggleGroup.bound-Cv09n91n.d.ts +9 -0
- package/dist/ToggleGroup.bound-DEc7rdNF.js +67 -0
- package/dist/Tooltip-BiS7isYB.d.ts +16 -0
- package/dist/{Tooltip-CpG1nz7Y.js → Tooltip-CMigoyri.js} +42 -7
- package/dist/{TooltipWrapper-3jyN0Wss.js → TooltipWrapper-D7HUZLsP.js} +6 -6
- package/dist/{Typography-XljT9s02.d.ts → Typography-D2FfZr7a.d.ts} +1 -1
- package/dist/{accordion.cva-CL1bVscW.js → accordion.cva-CeBWV9EO.js} +6 -6
- package/dist/{badgeButton.cva-B2bgCQP6.d.ts → badgeButton.cva-B8EQLwPv.d.ts} +3 -3
- package/dist/{badgeButton.cva-CvN4CTx5.js → badgeButton.cva-BPyVejxO.js} +66 -66
- package/dist/{breadcrumbs.cva-7zzdDhVR.js → breadcrumbs.cva-DPwJJK_D.js} +4 -4
- package/dist/{button.cva-C7kEhgoA.d.ts → button.cva-CBckM91c.d.ts} +3 -3
- package/dist/{Button-C5rv4Cr2.js → button.cva-vO0fPUTn.js} +26 -109
- package/dist/{buttonContent.cva-DPIlROA9.d.ts → buttonContent.cva-DG-4lRz4.d.ts} +2 -2
- package/dist/{checkbox.cva-t1Ox50hy.d.ts → checkbox.cva-CJy87xUo.d.ts} +5 -5
- package/dist/{CheckboxCheckmark-CpC3wlMs.js → checkbox.cva-D-D9Qgaf.js} +4 -45
- package/dist/components/accordion.js +1 -1
- package/dist/components/alert-dialog.d.ts +1 -1
- package/dist/components/alert-dialog.js +93 -86
- package/dist/components/alert.d.ts +1 -1
- package/dist/components/alert.js +116 -1
- package/dist/components/autocomplete.d.ts +2 -2
- package/dist/components/autocomplete.js +1 -134
- package/dist/components/badge-button.d.ts +1 -1
- package/dist/components/badge-button.js +3 -3
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/badge.js +4 -4
- package/dist/components/bottom-sheet-header.d.ts +16 -0
- package/dist/components/bottom-sheet-header.js +79 -0
- package/dist/components/bottom-sheet.d.ts +2 -2
- package/dist/components/bottom-sheet.js +2 -2
- package/dist/components/breadcrumb/react-aria.js +1 -1
- package/dist/components/breadcrumbs.d.ts +1 -1
- package/dist/components/breadcrumbs.js +1 -1
- package/dist/components/button-group.d.ts +12 -0
- package/dist/components/button-group.js +46 -0
- package/dist/components/button.d.ts +2 -2
- package/dist/components/button.js +1 -1
- package/dist/components/checkbox-group.d.ts +2 -2
- package/dist/components/checkbox-group.js +1 -163
- package/dist/components/checkbox.d.ts +2 -2
- package/dist/components/checkbox.js +2 -2
- package/dist/components/combo-box/react-aria.js +1 -1
- package/dist/components/date-picker/react-aria.js +1 -1
- package/dist/components/date-picker.d.ts +2 -2
- package/dist/components/date-picker.js +1 -1
- package/dist/components/date-range-picker/react-aria.js +1 -1
- package/dist/components/date-range-picker.d.ts +2 -2
- package/dist/components/date-range-picker.js +1 -1
- package/dist/components/date-time-picker.d.ts +2 -2
- package/dist/components/date-time-picker.js +1 -1
- package/dist/components/dialog-trigger/react-aria.js +1 -1
- package/dist/components/dialog.d.ts +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/drawer.js +3 -3
- package/dist/components/dropdown-menu.d.ts +2 -2
- package/dist/components/dropdown-menu.js +2 -2
- package/dist/components/file-input.d.ts +2 -2
- package/dist/components/file-input.js +1 -1
- package/dist/components/file-upload-container.d.ts +2 -2
- package/dist/components/file-upload-container.js +1 -1
- package/dist/components/file-upload.d.ts +3 -3
- package/dist/components/file-upload.js +1 -1
- package/dist/components/form-field.d.ts +1 -1
- package/dist/components/form-field.js +1 -1
- package/dist/components/icon-button.d.ts +1 -1
- package/dist/components/icon-button.js +17 -15
- package/dist/components/icon-slot.d.ts +1 -1
- package/dist/components/input-frame.d.ts +93 -0
- package/dist/{useStaticInputHandoff-NeZVnci-.js → components/input-frame.js} +42 -91
- package/dist/components/input.d.ts +2 -2
- package/dist/components/input.js +1 -241
- package/dist/components/link.d.ts +1 -1
- package/dist/components/link.js +2 -2
- package/dist/components/menu-trigger/react-aria.js +1 -1
- package/dist/components/modal/react-aria.js +1 -1
- package/dist/components/modal-overlay/react-aria.js +1 -1
- package/dist/components/number-field.d.ts +2 -2
- package/dist/components/number-field.js +1 -245
- package/dist/components/number-range-input.d.ts +2 -2
- package/dist/components/number-range-input.js +1 -1
- package/dist/components/pagination-list.d.ts +1 -1
- package/dist/components/pagination-list.js +1 -1
- package/dist/components/pagination.d.ts +1 -1
- package/dist/components/pagination.js +10 -6
- package/dist/components/password-input.d.ts +2 -2
- package/dist/components/password-input.js +22 -1
- package/dist/components/popover/react-aria.js +1 -1
- package/dist/components/popover.d.ts +1 -1
- package/dist/components/popover.js +38 -30
- package/dist/components/progress.d.ts +1 -1
- package/dist/components/progress.js +1 -1
- package/dist/components/radio-group.d.ts +2 -2
- package/dist/components/radio-group.js +1 -1
- package/dist/components/select/react-aria.js +1 -1
- package/dist/components/select.d.ts +2 -3
- package/dist/components/select.js +1 -1
- package/dist/components/slider.d.ts +2 -2
- package/dist/components/slider.js +1 -1
- package/dist/components/spinner.d.ts +1 -1
- package/dist/components/split-button.d.ts +1 -1
- package/dist/components/split-button.js +2 -2
- package/dist/components/stepper.d.ts +1 -1
- package/dist/components/stepper.js +1 -1
- package/dist/components/style-definitions.d.ts +3 -0
- package/dist/components/style-definitions.js +121 -0
- package/dist/components/submenu-trigger/react-aria.js +1 -1
- package/dist/components/switch.d.ts +2 -2
- package/dist/components/switch.js +1 -1
- package/dist/components/tag.d.ts +1 -1
- package/dist/components/tag.js +93 -1
- package/dist/components/text-area.d.ts +2 -2
- package/dist/components/text-area.js +1 -1
- package/dist/components/time-picker.d.ts +2 -2
- package/dist/components/time-picker.js +1 -1
- package/dist/components/toast.d.ts +2 -2
- package/dist/components/toast.js +2 -2
- package/dist/components/toggle-button.d.ts +1 -1
- package/dist/components/toggle-button.js +17 -30
- package/dist/components/toggle-group.d.ts +2 -3
- package/dist/components/toggle-group.js +1 -1
- package/dist/components/tooltip-ellipsis.js +1 -1
- package/dist/components/tooltip.d.ts +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/components/typography.d.ts +2 -2
- package/dist/components/use-toast.d.ts +1 -1
- package/dist/components/use-toast.js +2 -2
- package/dist/config/component-configuration.d.ts +30 -0
- package/dist/config/component-configuration.js +69 -0
- package/dist/config/confirmation.d.ts +1 -1
- package/dist/config/confirmation.js +1 -1
- package/dist/config/link-context.d.ts +2 -2
- package/dist/config/resources.d.ts +1 -1
- package/dist/config/resources.js +1 -1
- package/dist/config/ui-config.d.ts +2 -2
- package/dist/config/ui-config.js +1 -1
- package/dist/config/ui-overrides.d.ts +1 -1
- package/dist/{confirmation.context-BOeEVczb.d.ts → confirmation.context-B2z9A1v3.d.ts} +1 -1
- package/dist/{confirmation.context-BuzgCfYl.js → confirmation.context-BSn1s-ip.js} +1 -1
- package/dist/{datePickerValue.utils-DCgoSrP3.js → datePickerValue.utils-OAQBDk1R.js} +18 -10
- package/dist/{dialog.cva-COhDZaVl.js → dialog.cva-sioU_5R7.js} +1 -1
- package/dist/{dist-CAdwxJbe.js → dist-CAFUM34b.js} +53 -1
- package/dist/{dom.utils-D1AopHx9.js → dom.utils-BbfrA6RP.js} +1 -1
- package/dist/{dropdownMenu.cva-DvEmX0bs.js → dropdownMenu.cva-Bi3a21lO.js} +4 -4
- package/dist/{PasswordInput-DYwUZ4-k.js → eye-BA4nRlMX.js} +1 -22
- package/dist/{fileUpload.types-n5FxK_F-.d.ts → fileUpload.types-BT8P1o7a.d.ts} +17 -17
- package/dist/form.binding-B-2id68q.js +49 -0
- package/dist/form.types-C8P4sznq.d.ts +22 -0
- package/dist/formFieldError.cva-CTl0VeyG.js +14 -0
- package/dist/formFieldHelper.cva-CxAmrG2H.js +97 -0
- package/dist/hooks/use-async-list.d.ts +2 -0
- package/dist/hooks/use-async-list.js +2 -0
- package/dist/hooks/use-filters.js +1 -1
- package/dist/{i18n-CX1vFM9r.d.ts → i18n-2z5on9No.d.ts} +18 -0
- package/dist/{i18n-CX2EjhJI.js → i18n-BjNKHh_D.js} +20 -2
- package/dist/{iconSlot.cva-CnpFzAOR.d.ts → iconSlot.cva-BA9NahZH.d.ts} +2 -1
- package/dist/icons.d.ts +1 -1
- package/dist/index.d.ts +95 -91
- package/dist/index.js +80 -78
- package/dist/{input.cva-BsHgYa-L.d.ts → input.cva-L7jKDv6q.d.ts} +3 -3
- package/dist/{input.cva-DJA8ovm_.js → input.cva-w7ZEVQAM.js} +60 -41
- package/dist/{intlStrings-chfsan9H.js → intlStrings-Cu1YN1tA.js} +35 -35
- package/dist/isEqual-LFw0W5rU.js +97 -0
- package/dist/{link.context-D5qyz9Rf.d.ts → link.context-C4fE_aMo.d.ts} +1 -1
- package/dist/{link.cva-DMTHZiJG.js → link.cva-D3XRgcAv.js} +1 -1
- package/dist/{numberStatic.utils-BX50PSee.js → numberStatic.utils-BIyZuILs.js} +5 -5
- package/dist/progress.cva-D7iiX6Lh.js +28 -0
- package/dist/radio.cva-Ctdop1xV.js +82 -0
- package/dist/{radio.cva-DN9VQ3Kb.d.ts → radio.cva-DO3UEac-.d.ts} +3 -3
- package/dist/rich-text-editor.d.ts +2 -2
- package/dist/rich-text-editor.js +1 -1
- package/dist/{routing.utils-UTQonIhB.js → routing.utils-DfxEt0_Y.js} +5 -0
- package/dist/selectDesktop.cva-RzxvSBkd.js +14 -0
- package/dist/{selectDesktop.cva-CHAMxhfO.js → selectItem.cva-BWfEkNs_.js} +3 -36
- package/dist/{staticDateTimeSegments-DtU63_dw.js → staticDateTimeSegments-Bt5wCZvg.js} +58 -54
- package/dist/status.cva-BFGMKZO_.js +130 -0
- package/dist/{stepper.cva-CZ0Kj-s7.js → stepper.cva-CpRi0fGb.js} +10 -10
- package/dist/{configuration.context-f_FSPWhQ.d.ts → style-definitions-_RXJdSk-.d.ts} +183 -86
- package/dist/styles/editor.css +1 -1
- package/dist/styles/input.d.ts +1 -1
- package/dist/switch.cva-BsJ4iAFl.js +27 -0
- package/dist/{switch.cva-CWNzmdRc.d.ts → switch.cva-psw67dK9.d.ts} +3 -3
- package/dist/table.cva-CmfeWLyW.d.ts +84 -0
- package/dist/table.cva-DFQM8VbM.js +111 -0
- package/dist/tag.cva-BCCH7ku3.js +55 -0
- package/dist/tanstack/autocomplete.d.ts +3 -2
- package/dist/tanstack/autocomplete.js +1 -1
- package/dist/tanstack/checkbox-group.d.ts +3 -2
- package/dist/tanstack/checkbox-group.js +1 -1
- package/dist/tanstack/checkbox.d.ts +3 -2
- package/dist/tanstack/checkbox.js +2 -2
- package/dist/tanstack/date-picker.d.ts +3 -2
- package/dist/tanstack/date-picker.js +1 -1
- package/dist/tanstack/date-range-picker.d.ts +3 -2
- package/dist/tanstack/date-range-picker.js +1 -1
- package/dist/tanstack/date-time-picker.d.ts +3 -2
- package/dist/tanstack/date-time-picker.js +1 -1
- package/dist/tanstack/file-input.d.ts +3 -2
- package/dist/tanstack/file-input.js +1 -1
- package/dist/tanstack/file-upload.d.ts +4 -3
- package/dist/tanstack/file-upload.js +1 -1
- package/dist/tanstack/form.d.ts +3 -3
- package/dist/tanstack/form.js +3 -3
- package/dist/tanstack/input.d.ts +3 -2
- package/dist/tanstack/input.js +1 -1
- package/dist/tanstack/number-field.d.ts +3 -2
- package/dist/tanstack/number-field.js +1 -1
- package/dist/tanstack/number-range-input.d.ts +3 -2
- package/dist/tanstack/number-range-input.js +1 -1
- package/dist/tanstack/password-input.d.ts +1 -1
- package/dist/tanstack/password-input.js +1 -1
- package/dist/tanstack/radio-group.d.ts +3 -2
- package/dist/tanstack/radio-group.js +1 -1
- package/dist/tanstack/rich-text-editor.d.ts +9 -2
- package/dist/tanstack/rich-text-editor.js +27 -1
- package/dist/tanstack/select.d.ts +3 -2
- package/dist/tanstack/select.js +1 -1
- package/dist/tanstack/slider.d.ts +3 -2
- package/dist/tanstack/slider.js +1 -1
- package/dist/tanstack/switch.d.ts +3 -2
- package/dist/tanstack/switch.js +1 -1
- package/dist/tanstack/table.d.ts +3 -2
- package/dist/tanstack/table.js +2 -3
- package/dist/tanstack/text-area.d.ts +3 -2
- package/dist/tanstack/text-area.js +1 -1
- package/dist/tanstack/time-picker.d.ts +3 -2
- package/dist/tanstack/time-picker.js +1 -1
- package/dist/tanstack/toggle-group.d.ts +3 -3
- package/dist/tanstack/toggle-group.js +1 -1
- package/dist/tanstack-DQu9PNjn.d.ts +469 -0
- package/dist/tanstack.d.ts +79 -78
- package/dist/tanstack.js +80 -76
- package/dist/{toast.cva-By5lvAfr.d.ts → toast.cva-L0k_TBiW.d.ts} +7 -7
- package/dist/{toast.cva-C_L_RffH.js → toast.cva-aC4NMpLb.js} +14 -14
- package/dist/{toast.runtime-cxex9e4E.js → toast.runtime-DKOeUnk6.js} +1 -2
- package/dist/{toggleGroup.cva-MbpaEBg1.js → toggleGroup.cva-CEhjMT4j.js} +1 -1
- package/dist/{tooltip.cva-BIzlOXHH.js → tooltip.cva-ClcaR72U.js} +4 -4
- package/dist/tw-ui-plugin.js +5 -1
- package/dist/{typography.cva-D1JOEYl-.d.ts → typography.cva-GpC6QQNx.d.ts} +2 -2
- package/dist/{uiConfig.context-DeBX2beU.d.ts → uiConfig.context-CQU9Tzq_.d.ts} +12 -20
- package/dist/{uiConfig.context-BS3r_kTS.js → uiConfig.context-CT9EVqC5.js} +3 -109
- package/dist/{uiOverrides.context-DEp139He.d.ts → uiOverrides.context-Dmev7iRS.d.ts} +44 -6
- package/dist/useAsyncList-Cu-Y8If2.d.ts +9 -0
- package/dist/useAsyncList-yHz7twsj.js +445 -0
- package/dist/{useBreakpoint-DQoMN-BG.js → useBreakpoint-BzYqQEBO.js} +1 -1
- package/dist/{useControlledState-CzXkZCX8.js → useControlledState-CuU1VIh1.js} +2 -2
- package/dist/useFieldAccessibility-eZIMECmG.js +19 -0
- package/dist/{useFilters-XNH27Md2.js → useFilters-HIngImwn.js} +1 -1
- package/dist/{form.binding-DVJ5F0JE.d.ts → useForm-I6z23FXf.d.ts} +15 -15
- package/dist/{form.binding-CG1RPv6o.js → useForm-eW4KpH1u.js} +79 -42
- package/dist/useFormAutosave-BBLm3Ujo.d.ts +34 -0
- package/dist/useFormAutosave-XEQqk1lK.js +216 -0
- package/dist/useStaticInputHandoff-DyYxfwv6.js +77 -0
- package/dist/useTableColumnConfig-CUINwVTR.js +1348 -0
- package/dist/{useTableNav-Ckj5PBRk.d.ts → useTableNav-rU9WmCj6.d.ts} +34 -96
- package/dist/{useToast-yreVCUer.d.ts → useToast-DfQif03I.d.ts} +1 -1
- package/dist/{utils-Czcqspm7.js → utils-BkLF-JA3.js} +1 -1
- package/package.json +65 -232
- package/.rulesync/rules/ui-buttons-and-content.md +0 -56
- package/.rulesync/rules/ui-inputs-and-forms.md +0 -62
- package/.rulesync/rules/ui-overlays-navigation-and-styling.md +0 -49
- package/.rulesync/rules/ui-overview.md +0 -33
- package/dist/Alert-CnvEb1D_.js +0 -244
- package/dist/AppCanvasPage--RG31Yyv.js +0 -2421
- package/dist/AppCanvasPage-BIFYeEeS.d.ts +0 -80
- package/dist/Autocomplete-BwNHp8fy.d.ts +0 -15
- package/dist/Button-D-4qb0IR.d.ts +0 -42
- package/dist/CheckboxGroup-DGF12cmB.d.ts +0 -28
- package/dist/ComponentGallery-C6exitZN.js +0 -3513
- package/dist/Dialog-CW93T9X1.d.ts +0 -56
- package/dist/DropdownMenu-JNpYT4-3.d.ts +0 -62
- package/dist/FileUpload-CR7bZxV1.d.ts +0 -7
- package/dist/Form-DbEWnCKc.d.ts +0 -49
- package/dist/FormFieldHeaderTooltip-BV2Ju4oB.js +0 -17
- package/dist/IconButton-D4thBurp.d.ts +0 -16
- package/dist/InlineIconButton-BeJCjl-q.d.ts +0 -15
- package/dist/InputItem-CIxbTxZu.js +0 -63
- package/dist/Inputs-DJSKiaWY.js +0 -17
- package/dist/Inputs-O84btFJL.d.ts +0 -13
- package/dist/QuerySelect-BGxb6Y0K.d.ts +0 -24
- package/dist/RadioGroup-CZg2kIMk.d.ts +0 -24
- package/dist/RichTextEditor-YxuRUlI7.d.ts +0 -26
- package/dist/Select-UR0ec2Ux.js +0 -154
- package/dist/Select-pHbyJdZJ.d.ts +0 -15
- package/dist/Switch-s_EPn0Jz.d.ts +0 -22
- package/dist/Table-BN2_J_Ne.js +0 -636
- package/dist/Tag-DPg5sL1Z.js +0 -146
- package/dist/TextButton-XUhV_1s0.d.ts +0 -15
- package/dist/TimePicker-B1POvGWs.d.ts +0 -33
- package/dist/Toast-DtG3pA61.js +0 -53
- package/dist/ToggleButton-7aP8Jb11.d.ts +0 -11
- package/dist/ToggleGroup-CRFDIPGZ.d.ts +0 -7
- package/dist/Tooltip-DHv6vAqW.d.ts +0 -57
- package/dist/UIConfigurator-BwLRfe-a.js +0 -6704
- package/dist/autocomplete-DeERHN8W.d.ts +0 -16
- package/dist/checkbox-DxIPDTK5.d.ts +0 -9
- package/dist/checkbox-group-B3BOVshI.d.ts +0 -9
- package/dist/chevron-left-Dgo_b9wJ.js +0 -20
- package/dist/chevron-up-D_Gqpb5M.js +0 -20
- package/dist/components/inline-icon-button.d.ts +0 -2
- package/dist/components/inline-icon-button.js +0 -40
- package/dist/components/query-autocomplete.d.ts +0 -8
- package/dist/components/query-autocomplete.js +0 -134
- package/dist/components/query-select.d.ts +0 -2
- package/dist/components/query-select.js +0 -147
- package/dist/components/text-button.d.ts +0 -2
- package/dist/components/text-button.js +0 -35
- package/dist/config/app-canvas-tanstack.d.ts +0 -23
- package/dist/config/app-canvas-tanstack.js +0 -62
- package/dist/config/app-canvas.d.ts +0 -12
- package/dist/config/app-canvas.js +0 -2
- package/dist/config/ui-configurator-theme.d.ts +0 -2
- package/dist/config/ui-configurator-theme.js +0 -2
- package/dist/config/ui-configurator-vite.d.ts +0 -10
- package/dist/config/ui-configurator-vite.js +0 -174
- package/dist/config/ui-configurator.d.ts +0 -15
- package/dist/config/ui-configurator.js +0 -3
- package/dist/date-picker-DnxDmlOW.d.ts +0 -9
- package/dist/date-range-picker-DHDOSvHN.d.ts +0 -9
- package/dist/date-time-picker-UkTa0OJ8.d.ts +0 -9
- package/dist/date.transforms-DLg-eFcE.js +0 -15
- package/dist/dynamicInputs-ByVMnx4Z.d.ts +0 -772
- package/dist/dynamicInputs-CRMWIpHA.js +0 -194
- package/dist/dynamicInputs-m_DQu5q0.js +0 -214
- package/dist/fieldAdapter-C4sDFC8f.d.ts +0 -9
- package/dist/fieldAdapter-DjYls12j.js +0 -63
- package/dist/file-input-DkbkdI7l.d.ts +0 -9
- package/dist/file-upload-CTsPhxJk.d.ts +0 -10
- package/dist/form.types-CecYaerF.d.ts +0 -13
- package/dist/form.types-ZNGbcqJS.d.ts +0 -13
- package/dist/info-iUmX3uDk.js +0 -32
- package/dist/input-CdQNCPgH.d.ts +0 -8
- package/dist/number-field-CUDbenNV.d.ts +0 -8
- package/dist/number-range-input-DZGrcvjL.d.ts +0 -8
- package/dist/password-input-fYN20cQO.d.ts +0 -8
- package/dist/query-autocomplete-CfuQeiYG.d.ts +0 -14
- package/dist/query-select-CuT_sE6a.d.ts +0 -15
- package/dist/queryAutocomplete.types-tl3r6iaY.d.ts +0 -27
- package/dist/radio-group-B3ccPf0p.d.ts +0 -9
- package/dist/rhf/autocomplete.d.ts +0 -3
- package/dist/rhf/autocomplete.js +0 -8
- package/dist/rhf/checkbox-group.d.ts +0 -3
- package/dist/rhf/checkbox-group.js +0 -8
- package/dist/rhf/checkbox.d.ts +0 -3
- package/dist/rhf/checkbox.js +0 -8
- package/dist/rhf/date-picker.d.ts +0 -3
- package/dist/rhf/date-picker.js +0 -9
- package/dist/rhf/date-range-picker.d.ts +0 -3
- package/dist/rhf/date-range-picker.js +0 -9
- package/dist/rhf/date-time-picker.d.ts +0 -3
- package/dist/rhf/date-time-picker.js +0 -9
- package/dist/rhf/file-input.d.ts +0 -3
- package/dist/rhf/file-input.js +0 -6
- package/dist/rhf/file-upload.d.ts +0 -3
- package/dist/rhf/file-upload.js +0 -6
- package/dist/rhf/input.d.ts +0 -3
- package/dist/rhf/input.js +0 -6
- package/dist/rhf/inputs.d.ts +0 -4
- package/dist/rhf/inputs.js +0 -2
- package/dist/rhf/number-field.d.ts +0 -3
- package/dist/rhf/number-field.js +0 -6
- package/dist/rhf/number-range-input.d.ts +0 -3
- package/dist/rhf/number-range-input.js +0 -6
- package/dist/rhf/password-input.d.ts +0 -3
- package/dist/rhf/password-input.js +0 -6
- package/dist/rhf/query-autocomplete.d.ts +0 -2
- package/dist/rhf/query-autocomplete.js +0 -8
- package/dist/rhf/query-select.d.ts +0 -2
- package/dist/rhf/query-select.js +0 -8
- package/dist/rhf/radio-group.d.ts +0 -3
- package/dist/rhf/radio-group.js +0 -8
- package/dist/rhf/rich-text-editor.d.ts +0 -3
- package/dist/rhf/rich-text-editor.js +0 -6
- package/dist/rhf/select.d.ts +0 -3
- package/dist/rhf/select.js +0 -8
- package/dist/rhf/slider.d.ts +0 -3
- package/dist/rhf/slider.js +0 -6
- package/dist/rhf/switch.d.ts +0 -3
- package/dist/rhf/switch.js +0 -8
- package/dist/rhf/text-area.d.ts +0 -3
- package/dist/rhf/text-area.js +0 -6
- package/dist/rhf/time-picker.d.ts +0 -3
- package/dist/rhf/time-picker.js +0 -9
- package/dist/rhf/toggle-group.d.ts +0 -3
- package/dist/rhf/toggle-group.js +0 -6
- package/dist/rhf-t348TCCL.js +0 -256
- package/dist/rhf.d.ts +0 -106
- package/dist/rhf.js +0 -112
- package/dist/rich-text-editor-B-Onl7T8.d.ts +0 -8
- package/dist/select-B4a52eWW.d.ts +0 -16
- package/dist/slider-dNj9jruO.d.ts +0 -8
- package/dist/style-merge.util-zLimKwt6.d.ts +0 -40
- package/dist/styles/app-canvas.css +0 -740
- package/dist/styles/configurator.css +0 -3280
- package/dist/switch-C--iWnY8.d.ts +0 -9
- package/dist/table.cva-D5oQ-QvA.js +0 -101
- package/dist/tanstack/inputs.d.ts +0 -5
- package/dist/tanstack/inputs.js +0 -3
- package/dist/tanstack/query-autocomplete.d.ts +0 -2
- package/dist/tanstack/query-autocomplete.js +0 -2
- package/dist/tanstack/query-select.d.ts +0 -2
- package/dist/tanstack/query-select.js +0 -2
- package/dist/text-area-DQAtpOQp.d.ts +0 -8
- package/dist/theme-model-DtYPxNvH.js +0 -406
- package/dist/theme-model-T1zIdBg8.d.ts +0 -12
- package/dist/time-picker-DoGfbil6.d.ts +0 -9
- package/dist/toggle-group-C1nMDOwz.d.ts +0 -9
- package/dist/underline-66hmELxa.js +0 -81
- package/dist/upload-CXU83BJ4.js +0 -30
- package/dist/useFormAutosave-DfuP7drj.js +0 -198
- package/dist/useQueryAutocomplete-CraXvRm_.js +0 -152
- package/dist/useTableColumnConfig-Di0_w80v.js +0 -892
- package/dist/zod.utils-DrrPDT9v.js +0 -24
- package/rulesync.jsonc +0 -11
- package/scripts/generate-rules.mjs +0 -34
- package/src/configurator/README.md +0 -77
- package/dist/{import-BE0r63d8.js → import-D_3dPATF.js} +2 -2
- /package/dist/{queries.utils-CmbhAoHU.js → tanstack-CmbhAoHU.js} +0 -0
package/MIGRATION.md
ADDED
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
# Povio UI migration guide
|
|
2
|
+
|
|
3
|
+
This guide covers the web UI cleanup, including the focused button cleanup: removal of React Hook Form integration, schema-driven rendering, query selectors, and the admin page builder; stricter input contracts; the form, accessibility, upload, date/time, table, and pagination fixes; and consolidation of redundant button wrappers.
|
|
4
|
+
|
|
5
|
+
Migrate one form or page at a time. Preserve its API payloads, permissions, translations, URL state, and design. Choose controls from the meaning of each field, then verify their value types against the public declarations. A TypeScript error should be resolved by fixing the binding or data shape, rather than adding a cast or suppression.
|
|
6
|
+
|
|
7
|
+
`Input` retains its name. Button component choices and palette role names are clarified below; existing designs, sizes, and color values are preserved. This migration does not require a design overhaul. React Native form integration is outside this web migration; the palette section also identifies the shared color names used by native apps.
|
|
8
|
+
|
|
9
|
+
## 1. Find the affected code
|
|
10
|
+
|
|
11
|
+
Start with application code, shared wrappers, examples, and code generators. Search for these usages:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
rg -n '@povio/ui/rhf|formControl|QuerySelect|QueryAutocomplete|useQueryAutocomplete|dynamicInputs|dynamicColumns|ZodUtils|usePageBuilder|PageBuilder|builderConfigs' apps packages
|
|
15
|
+
rg -n '@povio/ui/(tanstack/)?(inputs|query-select|query-autocomplete)|ui\.(querySelect|queryAutocomplete)' apps packages
|
|
16
|
+
rg -n '\bfullIso\b|\bselectionMode\b|\bdefaultState\b' apps packages
|
|
17
|
+
rg -n 'TextButton|InlineIconButton|@povio/ui/(text-button|inline-icon-button)|\biconOnly\b|\btoggle\b' apps packages
|
|
18
|
+
rg -n 'text-text-|bg-elevation-fill-|interactive-contained-' apps packages
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Also inspect imports of `Form`, `Inputs`, and `InputItem` from Povio UI, broad barrel imports used for standalone inputs, table cell callbacks that destructure `original`, and callbacks or defaults passed directly to bound inputs. The searches include valid usages: inspect the component before changing a prop. In particular, ToggleButton, BadgeButton, Breadcrumbs, and ToggleGroup retain their own selection or icon props; do not apply a global `iconOnly` or `toggle` removal. Keep React Native components unchanged.
|
|
22
|
+
|
|
23
|
+
| Previous usage | Replacement |
|
|
24
|
+
| ---------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
25
|
+
| `@povio/ui/rhf` and its component subpaths | `@povio/ui/tanstack/form` and `@povio/ui/tanstack/<component>` |
|
|
26
|
+
| `formControl={{ control, name }}` | `field={{ form, name }}` |
|
|
27
|
+
| Povio `Form`, `Inputs`, `InputItem`, `dynamicInputs`, `ZodUtils` | Explicit JSX fields and ordinary Zod validation |
|
|
28
|
+
| `dynamicColumns` | Explicit typed column definitions |
|
|
29
|
+
| ID-valued or multi-selection `Autocomplete` | `Select`, with `isSearchable` when needed |
|
|
30
|
+
| `QuerySelect`, `QueryAutocomplete`, `useQueryAutocomplete` | `Select` plus `useAsyncList`, or explicit text suggestion loading |
|
|
31
|
+
| Admin page-builder configuration and generated `builderConfigs` | Domain pages, filters, fields, tables, and dialogs |
|
|
32
|
+
| `fullIso` on `DateTimePicker` or `TimePicker` | Remove the prop; keep full UTC timestamp values |
|
|
33
|
+
| Web `TextButton` / `@povio/ui/text-button` | `Button variant="text" width="hug"` |
|
|
34
|
+
| Web `InlineIconButton` / `@povio/ui/inline-icon-button` | `IconButton variant="text" size="sm" width="hug" disableTooltip` |
|
|
35
|
+
| `Button iconOnly` / `Button toggle` | `IconButton` / `ToggleButton` with equivalent appearance |
|
|
36
|
+
| Table cell `({ original }) => original.name` | `({ row }) => row.original.name` |
|
|
37
|
+
|
|
38
|
+
Removed symbols and subpaths have no compatibility adapter. Update shared abstractions first so their consumers inherit the corrected contract.
|
|
39
|
+
|
|
40
|
+
## 2. Replace RHF integration and choose the correct imports
|
|
41
|
+
|
|
42
|
+
TanStack Form is the supported web form integration. Ordinary component subpaths are standalone; corresponding `tanstack` subpaths are bound to a form. The broad `@povio/ui` and `@povio/ui/tanstack` barrels expose bound input versions. Use explicit subpaths so the ownership of a value is visible at the import.
|
|
43
|
+
|
|
44
|
+
| Purpose | Import example | Value ownership |
|
|
45
|
+
| ------------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------- |
|
|
46
|
+
| Controlled or uncontrolled standalone input | `@povio/ui/input` | `value`/`onChange`, or a supported default prop |
|
|
47
|
+
| Form-bound input | `@povio/ui/tanstack/input` | Required `field={{ form, name }}` |
|
|
48
|
+
| Form hooks and types | `@povio/ui/tanstack/form` | Raw form state and parsed submissions |
|
|
49
|
+
| ID selection | `@povio/ui/select` or `@povio/ui/tanstack/select` | Single ID or array of IDs |
|
|
50
|
+
| Free text with suggestions | `@povio/ui/autocomplete` or `@povio/ui/tanstack/autocomplete` | String |
|
|
51
|
+
| Tables | `@povio/ui/tanstack/table` | Explicit rows, columns, and table state |
|
|
52
|
+
|
|
53
|
+
Replace the RHF resolver with `zodSchema`. Replace the old control object with the entire Povio form object. A complete form now looks like this:
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { z } from "zod";
|
|
57
|
+
import { Button } from "@povio/ui/button";
|
|
58
|
+
import { useForm } from "@povio/ui/tanstack/form";
|
|
59
|
+
import { Input } from "@povio/ui/tanstack/input";
|
|
60
|
+
import { Select } from "@povio/ui/tanstack/select";
|
|
61
|
+
|
|
62
|
+
const profileSchema = z.object({
|
|
63
|
+
name: z.string().min(1, "Name is required"),
|
|
64
|
+
roleId: z.string().nullable(),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export function ProfileForm({ onSave }: { onSave: (values: z.output<typeof profileSchema>) => Promise<void> }) {
|
|
68
|
+
const form = useForm({
|
|
69
|
+
zodSchema: profileSchema,
|
|
70
|
+
defaultValues: { name: "", roleId: null },
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<form onSubmit={form.handleSubmit(onSave)}>
|
|
75
|
+
<Input
|
|
76
|
+
label="Name"
|
|
77
|
+
field={{ form, name: "name" }}
|
|
78
|
+
/>
|
|
79
|
+
<Select
|
|
80
|
+
label="Role"
|
|
81
|
+
field={{ form, name: "roleId" }}
|
|
82
|
+
items={[{ id: "editor", label: "Editor" }]}
|
|
83
|
+
/>
|
|
84
|
+
<Button type="submit">Save</Button>
|
|
85
|
+
</form>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Use `form.handleSubmit(onValid, onInvalid)` as the submit handler. `onValid` receives parsed output; `onInvalid` receives errors and raw values. `onSubmitAsync` in the hook options is an asynchronous validator receiving `{ value }` in raw form shape, rather than the successful-submit callback.
|
|
91
|
+
|
|
92
|
+
| RHF operation | Povio TanStack operation |
|
|
93
|
+
| ---------------------------------------------- | ---------------------------------------------------------------- |
|
|
94
|
+
| `watch("name")` or reactive value subscription | `useFormValue(form, values => values.name)` |
|
|
95
|
+
| Reactive `formState` access | `useFormState(form, state => state.isDirty)` or another selector |
|
|
96
|
+
| `setValue("name", value)` | `form.setFieldValue("name", value)` |
|
|
97
|
+
| Replace values and establish defaults | `form.reset(rawValues)` |
|
|
98
|
+
| Read current values outside rendering | `form.state.values` |
|
|
99
|
+
|
|
100
|
+
RHF options and error APIs do not map by a simple rename. Reimplement their behavior with the supported form and field APIs. Keep RHF dependencies if other parts of the application still use them; remove them when no remaining consumer needs them. An application that retains RHF can adapt standalone controls itself.
|
|
101
|
+
|
|
102
|
+
## 3. Give each value one owner
|
|
103
|
+
|
|
104
|
+
Standalone controls reject `field`. Bound controls require it and reject top-level `value`, `onChange`, `onBlur`, `defaultValue`, `defaultSelected`, `defaultChecked`, `defaultState`, and `onValueCommit`. Boolean controls also reject competing `isSelected` values when bound. Initialize bound values through form defaults or reset them through the form.
|
|
105
|
+
|
|
106
|
+
For example, replace a bound input with a top-level change side effect:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
Before: <Input field={{ form, name: "name" }} onChange={trackName} />
|
|
110
|
+
After: <Input field={{ form, name: "name", onValueChange: trackName }} />
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`field.onValueChange` receives the control's native value after raw state updates. `field.onBlur` takes no arguments and runs after actual focus loss marks the field touched. Selection commits can validate or flush autosave without invoking that blur side effect. Programmatic setters and resets invoke neither callback. Move business effects that must run on programmatic changes into application logic explicitly.
|
|
114
|
+
|
|
115
|
+
Use these value shapes when choosing a field schema and default:
|
|
116
|
+
|
|
117
|
+
| Control | Interaction value | Empty value |
|
|
118
|
+
| ---------------------------------------------------- | --------------------------------------------------- | -------------------------- |
|
|
119
|
+
| `Input`, `TextArea`, `PasswordInput`, `Autocomplete` | String | `""` |
|
|
120
|
+
| `NumberField` | Number | `null` |
|
|
121
|
+
| `NumberRangeInput` | `{ min: number \| null; max: number \| null }` | `{ min: null, max: null }` |
|
|
122
|
+
| `Checkbox`, `Switch` | Boolean, controlled through standalone `isSelected` | `false` |
|
|
123
|
+
| Single `Select` | String or number ID | `null` |
|
|
124
|
+
| Multiple `Select` | Array of IDs; `selectionMode="multiple"` | `[]` |
|
|
125
|
+
| Date/time controls | String; see the format table below | `null` |
|
|
126
|
+
| Single `FileInput` or bound `FileUpload` | Native `File` | `null` |
|
|
127
|
+
| Multiple `FileInput` or bound `FileUpload` | `File[]` | `[]` |
|
|
128
|
+
|
|
129
|
+
For other controls, use their public component types. Defaults are component-specific; do not add `defaultValue` to every standalone control. Checkbox and Switch use `defaultSelected` where an uncontrolled default is needed.
|
|
130
|
+
|
|
131
|
+
NumberRangeInput uses `null` for each cleared endpoint, whether cleared with the keyboard or its clear button. Use nullable numbers in the range schema; keyboard clearing no longer propagates `NaN` into the form or standalone change callback.
|
|
132
|
+
|
|
133
|
+
## 4. Replace schema-driven fields and columns
|
|
134
|
+
|
|
135
|
+
Remove Povio `Form`, `Inputs`, `InputItem`, `dynamicInputs`, `dynamicColumns`, and `ZodUtils` usages. The `@povio/ui/tanstack/inputs` entry is gone. Keep Zod schemas for validation and transformation, and render each field explicitly as in the profile example.
|
|
136
|
+
|
|
137
|
+
Choose widgets from domain meaning. A string may represent a name, password, selected ID, calendar date, or timestamp; its Zod primitive alone cannot determine the correct control. Preserve labels, options, permissions, conditional visibility, helper text, and custom layouts previously supplied by renderer configuration. Arrays of IDs should become multiple Select fields; arrays of domain objects need explicit editing UI.
|
|
138
|
+
|
|
139
|
+
Define table columns directly using public types. For example:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { Table, type TableProps } from "@povio/ui/tanstack/table";
|
|
143
|
+
|
|
144
|
+
type Rocket = { id: string; name: string };
|
|
145
|
+
|
|
146
|
+
const columns: TableProps<Rocket>["columns"] = [
|
|
147
|
+
{
|
|
148
|
+
id: "name",
|
|
149
|
+
accessorKey: "name",
|
|
150
|
+
header: "Name",
|
|
151
|
+
cell: ({ row }) => row.original.name,
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
export function RocketsTable({ items }: { items: Rocket[] }) {
|
|
156
|
+
return (
|
|
157
|
+
<Table
|
|
158
|
+
items={items}
|
|
159
|
+
columns={columns}
|
|
160
|
+
getRowId={(rocket) => rocket.id}
|
|
161
|
+
/>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Use `row.original` for the domain row and `getValue()` for a cell's accessor value. Runtime aliases such as `original`, `data`, and `value` remain for compatibility, but do not rely on them in consumer code: they are not the portable public cell contract. Workspace type augmentations can hide this problem, so check examples against published declarations too.
|
|
167
|
+
|
|
168
|
+
For row-selection cells, standalone Checkbox emits a boolean: use `isSelected={row.getIsSelected()}` with `onChange={(isSelected) => row.toggleSelected(isSelected)}`. Do not pass `row.getToggleSelectedHandler()` directly; that TanStack adapter expects a DOM event with `target.checked`. The select-all checkbox can use `onChange={table.toggleAllRowsSelected}` because that method accepts a boolean.
|
|
169
|
+
|
|
170
|
+
Table selection defaults and change callbacks now work independently. `defaultSelectedRows` alone initializes internally managed selection once; later default changes do not reset it. `onRowSelectionChange` alone observes internal changes. Supplying both retains the existing controlled behavior: pass the current selection through the legacy `defaultSelectedRows` prop and update it through the callback, for example with a React state value and setter. The callback receives TanStack selection values or updater functions, not always a resolved object. Keep stable `getRowId` values so the selected keys identify the intended records.
|
|
171
|
+
|
|
172
|
+
`useFilters(defaults, prefix, schema)` remains available with its existing positional API. Removing visual schema renderers does not require removing schemas used to parse filter data.
|
|
173
|
+
|
|
174
|
+
## 5. Separate selected IDs from entered text
|
|
175
|
+
|
|
176
|
+
Use `Select` when the submitted value identifies an option. Add `isSearchable` when users need to search those options. Typing a search does not replace the selected ID with the search text. Single selection emits an ID or `null`; multiple selection emits an ID array.
|
|
177
|
+
|
|
178
|
+
Use `Autocomplete` when the submitted value is text. Suggestions help enter that text: choosing `{ id: "city-1", label: "Ljubljana" }` stores `"Ljubljana"`. Suggestion IDs identify list rows. Arbitrary text is allowed, and clearing emits `""`.
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { Select } from "@povio/ui/select";
|
|
182
|
+
import { Autocomplete } from "@povio/ui/autocomplete";
|
|
183
|
+
|
|
184
|
+
const cities = [{ id: "city-1", label: "Ljubljana" }];
|
|
185
|
+
|
|
186
|
+
export function CityFields({
|
|
187
|
+
cityId,
|
|
188
|
+
setCityId,
|
|
189
|
+
cityText,
|
|
190
|
+
setCityText,
|
|
191
|
+
}: {
|
|
192
|
+
cityId: string | null;
|
|
193
|
+
setCityId: (value: string | null) => void;
|
|
194
|
+
cityText: string;
|
|
195
|
+
setCityText: (value: string) => void;
|
|
196
|
+
}) {
|
|
197
|
+
return (
|
|
198
|
+
<>
|
|
199
|
+
<Select<string>
|
|
200
|
+
label="City record"
|
|
201
|
+
items={cities}
|
|
202
|
+
isSearchable
|
|
203
|
+
value={cityId}
|
|
204
|
+
onChange={setCityId}
|
|
205
|
+
/>
|
|
206
|
+
<Autocomplete
|
|
207
|
+
label="City text"
|
|
208
|
+
items={cities}
|
|
209
|
+
value={cityText}
|
|
210
|
+
onChange={setCityText}
|
|
211
|
+
/>
|
|
212
|
+
</>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Move old ID-valued and multiple Autocomplete usages to Select. Preserve numeric IDs as numbers when the domain uses them. Do not convert IDs to labels in the request DTO merely to satisfy the Autocomplete type.
|
|
218
|
+
|
|
219
|
+
## 6. Replace query selectors with explicit loaders
|
|
220
|
+
|
|
221
|
+
`QuerySelect`, `QueryAutocomplete`, `useQueryAutocomplete`, their query-specific helper types, and the native and TanStack query-selector entries are removed. Remove obsolete `UIConfig.querySelect` and `UIConfig.queryAutocomplete` configuration. `AsyncSelect` is an example name, rather than a replacement public component.
|
|
222
|
+
|
|
223
|
+
Create an independent `useAsyncList` in the component for each independently searchable Select. The application owns API calls, authentication, request mapping, response mapping, and errors. The loader receives `signal`, `filterText`, and `cursor`, and returns `{ items, cursor }`. Return `undefined` or `null` for the final cursor. Forward the abort signal to the request.
|
|
224
|
+
|
|
225
|
+
This example accepts a typed application loader, so it can use the project's existing API client and response validation:
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
import { Select, type SelectItem } from "@povio/ui/select";
|
|
229
|
+
import { useAsyncList } from "@povio/ui/use-async-list";
|
|
230
|
+
|
|
231
|
+
type UserPage = { items: SelectItem<string>[]; cursor?: string };
|
|
232
|
+
type LoadUsers = (request: { search: string; cursor?: string; signal: AbortSignal }) => Promise<UserPage>;
|
|
233
|
+
|
|
234
|
+
export function UserSelect({
|
|
235
|
+
value,
|
|
236
|
+
onChange,
|
|
237
|
+
initialSelection,
|
|
238
|
+
loadUsers,
|
|
239
|
+
}: {
|
|
240
|
+
value: string | null;
|
|
241
|
+
onChange: (value: string | null) => void;
|
|
242
|
+
initialSelection?: SelectItem<string> | null;
|
|
243
|
+
loadUsers: LoadUsers;
|
|
244
|
+
}) {
|
|
245
|
+
const list = useAsyncList<SelectItem<string>>({
|
|
246
|
+
getKey: (item) => item.id,
|
|
247
|
+
load: ({ signal, filterText, cursor }) => loadUsers({ signal, search: filterText ?? "", cursor }),
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<>
|
|
252
|
+
<Select<string>
|
|
253
|
+
label="User"
|
|
254
|
+
list={list}
|
|
255
|
+
isSearchable
|
|
256
|
+
value={value}
|
|
257
|
+
onChange={onChange}
|
|
258
|
+
initialSelection={initialSelection}
|
|
259
|
+
/>
|
|
260
|
+
{list.error && (
|
|
261
|
+
<div role="alert">
|
|
262
|
+
Could not load users.{" "}
|
|
263
|
+
<button
|
|
264
|
+
type="button"
|
|
265
|
+
onClick={() => list.reload()}
|
|
266
|
+
>
|
|
267
|
+
Retry
|
|
268
|
+
</button>
|
|
269
|
+
</div>
|
|
270
|
+
)}
|
|
271
|
+
</>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The hook loads on mount. `Select list={list}` forwards search and load-more interactions, owns loading flags, and disables local filtering of server results. Supply either `list` or `items`. With `list`, omit `isLoading`, `hasLoadMore`, `onLoadMore`, `isClientSearchDisabled`, and `ignoreInputValueFiltering`; these would compete with list state. A bound Select uses the same loader with `field` in place of `value` and `onChange`.
|
|
277
|
+
|
|
278
|
+
React query hooks belong at component or custom-hook scope. Do not invoke them inside the asynchronous `load` callback. Call ordinary API functions or an explicitly obtained query client there.
|
|
279
|
+
|
|
280
|
+
An existing selected ID may be absent from the first page. Supply `initialSelection` with its label, or explicitly resolve and merge selected records into the loaded options. Re-resolve when asynchronous form defaults or a reset change the selected IDs. Preserve those IDs if label loading fails and provide retry; a failed lookup must not silently clear a stored relationship. Carry forward cache and ACL behavior from the removed wrapper.
|
|
281
|
+
|
|
282
|
+
For remotely loaded free-text suggestions, keep `Autocomplete items={list.items}`, forward text changes to both the text owner and `list.setFilterText(text)`, pass `isLoading={list.isLoading}`, and set `isClientSearchDisabled`. Autocomplete has no `list` prop. Render loading errors and retry separately.
|
|
283
|
+
|
|
284
|
+
## 7. Preserve raw form types and parsed output
|
|
285
|
+
|
|
286
|
+
`UIForm<Raw, Output>` and `useForm<Raw, Output>` distinguish editable values from submitted values. Remove the obsolete third generic argument. A schema is required when parsed output differs from input, and passing `zodSchema` can infer both types.
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
import { z } from "zod";
|
|
290
|
+
import { useForm } from "@povio/ui/tanstack/form";
|
|
291
|
+
import { Input } from "@povio/ui/tanstack/input";
|
|
292
|
+
|
|
293
|
+
const quantitySchema = z.object({
|
|
294
|
+
quantity: z.string().regex(/^\d+$/, "Enter a whole number").transform(Number),
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
export function QuantityForm({ onSave }: { onSave: (values: z.output<typeof quantitySchema>) => Promise<void> }) {
|
|
298
|
+
const form = useForm({ zodSchema: quantitySchema, defaultValues: { quantity: "1" } });
|
|
299
|
+
// Raw setters and resets receive strings; successful submission receives a number.
|
|
300
|
+
return (
|
|
301
|
+
<form onSubmit={form.handleSubmit(onSave)}>
|
|
302
|
+
<Input
|
|
303
|
+
label="Quantity"
|
|
304
|
+
field={{ form, name: "quantity" }}
|
|
305
|
+
/>
|
|
306
|
+
<button type="submit">Save</button>
|
|
307
|
+
</form>
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Keep field names and bound values in the raw input shape. Use parsed output for API submission. Do not change the input component to a number-valued control just because a transform produces a number; either keep the raw string binding or intentionally change the schema's input contract.
|
|
313
|
+
|
|
314
|
+
### Reset and autosave
|
|
315
|
+
|
|
316
|
+
`defaultValues` establishes initial values. Changing that prop after mount does not replace current form values. Use `form.reset(rawValues)` for an intentional reset; it establishes the new baseline and clears dirty/touched state under the default reset behavior. Initial asynchronous defaults preserve edits made while loading and are ignored after a newer reset supersedes them.
|
|
317
|
+
|
|
318
|
+
For forms that save and refresh server data, use `useFormAutosave` with `getResetValues`, `resetDeps`, and `onAutosave`. Include the server record or revision that changes after saving in `resetDeps`. Convert server output back to raw editable values in `getResetValues`.
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import { useFormAutosave, type AutosavePatch } from "@povio/ui/tanstack/form";
|
|
322
|
+
import { Input } from "@povio/ui/tanstack/input";
|
|
323
|
+
|
|
324
|
+
type Settings = { name: string };
|
|
325
|
+
|
|
326
|
+
export function SettingsForm({
|
|
327
|
+
record,
|
|
328
|
+
onSave,
|
|
329
|
+
}: {
|
|
330
|
+
record: Settings;
|
|
331
|
+
onSave: (patch: AutosavePatch<Settings>) => Promise<void>;
|
|
332
|
+
}) {
|
|
333
|
+
const form = useFormAutosave<Settings>({
|
|
334
|
+
getResetValues: () => record,
|
|
335
|
+
resetDeps: [record],
|
|
336
|
+
onAutosave: onSave,
|
|
337
|
+
autosaveOn: "change",
|
|
338
|
+
});
|
|
339
|
+
return (
|
|
340
|
+
<Input
|
|
341
|
+
label="Name"
|
|
342
|
+
field={{ form, name: "name" }}
|
|
343
|
+
/>
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The save callback must update or invalidate the source of `record` so refreshed server data reaches the hook. Use `useAutosave({ form, onSave, ... })` when you manage refresh/reset separately. Public `AutosavePatch`, `AutosaveHandler`, and hook prop types are exported from the form entry.
|
|
349
|
+
|
|
350
|
+
Autosave schemas must preserve all raw field paths, including optional fields. Transforms can change a value's type at the same path; renaming or removing a path prevents reliable patch projection. Use an explicit submission/mapping strategy for those transformations instead.
|
|
351
|
+
|
|
352
|
+
Clears and removals now remain in patches, including `null` and `undefined`. Arrays and dates are treated as whole values. Ensure the API serializer represents the intended deletion: JSON omits `undefined`, so a wire contract may require `null` or a separate deletion operation. Do not strip clears with truthiness checks or a generic “remove empty values” helper.
|
|
353
|
+
|
|
354
|
+
An explicit reset cancels pending saves and rebases autosave. Disable/unmount cancels queued work. Refreshes after a save preserve edits made during the request; do not add a separate unconditional reset effect that overwrites them. A refresh timeout logs a warning rather than throwing; fix missing refresh dependencies or invalidation instead of treating the warning as a successful refresh.
|
|
355
|
+
|
|
356
|
+
## 8. Migrate upload values without losing attachment IDs
|
|
357
|
+
|
|
358
|
+
`multiple` is now a supported alias for `allowsMultiple` on FileInput and FileUpload. Either `multiple={true}` or `allowsMultiple={true}` enables multiple files; both true is also valid. Opposing flags are rejected. Single mode accepts nullable values; multiple mode uses `[]` for empty values.
|
|
359
|
+
|
|
360
|
+
FileUpload applies single mode to drag-and-drop as well as browsing: after filtering accepted file types, only the first accepted dropped file is selected and uploaded. Extra accepted files are ignored before callbacks or transfers. Enable multiple mode explicitly when every accepted file should be processed.
|
|
361
|
+
|
|
362
|
+
| Usage | Value/default contract | Change callback |
|
|
363
|
+
| ----------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
364
|
+
| Standalone `FileInput` | `File \| null`, or `File[]` in multiple mode | Native file(s) |
|
|
365
|
+
| Bound `FileInput` | Raw form field containing native file(s) | Optional `field.onValueChange` receives file(s) |
|
|
366
|
+
| Bound `FileUpload` | Raw form field containing `File \| null` or `File[]` | Optional `field.onValueChange` receives file(s) |
|
|
367
|
+
| Standalone `FileUpload` | `value`: `FileUploadState[] \| null` in single mode, `FileUploadState[]` in multiple mode | Native `File \| null` or `File[]`, rather than lifecycle records |
|
|
368
|
+
|
|
369
|
+
Standalone FileUpload is not a symmetric `value`/`onChange` metadata editor. Its `value` describes displayed upload lifecycle state. `defaultValue` initializes native files; `defaultState` initializes metadata for existing uploads. A supplied `value`, including `null`, takes precedence over defaults. Bound uploads get defaults from their form and reject `defaultState`.
|
|
370
|
+
|
|
371
|
+
Keep server attachment DTOs separate from browser files. `fileUpload(request, file, options)` returns a promise resolving to `{ id }`; `fileRemove({ id })` removes a server upload. Forward `options.abortController?.signal` and report progress through `options.onUploadProgress` in the application adapter. Capture returned IDs when constructing attachment payloads.
|
|
372
|
+
|
|
373
|
+
The upload callback must complete the actual file transfer before returning `{ id }`. Requesting upload instructions only reserves the upload; it does not send the file bytes. Follow the returned method, URL, and form fields, and reject failed HTTP responses so the control displays an error instead of marking the file uploaded. Pass only the generated mutation's supported request arguments; send the native `File` to the storage endpoint, not as an extra argument to the instructions mutation.
|
|
374
|
+
|
|
375
|
+
When migrating application adapters such as RocketMediaForm, send POST uploads as FormData with signed fields before the file, and PUT uploads as the raw file body. A resolved `fetch` does not imply HTTP success. Check transfer status and cancellation before publishing an attachment ID or preview, and forward upload progress when the transport supports it. The generated instructions mutation cannot cancel negotiation; check the supplied abort signal again after it resolves and before starting the transfer. The template's frontend adapter and current Storybook S3 guide demonstrate this flow.
|
|
376
|
+
|
|
377
|
+
FileUpload catches thrown or rejected upload callbacks and displays their message through its accessible field error, with a localized fallback when no message is available. A supplied `error` prop takes precedence. Failed files are removed from the selection while successful uploads in the same batch remain. Cancellation and stale completions stay quiet; a new attempt or external reset/replacement clears the internal upload error. Applications can still supply their own validation or upload feedback through `error`.
|
|
378
|
+
|
|
379
|
+
If a form field stores `{ id: string }`, use a standalone FileUpload with explicit application callbacks that update that attachment field. Do not bind it directly as if `{ id }` were a native File. Preserve existing attachment display metadata independently, and clear the attachment DTO when the user removes it.
|
|
380
|
+
|
|
381
|
+
Reset/cancel/replacement now protects the component from stale upload completion and progress. Application callbacks that write attachment IDs should also respect cancellation and the currently edited record; component safeguards cannot undo an unrelated application mutation.
|
|
382
|
+
|
|
383
|
+
## 9. Make date and time formats explicit
|
|
384
|
+
|
|
385
|
+
Remove `fullIso` from both standalone and bound DateTimePicker and TimePicker. It was unsupported and had no effect. Keep it on DatePicker and DateRangePicker when choosing their output format.
|
|
386
|
+
|
|
387
|
+
| Component | Output format | Empty value |
|
|
388
|
+
| ----------------------------------------- | --------------------------------------------------------------------------- | ----------- |
|
|
389
|
+
| `DatePicker`, default `fullIso=true` | UTC calendar date at `YYYY-MM-DDT00:00:00.000Z` | `null` |
|
|
390
|
+
| `DatePicker`, `fullIso=false` | `YYYY-MM-DD` | `null` |
|
|
391
|
+
| `DateRangePicker`, default `fullIso=true` | `{ start, end }`: UTC midnight start and UTC `23:59:59.999Z` end, inclusive | `null` |
|
|
392
|
+
| `DateRangePicker`, `fullIso=false` | `{ start, end }` containing `YYYY-MM-DD` endpoints | `null` |
|
|
393
|
+
| `DateTimePicker` | Full UTC ISO timestamp with milliseconds and `Z` | `null` |
|
|
394
|
+
| `TimePicker` | Full UTC ISO timestamp with milliseconds and `Z`, including its anchor date | `null` |
|
|
395
|
+
|
|
396
|
+
Date-only controls use UTC calendar fields to interpret timestamp inputs. Month granularity normalizes to the first of the month, and year granularity to January 1. Partial date ranges emit `null` unless `allowPartialRange` is enabled; with that option, a missing endpoint is `null`. Relative range mode emits a preset key through `onRelativeChange` and a resolved range through `onChange`. Clearing or switching modes resets both values.
|
|
397
|
+
|
|
398
|
+
DateTimePicker and TimePicker display/edit in `timeZone`, falling back to `UIConfig.dateInput.timeZone`, whose default is `"clientLocal"`. Output remains UTC. Display `format` and locale do not change the wire value. DateTimePicker's `isTimeOptional` completes a date with midnight in the effective zone when time is omitted.
|
|
399
|
+
|
|
400
|
+
TimePicker is not an `HH:mm` control. Its `date` anchor is parsed as a JavaScript Date instant and converted into the effective zone before replacing clock fields. Use a timestamp with an explicit offset or `Z`. Without an anchor, edits use today in that zone, even when the supplied value contains another date. Changing `date` after the editable input mounts re-emits the current clock time on the new anchor.
|
|
401
|
+
|
|
402
|
+
For example, `date="2025-03-04T00:00:00.000Z"` is March 3 in `America/Los_Angeles`. Entering 10:30 emits `2025-03-03T18:30:00.000Z`. Choose the anchor to represent the intended local day, and check daylight-saving transitions in the application's supported zones.
|
|
403
|
+
|
|
404
|
+
The removal of unsupported props does not require converting stored timestamps. If an API expects only clock text, map the full timestamp explicitly using the intended zone. If an API expects a calendar date, use DatePicker's date-only mode or an explicit domain conversion. Match request validation to the actual returned format. See [Date and time values](README.md#date-and-time-values) for examples.
|
|
405
|
+
|
|
406
|
+
## 10. Replace the admin page builder with domain components
|
|
407
|
+
|
|
408
|
+
Remove the shared page builder, `usePageBuilder`, dynamic page definitions, domain `*PageConfig(s)` wrappers, and generated `builderConfigs` outputs. Remove only the corresponding code-generation step; keep generated API clients, request/response schemas, and query hooks.
|
|
409
|
+
|
|
410
|
+
For each page, carry the old configuration's behavior into explicit components:
|
|
411
|
+
|
|
412
|
+
1. Render domain filters with standalone inputs, Select, and date controls.
|
|
413
|
+
2. Define typed columns, action cells, and stable row IDs.
|
|
414
|
+
3. Call existing domain query/mutation APIs from the page or its hooks.
|
|
415
|
+
4. Render domain create/edit forms and view dialogs explicitly.
|
|
416
|
+
5. Retain permission checks, translations, tabs, selected-record state, and query invalidation.
|
|
417
|
+
|
|
418
|
+
Keep small shared presentation components such as `QueryFeedback`, `EmptyResults`, and the `normalizeFilter` helper. Preserve the distinction between an empty dataset and a filtered search with no matches. When a refresh fails, keep cached rows visible and show the error with retry.
|
|
419
|
+
|
|
420
|
+
Keep filters, sorting, page size, and pagination in the established URL state. Use the existing routing serialization helpers; avoid adding another JSON encoding layer around arrays, objects, or quoted strings. Routing serialization was corrected to avoid double encoding.
|
|
421
|
+
|
|
422
|
+
The explicit examples in this repository include `apps/admin/src/components/rockets/RocketsPage.tsx`, its `filters/` and `tables/` siblings, and frontend `apps/fe/src/components/rockets/RocketFilters.tsx` and `RocketsTable.tsx`. Existing application code can contain workspace-only table aliases; use the public `row.original` pattern above when creating portable examples.
|
|
423
|
+
|
|
424
|
+
## 11. Check pagination boundaries
|
|
425
|
+
|
|
426
|
+
TanStack table state and every `usePagination` input/output use zero-based `pageIndex`: the first page is `0`. The hook now defaults to `{ pageIndex: 0, pageSize: 20 }`. The standalone Pagination component's `page` is one-based. PaginatedTable converts between them and resets the index to zero when page size changes.
|
|
427
|
+
|
|
428
|
+
Page sizes must be positive safe integers. The built-in page-size editor constrains numeric edits and only calls `onPageSizeChange` with a valid size; clearing it no longer emits `0` or resets pagination. Keep the same validation on application-owned page-size inputs, programmatic state, and API parameters.
|
|
429
|
+
|
|
430
|
+
The URL remains one-based: `?page=2` initializes `pageIndex: 1`. The hook writes index `1` back as `page=2`, omits `page` for the first page, and omits `size` for the default size of `20`. Other query parameters are preserved. Invalid page or size values fall back to the default for that field; URL values must be positive safe whole integers.
|
|
431
|
+
|
|
432
|
+
Change explicit first-page defaults from `usePagination({ pageIndex: 1, ... })` to `pageIndex: 0`. An explicitly supplied default state still takes precedence over URL initialization. Without it, the hook reads the URL when mounted; it does not rehydrate its state on later URL changes.
|
|
433
|
+
|
|
434
|
+
Remove compensating offsets that were added around the old behavior. Apply a conversion exactly once at each boundary:
|
|
435
|
+
|
|
436
|
+
```text
|
|
437
|
+
Table state pageIndex 0 → visible page 1
|
|
438
|
+
Table state pageIndex 1 → visible page 2
|
|
439
|
+
One-based server API page = pageIndex + 1
|
|
440
|
+
One-based pager selection → table pageIndex = page - 1
|
|
441
|
+
URL page 2 ↔ table pageIndex 1
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
For local data, replace `(pageIndex - 1) * pageSize` with `pageIndex * pageSize`. Pass that slice to PaginatedTable; the component displays the rows you supply:
|
|
445
|
+
|
|
446
|
+
```tsx
|
|
447
|
+
import { PaginatedTable, type TableProps, usePagination } from "@povio/ui/tanstack/table";
|
|
448
|
+
|
|
449
|
+
type Result = { id: string; name: string };
|
|
450
|
+
const columns: TableProps<Result>["columns"] = [
|
|
451
|
+
{ accessorKey: "name", header: "Name", cell: ({ row }) => row.original.name },
|
|
452
|
+
];
|
|
453
|
+
|
|
454
|
+
export function LocalResults({ rows }: { rows: Result[] }) {
|
|
455
|
+
const { pagination, setPagination } = usePagination();
|
|
456
|
+
const start = pagination.pageIndex * pagination.pageSize;
|
|
457
|
+
return (
|
|
458
|
+
<PaginatedTable
|
|
459
|
+
items={rows.slice(start, start + pagination.pageSize)}
|
|
460
|
+
columns={columns}
|
|
461
|
+
totalItems={rows.length}
|
|
462
|
+
pagination={pagination}
|
|
463
|
+
setPagination={setPagination}
|
|
464
|
+
/>
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
When connecting `usePagination` directly to a standalone Pagination, pass `page={pageIndex + 1}` and convert `onPageChange` back with `pageIndex: page - 1`. A jump-to-page input also shows one-based page numbers. For nonempty results, row ranges start at `pageIndex * pageSize + 1` and end at `Math.min((pageIndex + 1) * pageSize, totalItems)`. Set `pageIndex: 0` when changing page size manually; PaginatedTable already does this for its own pager.
|
|
470
|
+
|
|
471
|
+
Check the server API's actual convention before converting its page number. PaginatedTable includes its pager; avoid adding a second one. InfiniteTable remains available for incremental loading; an application-owned API page/cursor is separate from `usePagination` state and retains the API's convention. Check first-page loading, navigation, page-size resets, and reloading a `?page=2` URL so offsets are applied exactly once.
|
|
472
|
+
|
|
473
|
+
## 12. Preserve accessibility while replacing layouts
|
|
474
|
+
|
|
475
|
+
Every field needs an accessible name. Keep visible `label` props or an appropriate supported `aria-label`/`aria-labelledby`. A placeholder does not replace a label. Hiding a visual label must retain the accessible name.
|
|
476
|
+
|
|
477
|
+
Preserve helper text and visible validation errors, including filter and inline layouts. Use the component's error props so helper/error associations reach the input. Avoid recreating only a tooltip or a red border. Keep caller-provided `aria-describedby` associations when adding extra context.
|
|
478
|
+
|
|
479
|
+
Give Dialog an explicit accessible name, preferably `aria-labelledby` pointing to a visible heading, or `aria-label`. AlertDialog associates its heading automatically and honors explicit names. Supply Popover's `sheetLabel` to name its overlay. Keep date/time labels and unique input IDs when rendering repeated fields.
|
|
480
|
+
|
|
481
|
+
Check keyboard focus through static-to-editable input handoff, selection, clear actions, and overlay close. Disabled controls must remain unfocusable. An actual blur side effect must run once on focus loss, rather than on every selection commit. Avoid application focus effects that fight the component's focus restoration.
|
|
482
|
+
|
|
483
|
+
## 13. Choose buttons by behavior
|
|
484
|
+
|
|
485
|
+
The web `TextButton` and `InlineIconButton` components and their prop types (`TextButtonProps`, `InlineIconButtonProps`) are removed. Their `@povio/ui/text-button` and `@povio/ui/inline-icon-button` package entries and barrel exports are removed too. Replace their imports and usages, including shared wrappers, stories, and generated code. React Native buttons are unaffected.
|
|
486
|
+
|
|
487
|
+
| Meaning | Component and import | Contract |
|
|
488
|
+
| ------------------------------------ | --------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
489
|
+
| Action with visible text | `Button` from `@povio/ui/button` | `children` is the visible label; icons are optional |
|
|
490
|
+
| Action displayed only as an icon | `IconButton` from `@povio/ui/icon-button` | Required `icon` and accessible name, normally `label` |
|
|
491
|
+
| Persistent selected/unselected state | `ToggleButton` from `@povio/ui/toggle-button` | `isSelected`/`defaultSelected` and `onChange`; supports `iconOnly` for selected icon actions |
|
|
492
|
+
| Primary action and separate menu | `SplitButton` from `@povio/ui/split-button` | Keep the existing action and menu props |
|
|
493
|
+
|
|
494
|
+
`BadgeButton` remains available for interactive badge presentations and retains its existing `toggle`/selection contract. Do not migrate a status badge to an action button merely because the two share a shape. Noninteractive statuses should retain their existing status component.
|
|
495
|
+
|
|
496
|
+
The cleanup changes component selection, while preserving design, colors, spacing, variants, and sizes. `Button`, `IconButton`, `ToggleButton`, and `SplitButton` keep `sm` (including alias `s`), `default`, and `none`. The default remains `default`; the removed InlineIconButton wrapper used `sm`, which must be explicit in its replacement. Keep custom icon dimensions, classes, inverted colors, link targets, event handlers, and refs.
|
|
497
|
+
|
|
498
|
+
Use these replacements, preserving explicit sizes and widths:
|
|
499
|
+
|
|
500
|
+
```text
|
|
501
|
+
Before: <TextButton>Cancel</TextButton>
|
|
502
|
+
After: <Button variant="text" width="hug">Cancel</Button>
|
|
503
|
+
|
|
504
|
+
Before: <TextButton width="fill" size="none">Read more</TextButton>
|
|
505
|
+
After: <Button variant="text" width="fill" size="none">Read more</Button>
|
|
506
|
+
|
|
507
|
+
Before: <InlineIconButton icon={CloseIcon} label="Close" />
|
|
508
|
+
After: <IconButton variant="text" size="sm" width="hug" disableTooltip icon={CloseIcon} label="Close" />
|
|
509
|
+
|
|
510
|
+
Before: <InlineIconButton size="none" icon={CloseIcon} label="Close" />
|
|
511
|
+
After: <IconButton variant="text" size="none" width="hug" disableTooltip icon={CloseIcon} label="Close" />
|
|
512
|
+
|
|
513
|
+
Before: <Button iconOnly icon={CloseIcon}>Close</Button>
|
|
514
|
+
After: <IconButton icon={CloseIcon} label="Close" disableTooltip />
|
|
515
|
+
|
|
516
|
+
Before: <Button toggle variant="contained" isSelected={enabled} onChange={setEnabled}>Enabled</Button>
|
|
517
|
+
After: <ToggleButton variant="contained" isSelected={enabled} onChange={setEnabled}>Enabled</ToggleButton>
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
`TextButton iconOnly` was a text-styled icon action with default button sizing. Replace it with `IconButton variant="text" width="hug" disableTooltip` and turn its children into `label`; retain its original size rather than adding the InlineIconButton `sm` default.
|
|
521
|
+
|
|
522
|
+
`Button` rejects `iconOnly`, `toggle`, and selection props, including when their values are false. Remove `iconOnly={false}`/`toggle={false}` from ordinary actions. `Button` and `ButtonProps` no longer take an `IconOnly` generic argument. For a selected icon action, use `ToggleButton iconOnly` with an icon and preserve its accessible label and original appearance. Retain any original `variant`, `size`, or `width` when moving an existing Button to another behavior component. When the original `Button toggle` omitted its variant, preserve the effective configured Button variant explicitly: ToggleButton has historically defaulted to `outlined`, whereas the default Button configuration is `contained`.
|
|
523
|
+
|
|
524
|
+
An IconButton needs an accessible name through `label`, `ariaLabel`, `aria-label`, or `aria-labelledby`. `label` is the usual choice and supplies the tooltip text. Put an old Button's hidden children into that name; do not discard them. For complex label markup, provide equivalent name text or use `aria-labelledby` to reference a label element. IconButton shows a tooltip by default; `disableTooltip` preserves the former InlineIconButton and `Button iconOnly` behavior, including existing outer tooltips and their placements/delays. An external `aria-labelledby` names the button but does not supply tooltip text, so supply `label` too when a tooltip is desired.
|
|
525
|
+
|
|
526
|
+
If a shared wrapper spreads caller props, apply overridable defaults such as `size="sm"` before the spread. Apply the former InlineIconButton forced appearance (`variant="text"`, `width="hug"`, and `disableTooltip`) after the spread. Its old `disableTooltip={false}` never enabled a tooltip, so keep tooltip behavior explicit. The date-input configuration value `todayIconButtonComponent="inlineIconButton"` remains supported as an appearance preset; it does not refer to a package import and does not need renaming.
|
|
527
|
+
|
|
528
|
+
Loading and icon props were not renamed. Keep the supported `loading`/`isLoading`, `icon`/`iconPosition`, `startIcon`/`endIcon`, and width aliases on components that expose them. Do not perform an unrelated prop rename, introduce a new shape API, or change theme tokens as part of this migration.
|
|
529
|
+
|
|
530
|
+
## 14. Migrate palette roles
|
|
531
|
+
|
|
532
|
+
Palette names now describe content emphasis, recessed surfaces, status treatments, and fixed colors. Rename definitions and usages together: CSS custom properties, Tailwind `--color-*` aliases, component classes, state utilities, inline variable references, presets, and saved CSS/override exports. The template's web and native consumers use the new names. Old public token names are not retained as aliases.
|
|
533
|
+
|
|
534
|
+
Replace older example classes such as `text-text-default-1`, `text-text-default-2`, and `text-text-error-1` with `text-content-primary`, `text-content-secondary`, and `text-status-destructive-accent`. The old `bg-elevation-fill-*` and `interactive-contained-*` roles have no current aliases and generate no CSS. Choose card or sunken surfaces by purpose, and let custom option content inherit its parent's hover, focus, and selected text colors instead of hardcoding a foreground for every selection mode. The template resets Tailwind's default color palette; use the semantic theme roles rather than assuming classes such as `bg-gray-100` are available.
|
|
535
|
+
|
|
536
|
+
These are naming changes. Keep the existing RGB/hex values, alpha values, light/dark mappings, state mixes, and contrast relationships. Do not replace a palette role with a fixed color merely because they look similar in one mode.
|
|
537
|
+
|
|
538
|
+
### Content emphasis and recessed surfaces
|
|
539
|
+
|
|
540
|
+
| Previous token | Canonical token | Use |
|
|
541
|
+
| ------------------------------------- | ---------------------------- | ----------------------------------------- |
|
|
542
|
+
| `surface-default-card-foreground` | `content-primary` | Main text and prominent icons |
|
|
543
|
+
| `surface-default-foreground` | `content-secondary` | Descriptions and supporting text |
|
|
544
|
+
| `surface-default-popover-foreground` | `content-muted` | Low-emphasis content and placeholders |
|
|
545
|
+
| `surface-inverted-card-foreground` | `content-inverted-primary` | Main content on an inverted surface |
|
|
546
|
+
| `surface-inverted-foreground` | `content-inverted-secondary` | Supporting content on an inverted surface |
|
|
547
|
+
| `surface-inverted-popover-foreground` | `content-inverted-muted` | Muted content on an inverted surface |
|
|
548
|
+
| `surface-default-popover` | `surface-default-sunken` | Filled inputs and recessed content areas |
|
|
549
|
+
| `surface-inverted-popover` | `surface-inverted-sunken` | Recessed areas in an inverted treatment |
|
|
550
|
+
| `support-default` | `fixed-black` | Invariant black in both modes |
|
|
551
|
+
| `support-inverted` | `fixed-white` | Invariant white in both modes |
|
|
552
|
+
|
|
553
|
+
For example, `text-surface-default-card-foreground` becomes `text-content-primary`, and `bg-surface-default-popover` becomes `bg-surface-default-sunken`. A popover still uses the card surface: `bg-surface-default-card`. The former popover name described a recessed treatment rather than the Popover component's background.
|
|
554
|
+
|
|
555
|
+
Raw web variables retain their value representation: `--surface-default-card-foreground-base` becomes `--content-primary-base`, and `--color-surface-default-card-foreground` becomes `--color-content-primary`. Native themes use the same canonical roles without the web `-base` suffix. The native generator accepts legacy Atlas export names and normalizes both declarations and `var()` references to the canonical names.
|
|
556
|
+
|
|
557
|
+
### Status pairs and accents
|
|
558
|
+
|
|
559
|
+
For each of `success`, `warning`, and `destructive`, choose a complete treatment:
|
|
560
|
+
|
|
561
|
+
| Role | Color token | Existing value |
|
|
562
|
+
| ----------------------------------------- | ---------------------------- | -------------------------------------- |
|
|
563
|
+
| Contained background | `status-*-background` | Former `surface-*-base` |
|
|
564
|
+
| Content on contained background | `status-*-foreground` | Former `surface-*-inverted-base` |
|
|
565
|
+
| Subtle background | `status-*-subtle-background` | Existing subtle status treatment |
|
|
566
|
+
| Content on subtle background | `status-*-subtle-foreground` | Existing subtle status treatment |
|
|
567
|
+
| Standalone status text, icons, or borders | `status-*-accent` | Same value as the contained background |
|
|
568
|
+
|
|
569
|
+
Before/after examples preserve the existing colors:
|
|
570
|
+
|
|
571
|
+
```text
|
|
572
|
+
Contained success:
|
|
573
|
+
Before: bg-surface-success-base text-surface-success-inverted-base
|
|
574
|
+
After: bg-status-success-background text-status-success-foreground
|
|
575
|
+
|
|
576
|
+
Subtle success:
|
|
577
|
+
Before: bg-surface-success-inverted-base text-surface-success-base
|
|
578
|
+
After: bg-status-success-subtle-background text-status-success-subtle-foreground
|
|
579
|
+
|
|
580
|
+
Standalone error text:
|
|
581
|
+
Before: text-surface-destructive-base
|
|
582
|
+
After: text-status-destructive-accent
|
|
583
|
+
|
|
584
|
+
Status border:
|
|
585
|
+
Before: border-surface-warning-base
|
|
586
|
+
After: border-status-warning-accent
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
Success and warning subtle treatments reverse their existing contained pair. Destructive subtle treatments keep the existing `interactive-subtle-destructive-background` and `interactive-subtle-destructive-foreground` values. They do not reverse the contained destructive pair. In particular, old standalone error text maps to `status-destructive-accent`, not `status-destructive-subtle-foreground`; those colors differ in the light theme. Destructive action buttons retain their `interactive-*` roles.
|
|
590
|
+
|
|
591
|
+
Use the element's purpose when replacing status tokens. A tooltip pointer matching a contained status surface uses `status-*-background`; an independent status icon uses `status-*-accent`. A text replacement cannot be inferred solely from a shared old variable name. Raw web variables also lose the old doubled suffix: `--surface-success-base-base` becomes `--status-success-background-base`, while `--surface-success-inverted-base-base` becomes `--status-success-foreground-base`.
|
|
592
|
+
|
|
593
|
+
### Custom layouts and states
|
|
594
|
+
|
|
595
|
+
The template resets Tailwind's radius namespace as well as its color palette. Use defined theme utilities for custom layouts: replace bare `rounded` with `rounded-global-rounding-xs` (0.25rem), `rounded-md` with `rounded-global-rounding-s` (0.375rem), and `rounded-lg` with `rounded-global-rounding-m` (0.5rem). These replacements retain the conventional intended dimensions without restoring Tailwind defaults or changing theme values. Keep existing supported radius tokens and arbitrary values. A Table `variant="rounded"` is a component variant, not a CSS utility, and does not need this replacement.
|
|
596
|
+
|
|
597
|
+
```tsx
|
|
598
|
+
export function AccountPanel() {
|
|
599
|
+
return (
|
|
600
|
+
<section className="rounded-m border border-border-default-subtle bg-surface-default-card p-4 text-content-primary">
|
|
601
|
+
<h2>Account</h2>
|
|
602
|
+
<p className="text-content-secondary">Manage your details.</p>
|
|
603
|
+
<div className="bg-surface-default-sunken p-2">
|
|
604
|
+
<span className="text-content-muted">Optional settings</span>
|
|
605
|
+
</div>
|
|
606
|
+
<p className="text-status-success-accent">Changes saved.</p>
|
|
607
|
+
</section>
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
Keep the existing `surface-default-background`, `surface-default-card`, border, interactive action, focus ring, and overlay families. Semantic roles continue adapting to dark mode automatically. Use `fixed-white` or `fixed-black` only for content that must remain that literal color; do not change existing mode-aware content to a fixed color during the rename.
|
|
613
|
+
|
|
614
|
+
State utilities keep their syntax and mix values. For example, `hover:bg-state-surface-default-popover/hover` becomes `hover:bg-state-surface-default-sunken/hover`. The state remains `/hover`; selected action recipes retain `/toggled`, `/toggled-hovered`, and `/toggled-disabled`. These mixes do not guarantee a visible change against every base surface, so this migration does not introduce a new hover treatment for white cards.
|
|
615
|
+
|
|
616
|
+
Migrate app-owned exported themes and saved override strings before loading them. Search for old names after migration, allowing references in this guide, historical changelogs, and legacy generator input fixtures. Verify the rendered colors in both modes, including status accents versus subtle foregrounds. If a web Figma export still uses the old vocabulary, apply this mapping before replacing the template theme; the native generator already performs that normalization.
|
|
617
|
+
|
|
618
|
+
## 15. Validate each migrated feature
|
|
619
|
+
|
|
620
|
+
Use the application's normal typecheck, lint, and build commands. For table examples, also compile against the built package declarations so workspace augmentations cannot hide incompatible cell props. In this repository, `bun run test:table-examples` in `packages/ui` runs that focused check after `lib:build`.
|
|
621
|
+
|
|
622
|
+
Add or retain focused regression coverage for changed behavior:
|
|
623
|
+
|
|
624
|
+
- Forms: invalid input shows a visible associated error; successful submission receives parsed values; raw setters/reset values remain correctly typed.
|
|
625
|
+
- Bound controls: only the form owns values; interaction callbacks get native values; setters and resets do not fire them.
|
|
626
|
+
- Autosave: clearing a field sends the intended deletion; resetting cancels queued work; an edit made during save/refetch survives; refresh does not trigger an unintended save.
|
|
627
|
+
- Selection: searchable Select saves IDs, multiple Select clears to `[]`, and Autocomplete saves free text and clears to `""`.
|
|
628
|
+
- Loading: searching and loading the next cursor work; the final page stops loading; aborts do not restore old results; failed selected-label lookup preserves IDs and offers retry.
|
|
629
|
+
- Uploads: both multiple aliases work; single clearing produces `null`; multiple clearing produces `[]`; stale completion cannot replace a newer selection or attachment.
|
|
630
|
+
- Dates: outputs match the table above; range end is inclusive when using full ISO; time anchors and zone changes preserve the intended domain date/time.
|
|
631
|
+
- Tables/pages: the first and second pages request the expected rows; page size resets pagination; cached data survives refresh errors; filters and sort survive URL reload.
|
|
632
|
+
- Buttons: ordinary actions remain actions; selected actions retain their state and callbacks; icon actions have accessible names; loading prevents activation; links keep their targets; wrapper replacements retain sizes and existing tooltip behavior.
|
|
633
|
+
- Accessibility: labels, helper/error associations, keyboard operation, overlay names, and focus restoration work in the layouts the application uses.
|
|
634
|
+
|
|
635
|
+
Search again for removed entries and competing bound props before finishing. Review generated output as well as its generator so obsolete imports do not return on the next code-generation run.
|
|
636
|
+
|
|
637
|
+
## Removed AI instruction files
|
|
638
|
+
|
|
639
|
+
The old Povio UI rules, their generation command, rulesync configuration, and package distribution tooling for those instructions were removed. Remove obsolete references or copied UI instruction files from downstream projects. Keep unrelated project rules. Do not copy the old UI rules back or add a new automatic rule installation step as part of this migration.
|
|
640
|
+
|
|
641
|
+
Use public component types, this guide, the [README](README.md), and explicit examples to determine the current API. New AI instructions can be introduced separately after the API contracts are settled.
|
|
642
|
+
|
|
643
|
+
## Move development tools to @povio/ui-configurator
|
|
644
|
+
|
|
645
|
+
Install `@povio/ui-configurator` as a development dependency. Replace imports from `@povio/ui/ui-configurator` with `@povio/ui-configurator` (including `/vite`, `/theme`, and `/styles`), and `@povio/ui/app-canvas` with `@povio/ui-configurator/app-canvas` (including `/tanstack` and `/styles`). Add the new package to Tailwind's `@source` paths. These entries are no longer published by `@povio/ui`.
|