@ryuzaki13/react-foundation-ui 1.8.10 → 1.8.12
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/dist/advanced-search/index.js +1 -1
- package/dist/chunks/{defaultRenderers-Dbhg2hHc.js → defaultRenderers-u_Vep6Pj.js} +2 -2
- package/dist/chunks/defaultRenderers-u_Vep6Pj.js.map +1 -0
- package/dist/chunks/{multi-select-CHZhWoq6.js → multi-select-DtmRtX6v.js} +2 -2
- package/dist/chunks/multi-select-DtmRtX6v.js.map +1 -0
- package/dist/chunks/select-MN6zDPKM.js.map +1 -1
- package/dist/chunks/useODataSelectBase-DR4PrY1j.js.map +1 -1
- package/dist/multi-select/index.js +1 -1
- package/dist/multi-select/model/useODataMultiSelect.d.ts +1 -1
- package/dist/multi-select/model/useODataMultiSelect.d.ts.map +1 -1
- package/dist/multi-select/ui/MultiSelect.d.ts +2 -2
- package/dist/multi-select/ui/MultiSelect.d.ts.map +1 -1
- package/dist/multi-select/ui/SerializableMultiSelect.d.ts.map +1 -1
- package/dist/multi-select/ui/defaultRenderers.d.ts +2 -2
- package/dist/multi-select/ui/defaultRenderers.d.ts.map +1 -1
- package/dist/select/model/useODataSelect.d.ts +1 -1
- package/dist/select/model/useODataSelect.d.ts.map +1 -1
- package/dist/select/model/useODataSelectBase.d.ts +1 -1
- package/dist/select/model/useODataSelectBase.d.ts.map +1 -1
- package/dist/tree-select/index.js +1 -1
- package/dist/tree-select/index.js.map +1 -1
- package/dist/tree-select/model/buildODataTreeNodes.d.ts +1 -1
- package/dist/tree-select/model/buildODataTreeNodes.d.ts.map +1 -1
- package/package.json +3 -3
- package/storybook-static/assets/{Badge-BqQpQw_L.js → Badge-CveIo2LZ.js} +1 -1
- package/storybook-static/assets/{Badge.stories-BLEc3pho.js → Badge.stories-Bd8M64xJ.js} +1 -1
- package/storybook-static/assets/{BadgeList-DfMo6yit.js → BadgeList-xT41a0VL.js} +1 -1
- package/storybook-static/assets/{Button-D1w_se49.js → Button-C5bBSb3k.js} +1 -1
- package/storybook-static/assets/{Button-D6MwkfU8.js → Button-DkDgfpHL.js} +1 -1
- package/storybook-static/assets/{Button.stories-DsEGxbz-.js → Button.stories-CeKPeGK5.js} +1 -1
- package/storybook-static/assets/{CalendarView-FWwbhHMn.js → CalendarView-CEqcrblx.js} +1 -1
- package/storybook-static/assets/{CheckBox-BIeKlLsQ.js → CheckBox-DKeFkdOt.js} +1 -1
- package/storybook-static/assets/{CheckBox-krtKLFK6.js → CheckBox-OVvAarW-.js} +1 -1
- package/storybook-static/assets/{CheckBox.stories-gV23d8F9.js → CheckBox.stories-CfZ0p1yo.js} +1 -1
- package/storybook-static/assets/{Color-6AOWCN3U-DF3lA8Cg.js → Color-6AOWCN3U-BWW7zrfs.js} +1 -1
- package/storybook-static/assets/{ContextMenu-Jid_pp7z.js → ContextMenu-kia7is1N.js} +1 -1
- package/storybook-static/assets/{ContextMenu-CvOaSUdS.js → ContextMenu-xn2GtiLR.js} +1 -1
- package/storybook-static/assets/{ContextMenu.stories-BMRQo225.js → ContextMenu.stories-CYuy9uXF.js} +1 -1
- package/storybook-static/assets/{CustomOptionButton-B_3l2oEp.js → CustomOptionButton-C4w-APws.js} +1 -1
- package/storybook-static/assets/DateInput-BiUFIihm.js +1 -0
- package/storybook-static/assets/{DateInput-Dmfu-QPI.js → DateInput-DAzE5mCE.js} +1 -1
- package/storybook-static/assets/{DateInput.stories-BcZKAAUH.js → DateInput.stories-BcowGCRD.js} +1 -1
- package/storybook-static/assets/{DateRangePresetSelect-Dpjei_qk.js → DateRangePresetSelect-CQm4dNLR.js} +1 -1
- package/storybook-static/assets/{DateRangePresetSelect-C4QK2uI5.js → DateRangePresetSelect-RIyqNBk9.js} +1 -1
- package/storybook-static/assets/{DateRangePresetSelect.stories-HuFMQCzg.js → DateRangePresetSelect.stories-ypGyuGfy.js} +1 -1
- package/storybook-static/assets/{Detail-mSGrPHPd.js → Detail-CEypL2Nh.js} +1 -1
- package/storybook-static/assets/{Detail.stories-CNmeyajk.js → Detail.stories-DNkT7B-u.js} +1 -1
- package/storybook-static/assets/{Dialog-CNPtztC5.js → Dialog-BVFFQJDH.js} +1 -1
- package/storybook-static/assets/{Dialog-C4lB95kT.js → Dialog-DD0grLG3.js} +1 -1
- package/storybook-static/assets/{Dialog.stories-DGC2CdmD.js → Dialog.stories-DSCypHqR.js} +1 -1
- package/storybook-static/assets/{Disclosure-Bg9Uurzq.js → Disclosure-DauUgrev.js} +1 -1
- package/storybook-static/assets/{Disclosure.stories-52zq3d3b.js → Disclosure.stories-B1qB8vQZ.js} +1 -1
- package/storybook-static/assets/{DisclosureGroup-htBmjuHs.js → DisclosureGroup-D9oCCeHf.js} +1 -1
- package/storybook-static/assets/{DocsRenderer-JROSPFPF-CfCr8YB1.js → DocsRenderer-JROSPFPF-CmSf6tXp.js} +1 -1
- package/storybook-static/assets/{DropZone-DHl97f8Y.js → DropZone-D42ueN1w.js} +1 -1
- package/storybook-static/assets/{DropZone-BsjXindv.js → DropZone-D8hbPCAv.js} +1 -1
- package/storybook-static/assets/{DropZone.stories-UxmcssH9.js → DropZone.stories-DO-T_Bh4.js} +1 -1
- package/storybook-static/assets/{DropdownMenu-Bq4Z7eyk.js → DropdownMenu-CknJDoji.js} +1 -1
- package/storybook-static/assets/{ExpandableActionPanel-Buvm-uo_.js → ExpandableActionPanel-Dqi_bo3c.js} +1 -1
- package/storybook-static/assets/{ExpandableActionPanel.stories-DHjq73og.js → ExpandableActionPanel.stories-BD9QZGZN.js} +1 -1
- package/storybook-static/assets/{Flex-B9W01d7p.js → Flex-CaVn1IOP.js} +1 -1
- package/storybook-static/assets/{Flex.stories-Y8vGrgl5.js → Flex.stories-Bp9Y6q6b.js} +1 -1
- package/storybook-static/assets/{FloatingPopover-C06XhNb8.js → FloatingPopover-U7tx-Jlw.js} +1 -1
- package/storybook-static/assets/{FormattedTableCell-DnBQJjql.js → FormattedTableCell-pmmhsAbN.js} +1 -1
- package/storybook-static/assets/{Grid-BNsdOQE3.js → Grid-CEpMNurH.js} +1 -1
- package/storybook-static/assets/{Grid.stories-hwxpk_k9.js → Grid.stories-BM-gO5DN.js} +1 -1
- package/storybook-static/assets/{ImageCropper.stories-L6AaNzcC.js → ImageCropper.stories-BWz5XU6U.js} +1 -1
- package/storybook-static/assets/{ImageRenderer-DA4vCb7C.js → ImageRenderer-BTYZEX5t.js} +1 -1
- package/storybook-static/assets/{ImageRenderer.stories-eWJHpmcc.js → ImageRenderer.stories-Dz2STM95.js} +1 -1
- package/storybook-static/assets/{ImageView.stories-CDZmePLC.js → ImageView.stories-DBVe0an3.js} +1 -1
- package/storybook-static/assets/{ImageViewer.stories-c1s8XOKG.js → ImageViewer.stories-C4Px97lD.js} +2 -2
- package/storybook-static/assets/{ImageViewerRuntime-CB58FU7X.js → ImageViewerRuntime-TJtlJVfa.js} +1 -1
- package/storybook-static/assets/{Input-k78uABnO.js → Input-CIPgijvW.js} +1 -1
- package/storybook-static/assets/{Input-CPh1-5MN.js → Input-D8io9jVS.js} +1 -1
- package/storybook-static/assets/{Input.stories-Bjo-quWE.js → Input.stories-SUk3aYaC.js} +1 -1
- package/storybook-static/assets/{InputDateTime-D6wx8NHg.js → InputDateTime-DA5pIDuE.js} +1 -1
- package/storybook-static/assets/{InputDateTime.stories-DKYu3IHZ.js → InputDateTime.stories-DeudzDSU.js} +1 -1
- package/storybook-static/assets/{InputFile-B_d9cuuZ.js → InputFile-C5mp5Y5I.js} +1 -1
- package/storybook-static/assets/{InputFile-jyLYajsV.js → InputFile-CGAC7ruP.js} +1 -1
- package/storybook-static/assets/{InputFile.stories-BdefvDig.js → InputFile.stories-Cx1xQ6PE.js} +1 -1
- package/storybook-static/assets/{InputFiles-Bk5cxV_q.js → InputFiles-B7OBcPJN.js} +1 -1
- package/storybook-static/assets/{InputFiles-8NO4ybbw.js → InputFiles-Hzl89Ghf.js} +1 -1
- package/storybook-static/assets/{InputFiles.stories-ByWo1zY4.js → InputFiles.stories-CG6QjDZH.js} +1 -1
- package/storybook-static/assets/{InputFilesList-D4SB2px7.js → InputFilesList-B6htWHF1.js} +1 -1
- package/storybook-static/assets/{InputImage-Zoi-dxR0.js → InputImage-BTa4S4Wp.js} +1 -1
- package/storybook-static/assets/{InputImage-DehD0dUv.js → InputImage-CQnoblAE.js} +1 -1
- package/storybook-static/assets/{InputImage.stories-Bm6vjE22.js → InputImage.stories-CEI44Eyz.js} +1 -1
- package/storybook-static/assets/{InteractiveComponents-B1kglKoK.js → InteractiveComponents-B0ypWz1x.js} +1 -1
- package/storybook-static/assets/{InteractiveComponents.stories-HmO6jYBZ.js → InteractiveComponents.stories-BadApta9.js} +1 -1
- package/storybook-static/assets/{LayoutPicker-BdaZMF1N.js → LayoutPicker-COB9GlV_.js} +1 -1
- package/storybook-static/assets/{LayoutPicker-C__JzlAL.js → LayoutPicker-C_Uz7Tnj.js} +1 -1
- package/storybook-static/assets/{LayoutPicker.stories-Q1MsCb_7.js → LayoutPicker.stories-Btp0IcaL.js} +1 -1
- package/storybook-static/assets/{Listbox-_2Lhh6GE.js → Listbox-AAaZGSAl.js} +1 -1
- package/storybook-static/assets/{Listbox-HDTB2yAv.js → Listbox-CyfuZw7w.js} +1 -1
- package/storybook-static/assets/{Listbox.stories-C5uX1wxr.js → Listbox.stories-NDKQmjyQ.js} +1 -1
- package/storybook-static/assets/{Modal-Blv9Namu.js → Modal-BJDnJ4zv.js} +1 -1
- package/storybook-static/assets/{Modal.stories-Bh5G9FLw.js → Modal.stories-D_X5lTLO.js} +1 -1
- package/storybook-static/assets/{ModalManagerProvider-DedM4XGI.js → ModalManagerProvider-ShDjozpW.js} +1 -1
- package/storybook-static/assets/{MultiSelect-B_2TcTLI.js → MultiSelect-B5CElQ3-.js} +1 -1
- package/storybook-static/assets/{MultiSelect-C9a9z0VK.js → MultiSelect-DqXfrjcH.js} +1 -1
- package/storybook-static/assets/{MultiSelect.stories-D5Ly4DPj.js → MultiSelect.stories-fB3mcFmx.js} +1 -1
- package/storybook-static/assets/{NoData-CD8_tH4f.js → NoData-DDb0G7T8.js} +1 -1
- package/storybook-static/assets/{NotificationsHost-MW4gDQQK.js → NotificationsHost-CIGL-pKX.js} +1 -1
- package/storybook-static/assets/NotificationsHost.stories-B_MRb3fs.js +29 -0
- package/storybook-static/assets/{ODataMultiSelect-DjVOp5BB.js → ODataMultiSelect-DQAitH4N.js} +1 -1
- package/storybook-static/assets/{ODataMultiSelect.stories-Cpxe83Z0.js → ODataMultiSelect.stories-DwW221S9.js} +2 -2
- package/storybook-static/assets/{ODataSelect-C_2GMQva.js → ODataSelect-tiZhOIhE.js} +1 -1
- package/storybook-static/assets/{ODataSelect.stories-C6Wo7X-M.js → ODataSelect.stories-BhaatPjK.js} +2 -2
- package/storybook-static/assets/{ODataTreeMultiSelect-1PxW1yEH.js → ODataTreeMultiSelect-B9WqJ-Un.js} +1 -1
- package/storybook-static/assets/{ODataTreeMultiSelect.stories-AetogHrA.js → ODataTreeMultiSelect.stories-CAfKuhfU.js} +1 -1
- package/storybook-static/assets/{ODataTreeSelect-vPvVKIRZ.js → ODataTreeSelect-Cel1phxZ.js} +1 -1
- package/storybook-static/assets/{ODataTreeSelect.stories-Cvyu6C2q.js → ODataTreeSelect.stories-BpBCpBA9.js} +1 -1
- package/storybook-static/assets/{OneStepScroller-BtSUY6R7.js → OneStepScroller-BSeGbz02.js} +1 -1
- package/storybook-static/assets/{Option-D5HVST0Y.js → Option-BBtQ3GdK.js} +1 -1
- package/storybook-static/assets/{OptionButton-DMZn3qex.js → OptionButton-B9nZuqqW.js} +1 -1
- package/storybook-static/assets/{PeriodSelect-ccgbEHCS.js → PeriodSelect-BGvhR3to.js} +1 -1
- package/storybook-static/assets/{PeriodSelect-BirdSdPT.js → PeriodSelect-DA_zjcdA.js} +1 -1
- package/storybook-static/assets/{PeriodSelect.stories-LnR8MJQQ.js → PeriodSelect.stories-DDP1eXyM.js} +1 -1
- package/storybook-static/assets/{PickerTriggerActions-DEXowtVB.js → PickerTriggerActions-BgvzqRBd.js} +1 -1
- package/storybook-static/assets/{Popover-CfT-5TUj.js → Popover-BQql18MF.js} +1 -1
- package/storybook-static/assets/{Popover-B9Pbbd8S.js → Popover-C0NebUMz.js} +1 -1
- package/storybook-static/assets/{Popover.stories-DkIh7SkO.js → Popover.stories-CIyDUtlz.js} +1 -1
- package/storybook-static/assets/{PresetRangeDateInput-BshHlO-z.js → PresetRangeDateInput-BsgzPwCV.js} +1 -1
- package/storybook-static/assets/{PresetRangeDateInput-rHxPNjnG.js → PresetRangeDateInput-htbxc3ni.js} +1 -1
- package/storybook-static/assets/{PresetRangeDateInput.stories-BToClw-C.js → PresetRangeDateInput.stories-ClHM5Kah.js} +1 -1
- package/storybook-static/assets/{PresetSelect-BND50bCx.js → PresetSelect-Dcx0BOTx.js} +1 -1
- package/storybook-static/assets/README--LCKbep-.js +110 -0
- package/storybook-static/assets/{README-Du53oOl4.js → README-5M8ajrJp.js} +1 -1
- package/storybook-static/assets/README-5NhzH8VL.js +95 -0
- package/storybook-static/assets/README-Am6Fa6-b.js +69 -0
- package/storybook-static/assets/README-B3bFglqG.js +82 -0
- package/storybook-static/assets/README-B45Cwj2a.js +95 -0
- package/storybook-static/assets/README-B6Nq7NCU.js +416 -0
- package/storybook-static/assets/{README-s-T48I9S.js → README-B6ltJiw3.js} +1 -1
- package/storybook-static/assets/{README-DUA1kfLE.js → README-BB_JPejH.js} +1 -1
- package/storybook-static/assets/README-BIq-FXcN.js +2124 -0
- package/storybook-static/assets/README-BSh5XUR9.js +110 -0
- package/storybook-static/assets/README-BXJneZAJ.js +147 -0
- package/storybook-static/assets/README-BYSgTTZt.js +296 -0
- package/storybook-static/assets/{README-BRNFl9WV.js → README-BmhhWWEk.js} +1 -1
- package/storybook-static/assets/README-Bqnqu1bC.js +118 -0
- package/storybook-static/assets/README-BuMMG4_N.js +192 -0
- package/storybook-static/assets/README-BxjYCoYA.js +186 -0
- package/storybook-static/assets/{README-BsxKAG_a.js → README-ByALXSEH.js} +1 -1
- package/storybook-static/assets/README-Byo6DxIF.js +101 -0
- package/storybook-static/assets/README-C3UcjOGB.js +208 -0
- package/storybook-static/assets/README-C6BOdXNV.js +322 -0
- package/storybook-static/assets/README-C8E1O7DQ.js +230 -0
- package/storybook-static/assets/README-C9eh0JLs.js +64 -0
- package/storybook-static/assets/README-CAGQnLsv.js +90 -0
- package/storybook-static/assets/README-CC00hlZK.js +527 -0
- package/storybook-static/assets/README-CH_6ZIO2.js +64 -0
- package/storybook-static/assets/README-CHbo4O3Z.js +75 -0
- package/storybook-static/assets/{README-Y0nGf_0E.js → README-CIGfHKKE.js} +1 -1
- package/storybook-static/assets/{README-B7XIrdXq.js → README-CM-7E-Jf.js} +1 -1
- package/storybook-static/assets/{README-8Lm1JpdJ.js → README-CNHemCS2.js} +1 -1
- package/storybook-static/assets/{README-fxPT-NzI.js → README-CWfPiPIB.js} +1 -1
- package/storybook-static/assets/{README-Dw1C16bT.js → README-CeK4kfFO.js} +1 -1
- package/storybook-static/assets/README-Cj2e6HrF.js +178 -0
- package/storybook-static/assets/README-CsoHGRve.js +1844 -0
- package/storybook-static/assets/README-D9OypaFB.js +208 -0
- package/storybook-static/assets/{README-zAGDQqES.js → README-DDBqoI-T.js} +1 -1
- package/storybook-static/assets/README-DE2wk9-v.js +1282 -0
- package/storybook-static/assets/README-DEj2wSK0.js +264 -0
- package/storybook-static/assets/{README-DJlxGqOL.js → README-DIbfpC-2.js} +1 -1
- package/storybook-static/assets/{README-D5VR4x0m.js → README-DJHVgrpj.js} +1 -1
- package/storybook-static/assets/README-DN9HKtp_.js +124 -0
- package/storybook-static/assets/README-DNricOkt.js +136 -0
- package/storybook-static/assets/README-DV4fCpqN.js +1146 -0
- package/storybook-static/assets/{README-BMmR1B7a.js → README-DjCArsA5.js} +1 -1
- package/storybook-static/assets/README-Dl92E69Z.js +1704 -0
- package/storybook-static/assets/README-DnA-4W65.js +226 -0
- package/storybook-static/assets/README-DoCA4JXf.js +273 -0
- package/storybook-static/assets/{README-DUxV9GhP.js → README-DvAlDsh9.js} +1 -1
- package/storybook-static/assets/README-Ss-3t1nX.js +158 -0
- package/storybook-static/assets/README-eHCINzP3.js +154 -0
- package/storybook-static/assets/README-qHKxXU95.js +98 -0
- package/storybook-static/assets/README-tm9QH9cF.js +103 -0
- package/storybook-static/assets/README-ui-uanyg.js +672 -0
- package/storybook-static/assets/{RadioButton-BKvo6LIi.js → RadioButton-CWtjclwT.js} +1 -1
- package/storybook-static/assets/{RadioButton-D8KuponB.js → RadioButton-YIQXt0wx.js} +1 -1
- package/storybook-static/assets/{RadioButton.stories-BabeLrwX.js → RadioButton.stories-Ah-CBpeC.js} +1 -1
- package/storybook-static/assets/{RadioGroup-CsWjbEp2.js → RadioGroup-BnO-GL7A.js} +1 -1
- package/storybook-static/assets/{RadioGroup-jl5PxZpJ.js → RadioGroup-CUS0etBD.js} +1 -1
- package/storybook-static/assets/{RadioGroup.stories-BGoWy9-B.js → RadioGroup.stories-DGwCawtU.js} +1 -1
- package/storybook-static/assets/{Scrollable-CmPEHdW8.js → Scrollable-D85fA6pO.js} +1 -1
- package/storybook-static/assets/{Select-DiN4WVRM.js → Select-CGCxJjL9.js} +1 -1
- package/storybook-static/assets/{Select-BGM16rM6.js → Select-gRnfvfGh.js} +1 -1
- package/storybook-static/assets/{Select.stories-BEO6vXD_.js → Select.stories-CMwt4F9i.js} +1 -1
- package/storybook-static/assets/{SerializableSelect-B0DuNSqT.js → SerializableSelect-BLXfKJ38.js} +1 -1
- package/storybook-static/assets/{SerializableSelect.stories-DcI6UQCk.js → SerializableSelect.stories-Bca1a9ZU.js} +1 -1
- package/storybook-static/assets/{SingleDateTimeInput-C_Itd_An.js → SingleDateTimeInput-CyeQN0Rd.js} +1 -1
- package/storybook-static/assets/{SingleDateTimeInput-CwYhFl03.js → SingleDateTimeInput-xrmZckzw.js} +1 -1
- package/storybook-static/assets/SingleDateTimeInput.stories-BYFTQM9z.js +48 -0
- package/storybook-static/assets/{Slider-DCEQ39ar.js → Slider-1yJ3uVeR.js} +1 -1
- package/storybook-static/assets/{Slider-r4NefX-L.js → Slider-D8GtXVGI.js} +1 -1
- package/storybook-static/assets/{Slider.stories-B3M87sif.js → Slider.stories-CyQ3ns_C.js} +1 -1
- package/storybook-static/assets/{SliderInput-BmLucI1O.js → SliderInput-BOzHhEUA.js} +1 -1
- package/storybook-static/assets/{SliderInput-2ThnJzQ4.js → SliderInput-ISSx9vH_.js} +1 -1
- package/storybook-static/assets/{SliderInput.stories-B64rkErN.js → SliderInput.stories-7ooTghrS.js} +1 -1
- package/storybook-static/assets/{Sortable-Bx0rDd7W.js → Sortable-CCLiMmfZ.js} +1 -1
- package/storybook-static/assets/{Sortable.stories-BizbKIHw.js → Sortable.stories-B36szI6t.js} +1 -1
- package/storybook-static/assets/{Splitter-DGCB2owx.js → Splitter-DQGhgRwx.js} +1 -1
- package/storybook-static/assets/{Splitter.stories-8Oh14fbm.js → Splitter.stories-Hsq1wYaq.js} +1 -1
- package/storybook-static/assets/{StateSelect-Dw0Qm14-.js → StateSelect-C6hldFgO.js} +1 -1
- package/storybook-static/assets/{StateSelect-BSQUSTgI.js → StateSelect-DieNn4VC.js} +1 -1
- package/storybook-static/assets/{StateSelect.stories-C8WPRJNx.js → StateSelect.stories-CvAhDMix.js} +1 -1
- package/storybook-static/assets/{StringToggle.stories-K9u9rdE8.js → StringToggle.stories-CUT1tvt-.js} +1 -1
- package/storybook-static/assets/{Switch-BBuNsdNx.js → Switch-CX9p_uYU.js} +1 -1
- package/storybook-static/assets/{Switch-CtpvrECR.js → Switch-nEMRtcWe.js} +1 -1
- package/storybook-static/assets/{Switch.stories-Bcr4zA7L.js → Switch.stories-CPsHa2_m.js} +1 -1
- package/storybook-static/assets/{Table-iYeIie6s.js → Table-BhtITVtj.js} +1 -1
- package/storybook-static/assets/{Table.stories-BESdXqZx.js → Table.stories-nWNhSydG.js} +2 -2
- package/storybook-static/assets/{Tabs-aqWeCgs4.js → Tabs-DMQFh2BJ.js} +1 -1
- package/storybook-static/assets/{Tabs.stories-BSnrKg5G.js → Tabs.stories-D23_xvom.js} +1 -1
- package/storybook-static/assets/{TabsBox-CvRq3QA7.js → TabsBox-B5BsD_j_.js} +1 -1
- package/storybook-static/assets/{TagInput-CfKrOpJJ.js → TagInput-DO17z100.js} +1 -1
- package/storybook-static/assets/{TagInput.stories-CvXZl_qX.js → TagInput.stories-CMMFnIzb.js} +1 -1
- package/storybook-static/assets/{Text-_hP7L82D.js → Text-ClnbDqRk.js} +1 -1
- package/storybook-static/assets/{Textarea-Ujw8jml9.js → Textarea-C2IO_zsP.js} +1 -1
- package/storybook-static/assets/{Textarea-C6X20K4X.js → Textarea-DkhohiNc.js} +1 -1
- package/storybook-static/assets/{Textarea.stories-Bi4BQMxQ.js → Textarea.stories-NL6Aq8Vc.js} +1 -1
- package/storybook-static/assets/{TimePanel-B3eqkZj8.js → TimePanel-DNEPDlSW.js} +1 -1
- package/storybook-static/assets/{TimePanel.stories-BHXkDSMy.js → TimePanel.stories-DlfdPsz1.js} +1 -1
- package/storybook-static/assets/{Toggle-DS-Q4jwI.js → Toggle-3U5CceQN.js} +1 -1
- package/storybook-static/assets/{Toggle-6sjykxYk.js → Toggle-Cc6Ca-HI.js} +1 -1
- package/storybook-static/assets/{Toggle.stories-BhM1so-Z.js → Toggle.stories-BR-hVLDp.js} +1 -1
- package/storybook-static/assets/{TreeMultiSelect-D2lWYAa2.js → TreeMultiSelect-B0oBc-4y.js} +1 -1
- package/storybook-static/assets/{TreeMultiSelect-BudM77CT.js → TreeMultiSelect-D9hMQN2O.js} +1 -1
- package/storybook-static/assets/{TreeMultiSelect.stories-Bhh1zaAQ.js → TreeMultiSelect.stories-CslpbvPR.js} +1 -1
- package/storybook-static/assets/{TreePickerBase-CJfbJ6Ap.js → TreePickerBase-B_dMCe45.js} +1 -1
- package/storybook-static/assets/{TreeSelect-BFD6AKMu.js → TreeSelect-2lj0Q8gm.js} +1 -1
- package/storybook-static/assets/{TreeSelect-B7SG9PV7.js → TreeSelect-DEKNYF2b.js} +1 -1
- package/storybook-static/assets/{TreeSelect.stories-C-bHnrPH.js → TreeSelect.stories-CVDxn8Vm.js} +1 -1
- package/storybook-static/assets/{TreeTable-D-z37qlF.js → TreeTable-CBIpzYRL.js} +1 -1
- package/storybook-static/assets/{TreeTable.stories-CF_mH9Zz.js → TreeTable.stories-BMzrr2Kc.js} +2 -2
- package/storybook-static/assets/{blocks-Ddv0ZNIG.js → blocks-B5YBxaaS.js} +3 -3
- package/storybook-static/assets/{check-CgNbDbzr.js → check-BjtdCRaW.js} +1 -1
- package/storybook-static/assets/{chevron-down-0EnY_Ds_.js → chevron-down-B4u-y8Z1.js} +1 -1
- package/storybook-static/assets/{chevron-left-D5M5fFYk.js → chevron-left-BQfWs7Ah.js} +1 -1
- package/storybook-static/assets/{chevron-right-Uz5Iy_m-.js → chevron-right-ChokKd-f.js} +1 -1
- package/storybook-static/assets/{chunk-W22LQPXL-THpLoWLV.js → chunk-W22LQPXL-meOkhzk4.js} +1 -1
- package/storybook-static/assets/{circle-alert-B6Z--uoZ.js → circle-alert-B1AnDRf_.js} +1 -1
- package/storybook-static/assets/{circle-check-DMzkBUqN.js → circle-check-JYnlcC1F.js} +1 -1
- package/storybook-static/assets/{components-BmKs7c49.js → components-C_wl1sL5.js} +3 -3
- package/storybook-static/assets/{contextMenu-Dct-XhfD.js → contextMenu-B-TUGs_1.js} +1 -1
- package/storybook-static/assets/{defaultRenderers-BHXboKuy.js → defaultRenderers-DfmnIuod.js} +1 -1
- package/storybook-static/assets/{download-wey0TOZ0.js → download-eR3X8I-h.js} +1 -1
- package/storybook-static/assets/{floating-ui.react-COVT_I6r.js → floating-ui.react-D95VPQ0b.js} +1 -1
- package/storybook-static/assets/formatters-D33Uh3si-CxrG0jsB.js +1 -0
- package/storybook-static/assets/foundationApi-QhHXpYLB.js +59 -0
- package/storybook-static/assets/foundationLib-CEAjnstw.js +30 -0
- package/storybook-static/assets/{hooks-Baxp-XYz.js → hooks-awde7r2r.js} +1 -1
- package/storybook-static/assets/iframe-DzQq_POR.js +1 -0
- package/storybook-static/assets/{iframe-BOu-P2xF.js → iframe-FSp_AjJa.js} +4 -4
- package/storybook-static/assets/{info-gF0pk8a1.js → info-12vmb1sT.js} +1 -1
- package/storybook-static/assets/odata-C0Kpvttz.js +1 -0
- package/storybook-static/assets/odata-service-CWkHASdw-DlmSiioz.js +3 -0
- package/storybook-static/assets/{odataStoryFixtures-BUio-7WG.js → odataStoryFixtures-BXZnk_C7.js} +1 -1
- package/storybook-static/assets/{react-CN73PS7L.js → react-BlCqWuXr.js} +1 -1
- package/storybook-static/assets/{refresh-cw-BZ2qxodL.js → refresh-cw-Bf5ufPte.js} +1 -1
- package/storybook-static/assets/{settings-2-B33BG8wi.js → settings-2-DR-dTXIC.js} +1 -1
- package/storybook-static/assets/{sortable-CmC4atFR.js → sortable-B5e5yb_-.js} +1 -1
- package/storybook-static/assets/{syntaxhighlighter-QEQV7K2Y-Di0K55k7.js → syntaxhighlighter-QEQV7K2Y-EVJARTec.js} +1 -1
- package/storybook-static/assets/{trash-2-TnhWnKGO.js → trash-2-QP7TS18H.js} +1 -1
- package/storybook-static/assets/{triangle-alert-hZRwHRWu.js → triangle-alert-qw19mxHr.js} +1 -1
- package/storybook-static/assets/{useODataSelectBase-bTXYj3rC.js → useODataSelectBase-Csu_Cct9.js} +1 -1
- package/storybook-static/assets/useODataTreeData-BAv-Twqf.js +1 -0
- package/storybook-static/assets/{usePickerQuery-BMGBq6pi.js → usePickerQuery-Da-XM_Y0.js} +1 -1
- package/storybook-static/assets/{usePickerTriggerController-CB_TIrYx.js → usePickerTriggerController-C0TdC2Pz.js} +1 -1
- package/storybook-static/assets/{x-D86ykZGt.js → x-aCjYTirW.js} +1 -1
- package/storybook-static/iframe.html +2 -2
- package/storybook-static/index.json +1 -1
- package/storybook-static/project.json +1 -1
- package/dist/chunks/defaultRenderers-Dbhg2hHc.js.map +0 -1
- package/dist/chunks/multi-select-CHZhWoq6.js.map +0 -1
- package/storybook-static/assets/DateInput-DSwx7eI6.js +0 -1
- package/storybook-static/assets/NotificationsHost.stories-BZJG9Nvq.js +0 -29
- package/storybook-static/assets/SingleDateTimeInput.stories-kdKdW6al.js +0 -48
- package/storybook-static/assets/async-D1NpMm55.js +0 -625
- package/storybook-static/assets/formatters-CBgrBeSA-CqB1pZxS.js +0 -1
- package/storybook-static/assets/foundationLib-CRTVZVS8.js +0 -25
- package/storybook-static/assets/iframe-CDj936Ul.js +0 -1
- package/storybook-static/assets/odata-D9Wmxqmj.js +0 -1
- package/storybook-static/assets/odata-service-B6TxBSLm-Bq8Ya67E.js +0 -3
- package/storybook-static/assets/odataFetchFn-DfJwHTw8.js +0 -763
- package/storybook-static/assets/persisted-4qmfJLE0.js +0 -600
- package/storybook-static/assets/useODataTreeData-ZcX73Wdh.js +0 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import{n as e}from"./rolldown-runtime-DkW27tQK.js";import{n as t}from"./iframe-FSp_AjJa.js";import{i as n,r}from"./react-Bl2r1tuC.js";import{l as i,m as a}from"./blocks-B5YBxaaS.js";function o(e){let t={code:`code`,h1:`h1`,h2:`h2`,h3:`h3`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,table:`table`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,...n(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(i,{title:`Foundation Lib/Browser/Three Scene`}),`
|
|
2
|
+
`,(0,c.jsx)(t.h1,{id:`three-scene`,children:`Three Scene`}),`
|
|
3
|
+
`,(0,c.jsxs)(t.p,{children:[`Модуль `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/three-scene`}),` проверяет, можно ли безопасно показывать необязательную Three.js/WebGL-сцену, и помогает отключить её до конца браузерной сессии.`]}),`
|
|
4
|
+
`,(0,c.jsx)(t.p,{children:`Модуль не импортирует Three.js, не создаёт renderer и не управляет canvas. Его задача — принять раннее решение: загружать тяжёлую 3D-сцену или показать облегчённую альтернативу.`}),`
|
|
5
|
+
`,(0,c.jsx)(t.h2,{id:`когда-использовать`,children:`Когда использовать`}),`
|
|
6
|
+
`,(0,c.jsx)(t.p,{children:`Подходит для декоративных и дополнительных сцен:`}),`
|
|
7
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
8
|
+
`,(0,c.jsx)(t.li,{children:`3D-фон страницы;`}),`
|
|
9
|
+
`,(0,c.jsx)(t.li,{children:`визуализация, у которой есть обычная HTML-альтернатива;`}),`
|
|
10
|
+
`,(0,c.jsx)(t.li,{children:`lazy import Three.js только на поддерживаемых устройствах;`}),`
|
|
11
|
+
`,(0,c.jsx)(t.li,{children:`отключение повторных неудачных попыток WebGL в пределах вкладки.`}),`
|
|
12
|
+
`]}),`
|
|
13
|
+
`,(0,c.jsx)(t.p,{children:`Для критически важного бизнес-сценария одной проверки поддержки недостаточно: renderer всё равно может завершиться ошибкой позже, например из-за потери контекста или нехватки памяти.`}),`
|
|
14
|
+
`,(0,c.jsx)(t.h2,{id:`импорт`,children:`Импорт`}),`
|
|
15
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import {
|
|
16
|
+
disableThreeSceneForSession,
|
|
17
|
+
isThreeSceneDisabledForSession,
|
|
18
|
+
isThreeSceneSupported,
|
|
19
|
+
threeSceneDefaultDisabledStorageKey,
|
|
20
|
+
useThreeSceneAvailability,
|
|
21
|
+
type ThreeSceneAvailability
|
|
22
|
+
} from "@ryuzaki13/react-foundation-lib/three-scene";
|
|
23
|
+
`})}),`
|
|
24
|
+
`,(0,c.jsx)(t.p,{children:`Для hook нужен React. Остальные функции работают напрямую с браузерными API.`}),`
|
|
25
|
+
`,(0,c.jsx)(t.h2,{id:`быстрый-старт-с-react`,children:`Быстрый старт с React`}),`
|
|
26
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`import { lazy, Suspense } from "react";
|
|
27
|
+
import { useThreeSceneAvailability } from "@ryuzaki13/react-foundation-lib/three-scene";
|
|
28
|
+
|
|
29
|
+
const Scene = lazy(() => import("./Scene"));
|
|
30
|
+
|
|
31
|
+
export function HeroVisual() {
|
|
32
|
+
const availability = useThreeSceneAvailability({
|
|
33
|
+
webGLVersion: "webgl2",
|
|
34
|
+
disableWhenReducedMotion: true
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (availability.status !== "available") {
|
|
38
|
+
return <img src="/hero.webp" alt="" />;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Suspense fallback={<img src="/hero.webp" alt="" />}>
|
|
43
|
+
<Scene />
|
|
44
|
+
</Suspense>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
`})}),`
|
|
48
|
+
`,(0,c.jsxs)(t.p,{children:[`На первом клиентском рендере hook тоже возвращает `,(0,c.jsx)(t.code,{children:`unavailable/ssr`}),`. Проверка происходит в effect после hydration. Это сохраняет одинаковую начальную HTML-разметку на сервере и клиенте.`]}),`
|
|
49
|
+
`,(0,c.jsx)(t.h2,{id:`модель-состояния`,children:`Модель состояния`}),`
|
|
50
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type ThreeSceneAvailabilityStatus = "pending" | "available" | "unavailable";
|
|
51
|
+
|
|
52
|
+
type ThreeSceneUnavailableReason = "ssr" | "sessionDisabled" | "reducedMotion" | "webglUnsupported";
|
|
53
|
+
|
|
54
|
+
type ThreeSceneAvailability = {
|
|
55
|
+
readonly status: ThreeSceneAvailabilityStatus;
|
|
56
|
+
readonly reason?: ThreeSceneUnavailableReason;
|
|
57
|
+
};
|
|
58
|
+
`})}),`
|
|
59
|
+
`,(0,c.jsxs)(t.p,{children:[`Текущий hook фактически возвращает `,(0,c.jsx)(t.code,{children:`available`}),` или `,(0,c.jsx)(t.code,{children:`unavailable`}),`; начальное состояние — `,(0,c.jsx)(t.code,{children:`unavailable`}),` с причиной `,(0,c.jsx)(t.code,{children:`ssr`}),`. Значение `,(0,c.jsx)(t.code,{children:`pending`}),` входит в общий тип, но hook сейчас его не устанавливает.`]}),`
|
|
60
|
+
`,(0,c.jsx)(t.p,{children:`Причины:`}),`
|
|
61
|
+
`,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Причина`}),(0,c.jsx)(t.th,{children:`Значение`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ssr`})}),(0,c.jsx)(t.td,{children:`Проверка ещё не выполнена в браузере либо код работает без DOM`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`sessionDisabled`})}),(0,c.jsxs)(t.td,{children:[`Сцена отключена в `,(0,c.jsx)(t.code,{children:`sessionStorage`}),` текущей вкладки`]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`reducedMotion`})}),(0,c.jsx)(t.td,{children:`Пользователь предпочитает уменьшенное движение, а соответствующая опция включена`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`webglUnsupported`})}),(0,c.jsx)(t.td,{children:`Не удалось создать требуемый WebGL-контекст`})]})]})]}),`
|
|
62
|
+
`,(0,c.jsx)(t.h2,{id:`isthreescenesupportedoptions`,children:(0,c.jsx)(t.code,{children:`isThreeSceneSupported(options?)`})}),`
|
|
63
|
+
`,(0,c.jsx)(t.p,{children:`Синхронно проверяет создание WebGL-контекста на временном canvas.`}),`
|
|
64
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`isThreeSceneSupported(); // проверяет только WebGL 2
|
|
65
|
+
isThreeSceneSupported({ webGLVersion: "webgl2" });
|
|
66
|
+
isThreeSceneSupported({ webGLVersion: "webgl" });
|
|
67
|
+
`})}),`
|
|
68
|
+
`,(0,c.jsx)(t.p,{children:`Доступны два режима:`}),`
|
|
69
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
70
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`webgl2`}),` — принимает только контекст `,(0,c.jsx)(t.code,{children:`webgl2`}),`;`]}),`
|
|
71
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`webgl`}),` — пробует `,(0,c.jsx)(t.code,{children:`webgl2`}),`, затем `,(0,c.jsx)(t.code,{children:`webgl`}),` и `,(0,c.jsx)(t.code,{children:`experimental-webgl`}),`.`]}),`
|
|
72
|
+
`]}),`
|
|
73
|
+
`,(0,c.jsxs)(t.p,{children:[`Если контекст создан, функция по возможности вызывает расширение `,(0,c.jsx)(t.code,{children:`WEBGL_lose_context`}),`, чтобы освободить временный ресурс. При отсутствии `,(0,c.jsx)(t.code,{children:`document`}),`, ошибке браузера или невозможности создать контекст возвращается `,(0,c.jsx)(t.code,{children:`false`}),`.`]}),`
|
|
74
|
+
`,(0,c.jsx)(t.p,{children:`Положительный результат означает только базовую поддержку контекста. Он не гарантирует нужные extensions, производительность GPU, объём памяти или успешную загрузку конкретной сцены.`}),`
|
|
75
|
+
`,(0,c.jsx)(t.h2,{id:`отключение-на-время-сессии`,children:`Отключение на время сессии`}),`
|
|
76
|
+
`,(0,c.jsx)(t.h3,{id:`ключ-по-умолчанию`,children:`Ключ по умолчанию`}),`
|
|
77
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:"threeSceneDefaultDisabledStorageKey;\n// `${__APP_ID__}:three-scene:disabled`\n"})}),`
|
|
78
|
+
`,(0,c.jsxs)(t.p,{children:[`Пакет ожидает, что сборка приложения определит compile-time константу `,(0,c.jsx)(t.code,{children:`__APP_ID__`}),`. Она отделяет данные разных приложений на одном origin.`]}),`
|
|
79
|
+
`,(0,c.jsx)(t.h3,{id:`disablethreesceneforsessionstoragekey`,children:(0,c.jsx)(t.code,{children:`disableThreeSceneForSession(storageKey?)`})}),`
|
|
80
|
+
`,(0,c.jsxs)(t.p,{children:[`Записывает строку `,(0,c.jsx)(t.code,{children:`"1"`}),` в `,(0,c.jsx)(t.code,{children:`sessionStorage`}),`. Функция ничего не делает на сервере и молча игнорирует ошибки хранилища.`]}),`
|
|
81
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`try {
|
|
82
|
+
await startScene();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
disableThreeSceneForSession();
|
|
85
|
+
showStaticFallback();
|
|
86
|
+
}
|
|
87
|
+
`})}),`
|
|
88
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`sessionStorage`}),` живёт в пределах вкладки. Новая вкладка или новая сессия получает новую попытку.`]}),`
|
|
89
|
+
`,(0,c.jsx)(t.h3,{id:`isthreescenedisabledforsessionstoragekey`,children:(0,c.jsx)(t.code,{children:`isThreeSceneDisabledForSession(storageKey?)`})}),`
|
|
90
|
+
`,(0,c.jsxs)(t.p,{children:[`Возвращает `,(0,c.jsx)(t.code,{children:`true`}),`, только если по ключу хранится точная строка `,(0,c.jsx)(t.code,{children:`"1"`}),`. На сервере возвращает `,(0,c.jsx)(t.code,{children:`true`}),`, чтобы сцена не пыталась стартовать без браузера. Если чтение storage бросает исключение, возвращается `,(0,c.jsx)(t.code,{children:`false`}),` — недоступность storage сама по себе не отключает WebGL.`]}),`
|
|
91
|
+
`,(0,c.jsx)(t.h3,{id:`собственный-ключ`,children:`Собственный ключ`}),`
|
|
92
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const storageKey = "dashboard:analytics-scene:disabled";
|
|
93
|
+
|
|
94
|
+
disableThreeSceneForSession(storageKey);
|
|
95
|
+
isThreeSceneDisabledForSession(storageKey);
|
|
96
|
+
`})}),`
|
|
97
|
+
`,(0,c.jsx)(t.p,{children:`Одинаковый ключ нужно передавать и в hook.`}),`
|
|
98
|
+
`,(0,c.jsx)(t.h2,{id:`usethreesceneavailabilityoptions`,children:(0,c.jsx)(t.code,{children:`useThreeSceneAvailability(options?)`})}),`
|
|
99
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type UseThreeSceneAvailabilityOptions = {
|
|
100
|
+
readonly disabledStorageKey?: string;
|
|
101
|
+
readonly disableWhenReducedMotion?: boolean;
|
|
102
|
+
readonly webGLVersion?: "webgl" | "webgl2";
|
|
103
|
+
};
|
|
104
|
+
`})}),`
|
|
105
|
+
`,(0,c.jsx)(t.p,{children:`Значения по умолчанию:`}),`
|
|
106
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
107
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`disabledStorageKey`}),` — `,(0,c.jsx)(t.code,{children:`threeSceneDefaultDisabledStorageKey`}),`;`]}),`
|
|
108
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`disableWhenReducedMotion`}),` — `,(0,c.jsx)(t.code,{children:`false`}),`;`]}),`
|
|
109
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`webGLVersion`}),` — `,(0,c.jsx)(t.code,{children:`webgl2`}),`.`]}),`
|
|
110
|
+
`]}),`
|
|
111
|
+
`,(0,c.jsx)(t.p,{children:`После монтирования проверки выполняются в строгом порядке:`}),`
|
|
112
|
+
`,(0,c.jsxs)(t.ol,{children:[`
|
|
113
|
+
`,(0,c.jsx)(t.li,{children:`включённая политика reduced motion;`}),`
|
|
114
|
+
`,(0,c.jsx)(t.li,{children:`флаг отключения в sessionStorage;`}),`
|
|
115
|
+
`,(0,c.jsx)(t.li,{children:`поддержка требуемого WebGL;`}),`
|
|
116
|
+
`,(0,c.jsxs)(t.li,{children:[`состояние `,(0,c.jsx)(t.code,{children:`available`}),`.`]}),`
|
|
117
|
+
`]}),`
|
|
118
|
+
`,(0,c.jsxs)(t.p,{children:[`Если WebGL не поддержан, hook автоматически записывает session-флаг. Следующие проверки в этой вкладке сразу получат `,(0,c.jsx)(t.code,{children:`sessionDisabled`}),` и не будут повторно создавать пробный контекст.`]}),`
|
|
119
|
+
`,(0,c.jsxs)(t.p,{children:[`Hook повторяет вычисление, если меняются options или результат media query `,(0,c.jsx)(t.code,{children:`prefers-reduced-motion`}),`.`]}),`
|
|
120
|
+
`,(0,c.jsx)(t.h2,{id:`reduced-motion`,children:`Reduced motion`}),`
|
|
121
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`const availability = useThreeSceneAvailability({
|
|
122
|
+
disableWhenReducedMotion: true
|
|
123
|
+
});
|
|
124
|
+
`})}),`
|
|
125
|
+
`,(0,c.jsxs)(t.p,{children:[`При `,(0,c.jsx)(t.code,{children:`true`}),` сцена отключается для пользователя с настройкой `,(0,c.jsx)(t.code,{children:`prefers-reduced-motion: reduce`}),`. Сам session-флаг при этом не записывается: если пользователь изменит системную настройку, hook сможет пересчитать состояние.`]}),`
|
|
126
|
+
`,(0,c.jsxs)(t.p,{children:[`Если 3D-сцена не содержит значимого движения или имеет собственный облегчённый режим, приложение может оставить опцию `,(0,c.jsx)(t.code,{children:`false`}),` и применить reduced-motion внутри renderer.`]}),`
|
|
127
|
+
`,(0,c.jsx)(t.h2,{id:`восстановление-после-ошибки`,children:`Восстановление после ошибки`}),`
|
|
128
|
+
`,(0,c.jsxs)(t.p,{children:[`Модуль не экспортирует `,(0,c.jsx)(t.code,{children:`enableThreeSceneForSession`}),`. Чтобы дать пользователю кнопку «Попробовать снова», приложение может удалить тот же ключ и перезагрузить/перемонтировать проверку:`]}),`
|
|
129
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`window.sessionStorage.removeItem(threeSceneDefaultDisabledStorageKey);
|
|
130
|
+
window.location.reload();
|
|
131
|
+
`})}),`
|
|
132
|
+
`,(0,c.jsx)(t.p,{children:`Удаление storage и reload — решение приложения, потому что повторный запуск тяжёлой сцены должен быть явным пользовательским действием.`}),`
|
|
133
|
+
`,(0,c.jsx)(t.h2,{id:`рекомендуемая-граница-загрузки`,children:`Рекомендуемая граница загрузки`}),`
|
|
134
|
+
`,(0,c.jsx)(t.p,{children:`Не импортируйте тяжёлую сцену до проверки:`}),`
|
|
135
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`// Хорошо: код сцены загружается отдельным chunk только при рендере Scene.
|
|
136
|
+
const Scene = lazy(() => import("./Scene"));
|
|
137
|
+
`})}),`
|
|
138
|
+
`,(0,c.jsxs)(t.p,{children:[`Статический `,(0,c.jsx)(t.code,{children:`import Scene from "./Scene"`}),` загрузит Three.js даже если компонент затем вернёт fallback.`]}),`
|
|
139
|
+
`,(0,c.jsxs)(t.p,{children:[`После `,(0,c.jsx)(t.code,{children:`available`}),` всё равно ставьте error boundary вокруг сцены. Runtime-ошибка renderer не меняет availability автоматически.`]}),`
|
|
140
|
+
`,(0,c.jsx)(t.h2,{id:`ssr-и-hydration`,children:`SSR и hydration`}),`
|
|
141
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
142
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`isThreeSceneSupported`}),` на сервере возвращает `,(0,c.jsx)(t.code,{children:`false`}),`.`]}),`
|
|
143
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`isThreeSceneDisabledForSession`}),` на сервере возвращает `,(0,c.jsx)(t.code,{children:`true`}),`.`]}),`
|
|
144
|
+
`,(0,c.jsxs)(t.li,{children:[`hook начинает с детерминированного `,(0,c.jsx)(t.code,{children:`unavailable/ssr`}),`.`]}),`
|
|
145
|
+
`,(0,c.jsxs)(t.li,{children:[`фактическая проверка выполняется только в `,(0,c.jsx)(t.code,{children:`useEffect`}),`.`]}),`
|
|
146
|
+
`]}),`
|
|
147
|
+
`,(0,c.jsxs)(t.p,{children:[`Поэтому сервер должен рендерить статический fallback. Не считайте начальную причину `,(0,c.jsx)(t.code,{children:`ssr`}),` окончательным отказом браузера.`]}),`
|
|
148
|
+
`,(0,c.jsx)(t.h2,{id:`частые-ошибки`,children:`Частые ошибки`}),`
|
|
149
|
+
`,(0,c.jsx)(t.h3,{id:`считать-webgl-проверку-benchmark`,children:`Считать WebGL-проверку benchmark`}),`
|
|
150
|
+
`,(0,c.jsx)(t.p,{children:`Функция проверяет возможность создания контекста, но не измеряет FPS и не оценивает сложность сцены.`}),`
|
|
151
|
+
`,(0,c.jsx)(t.h3,{id:`запускать-сцену-во-время-ssr`,children:`Запускать сцену во время SSR`}),`
|
|
152
|
+
`,(0,c.jsxs)(t.p,{children:[`Canvas, sessionStorage и WebGL — browser-only API. Загружайте и запускайте renderer после `,(0,c.jsx)(t.code,{children:`availability.status === "available"`}),`.`]}),`
|
|
153
|
+
`,(0,c.jsxs)(t.h3,{id:`не-определить-__app_id__`,children:[`Не определить `,(0,c.jsx)(t.code,{children:`__APP_ID__`})]}),`
|
|
154
|
+
`,(0,c.jsx)(t.p,{children:`Значение участвует в ключе storage на этапе выполнения собранного кода. Сборщик потребителя должен заменить эту compile-time константу.`}),`
|
|
155
|
+
`,(0,c.jsx)(t.h3,{id:`ожидать-автоматического-отключения-при-любой-runtime-ошибке`,children:`Ожидать автоматического отключения при любой runtime-ошибке`}),`
|
|
156
|
+
`,(0,c.jsx)(t.p,{children:`Автоматический session-флаг ставится только при неуспешной первоначальной проверке WebGL. Ошибки загрузки ассетов и renderer приложение обрабатывает самостоятельно.`}),`
|
|
157
|
+
`,(0,c.jsx)(t.h2,{id:`краткая-карта-api`,children:`Краткая карта API`}),`
|
|
158
|
+
`,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Экспорт`}),(0,c.jsx)(t.th,{children:`Назначение`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isThreeSceneSupported()`})}),(0,c.jsx)(t.td,{children:`Проверить возможность создать WebGL-контекст`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`disableThreeSceneForSession()`})}),(0,c.jsx)(t.td,{children:`Отключить сцену до конца сессии вкладки`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isThreeSceneDisabledForSession()`})}),(0,c.jsx)(t.td,{children:`Прочитать session-флаг`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`threeSceneDefaultDisabledStorageKey`})}),(0,c.jsx)(t.td,{children:`Ключ storage с namespace приложения`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`useThreeSceneAvailability()`})}),(0,c.jsx)(t.td,{children:`Объединить WebGL, session и reduced-motion проверки в React`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ThreeSceneAvailability`})}),(0,c.jsx)(t.td,{children:`Тип результата availability`})]})]})]})]})}function s(e={}){let{wrapper:t}={...n(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(o,{...e})}):o(e)}var c;function l(){return(l=e((()=>{c=t(),r(),a()})))()}l();export{s as default};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import{n as e}from"./rolldown-runtime-DkW27tQK.js";import{n as t}from"./iframe-FSp_AjJa.js";import{i as n,r}from"./react-Bl2r1tuC.js";import{l as i,m as a}from"./blocks-B5YBxaaS.js";function o(e){let t={a:`a`,blockquote:`blockquote`,code:`code`,h1:`h1`,h2:`h2`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,table:`table`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,...n(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(i,{title:`Foundation Lib/Validation/Runtime Guards`}),`
|
|
2
|
+
`,(0,c.jsxs)(t.h1,{id:`runtime-guards-и-validators-через-ryuzaki13react-foundation-libvalidators`,children:[`Runtime guards и validators через `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/validators`})]}),`
|
|
3
|
+
`,(0,c.jsxs)(t.p,{children:[`Модуль содержит небольшие проверки для `,(0,c.jsx)(t.code,{children:`unknown`}),`, object-like значений, image extensions, positive integer, URL и Floating UI DOM reference.`]}),`
|
|
4
|
+
`,(0,c.jsxs)(t.blockquote,{children:[`
|
|
5
|
+
`,(0,c.jsxs)(t.p,{children:[`Название функции не расширяет её контракт. Например, `,(0,c.jsx)(t.code,{children:`isSafe`}),` проверяет только отсутствие `,(0,c.jsx)(t.code,{children:`null`}),`/`,(0,c.jsx)(t.code,{children:`undefined`}),`, а `,(0,c.jsx)(t.code,{children:`isRecord`}),` допускает `,(0,c.jsx)(t.code,{children:`Date`}),` и `,(0,c.jsx)(t.code,{children:`Map`}),`. Ниже указано точное поведение каждой проверки.`]}),`
|
|
6
|
+
`]}),`
|
|
7
|
+
`,(0,c.jsx)(t.h2,{id:`содержание`,children:`Содержание`}),`
|
|
8
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
9
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D0%B8-%D0%B8%D0%BC%D0%BF%D0%BE%D1%80%D1%82`,children:`Установка и импорт`})}),`
|
|
10
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BA%D0%B0%D0%BA-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%8E%D1%82-type-guards`,children:`Как работают type guards`})}),`
|
|
11
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#issafe`,children:(0,c.jsx)(t.code,{children:`isSafe`})})}),`
|
|
12
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsxs)(t.a,{href:`#isobject-isrecord-asrecord`,children:[(0,c.jsx)(t.code,{children:`isObject`}),`, `,(0,c.jsx)(t.code,{children:`isRecord`}),`, `,(0,c.jsx)(t.code,{children:`asRecord`})]})}),`
|
|
13
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#isplainobject`,children:(0,c.jsx)(t.code,{children:`isPlainObject`})})}),`
|
|
14
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#readpositiveinteger`,children:(0,c.jsx)(t.code,{children:`readPositiveInteger`})})}),`
|
|
15
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#image-extensions`,children:`Image extensions`})}),`
|
|
16
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#isdomreference`,children:(0,c.jsx)(t.code,{children:`isDomReference`})})}),`
|
|
17
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#validateurl`,children:(0,c.jsx)(t.code,{children:`validateUrl`})})}),`
|
|
18
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#security-boundary`,children:`Security boundary`})}),`
|
|
19
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9-api`,children:`Полный API`})}),`
|
|
20
|
+
`]}),`
|
|
21
|
+
`,(0,c.jsx)(t.h2,{id:`установка-и-импорт`,children:`Установка и импорт`}),`
|
|
22
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import {
|
|
23
|
+
asRecord,
|
|
24
|
+
IMAGE_EXTENSIONS,
|
|
25
|
+
isDomReference,
|
|
26
|
+
isImageExtension,
|
|
27
|
+
isObject,
|
|
28
|
+
isPlainObject,
|
|
29
|
+
isRecord,
|
|
30
|
+
isSafe,
|
|
31
|
+
readPositiveInteger,
|
|
32
|
+
validateUrl
|
|
33
|
+
} from "@ryuzaki13/react-foundation-lib/validators";
|
|
34
|
+
`})}),`
|
|
35
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`isDomReference`}),` использует type из `,(0,c.jsx)(t.code,{children:`@floating-ui/react`}),`; host entrypoint должен разрешить совместимую peer dependency. Остальные функции не требуют React.`]}),`
|
|
36
|
+
`,(0,c.jsx)(t.h2,{id:`как-работают-type-guards`,children:`Как работают type guards`}),`
|
|
37
|
+
`,(0,c.jsx)(t.p,{children:`Type guard возвращает boolean и помогает TypeScript сузить значение:`}),`
|
|
38
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`function readCode(value: unknown): string | undefined {
|
|
39
|
+
if (!isRecord(value)) return undefined;
|
|
40
|
+
return typeof value.code === "string" ? value.code : undefined;
|
|
41
|
+
}
|
|
42
|
+
`})}),`
|
|
43
|
+
`,(0,c.jsx)(t.p,{children:`Guard не преобразует значение и не гарантирует поля, которые сам не проверил.`}),`
|
|
44
|
+
`,(0,c.jsx)(t.h2,{id:`issafe`,children:(0,c.jsx)(t.code,{children:`isSafe`})}),`
|
|
45
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`function isSafe<T>(value: T | null | undefined): value is T;
|
|
46
|
+
`})}),`
|
|
47
|
+
`,(0,c.jsxs)(t.p,{children:[`Возвращает `,(0,c.jsx)(t.code,{children:`false`}),` только для `,(0,c.jsx)(t.code,{children:`null`}),` и `,(0,c.jsx)(t.code,{children:`undefined`}),`:`]}),`
|
|
48
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`[0, "", false, null, undefined, "ok"].filter(isSafe);
|
|
49
|
+
// [0, "", false, "ok"].
|
|
50
|
+
`})}),`
|
|
51
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`0`}),`, пустая строка и `,(0,c.jsx)(t.code,{children:`false`}),` являются безопасными в смысле этой функции. `,(0,c.jsx)(t.code,{children:`isSafe`}),` не проверяет XSS, SQL, URL, число, object schema или authorization.`]}),`
|
|
52
|
+
`,(0,c.jsxs)(t.h2,{id:`isobject-isrecord-asrecord`,children:[(0,c.jsx)(t.code,{children:`isObject`}),`, `,(0,c.jsx)(t.code,{children:`isRecord`}),`, `,(0,c.jsx)(t.code,{children:`asRecord`})]}),`
|
|
53
|
+
`,(0,c.jsxs)(t.p,{children:[`Три функции используют одинаковую базовую проверку: значение truthy, `,(0,c.jsx)(t.code,{children:`typeof === "object"`}),`, не array.`]}),`
|
|
54
|
+
`,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Вход`}),(0,c.jsxs)(t.th,{style:{textAlign:`center`},children:[(0,c.jsx)(t.code,{children:`isObject`}),` / `,(0,c.jsx)(t.code,{children:`isRecord`})]}),(0,c.jsx)(t.th,{children:(0,c.jsx)(t.code,{children:`asRecord`})})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`{}`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`true`})}),(0,c.jsx)(t.td,{children:`тот же object`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`new Date()`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`true`})}),(0,c.jsx)(t.td,{children:`тот же Date, типизированный как record`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`new Map()`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`true`})}),(0,c.jsx)(t.td,{children:`тот же Map`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`DOM element`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`true`})}),(0,c.jsx)(t.td,{children:`тот же element`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`[]`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`false`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`null`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`null`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`false`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`null`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`function`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`false`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`null`})})]})]})]}),`
|
|
55
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`isObject`}),` сужает до `,(0,c.jsx)(t.code,{children:`object`}),`, `,(0,c.jsx)(t.code,{children:`isRecord`}),` — до `,(0,c.jsx)(t.code,{children:`Record<string, unknown>`}),`, `,(0,c.jsx)(t.code,{children:`asRecord`}),` возвращает record или `,(0,c.jsx)(t.code,{children:`null`}),`.`]}),`
|
|
56
|
+
`,(0,c.jsx)(t.p,{children:`Они не проверяют plain object и не гарантируют JSON-compatible данные.`}),`
|
|
57
|
+
`,(0,c.jsx)(t.h2,{id:`isplainobject`,children:(0,c.jsx)(t.code,{children:`isPlainObject`})}),`
|
|
58
|
+
`,(0,c.jsxs)(t.p,{children:[`Возвращает `,(0,c.jsx)(t.code,{children:`true`}),`, только если prototype равен `,(0,c.jsx)(t.code,{children:`Object.prototype`}),` или `,(0,c.jsx)(t.code,{children:`null`}),`:`]}),`
|
|
59
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`isPlainObject({}); // true.
|
|
60
|
+
isPlainObject(Object.create(null)); // true.
|
|
61
|
+
isPlainObject(new Date()); // false.
|
|
62
|
+
isPlainObject(new Map()); // false.
|
|
63
|
+
`})}),`
|
|
64
|
+
`,(0,c.jsxs)(t.p,{children:[`Сигнатура принимает `,(0,c.jsx)(t.code,{children:`object`}),`, поэтому сначала сузьте `,(0,c.jsx)(t.code,{children:`unknown`}),`:`]}),`
|
|
65
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`if (isObject(value) && isPlainObject(value)) {
|
|
66
|
+
// Plain record-like object.
|
|
67
|
+
}
|
|
68
|
+
`})}),`
|
|
69
|
+
`,(0,c.jsxs)(t.p,{children:[`Прямой runtime-вызов `,(0,c.jsx)(t.code,{children:`isPlainObject(null as never)`}),` приведёт к ошибке `,(0,c.jsx)(t.code,{children:`Object.getPrototypeOf`}),`. TypeScript contract запрещает такой аргумент.`]}),`
|
|
70
|
+
`,(0,c.jsx)(t.h2,{id:`readpositiveinteger`,children:(0,c.jsx)(t.code,{children:`readPositiveInteger`})}),`
|
|
71
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`readPositiveInteger(12); // 12.
|
|
72
|
+
readPositiveInteger("12"); // 12.
|
|
73
|
+
readPositiveInteger(" 12 "); // 12.
|
|
74
|
+
readPositiveInteger(0); // undefined.
|
|
75
|
+
readPositiveInteger(-1); // undefined.
|
|
76
|
+
readPositiveInteger(1.5); // undefined.
|
|
77
|
+
readPositiveInteger("bad"); // undefined.
|
|
78
|
+
`})}),`
|
|
79
|
+
`,(0,c.jsxs)(t.p,{children:[`String преобразуется стандартным `,(0,c.jsx)(t.code,{children:`Number(value)`}),`, затем проверяются:`]}),`
|
|
80
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
81
|
+
`,(0,c.jsx)(t.li,{children:`runtime type number;`}),`
|
|
82
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`Number.isInteger`}),`;`]}),`
|
|
83
|
+
`,(0,c.jsxs)(t.li,{children:[`значение строго больше `,(0,c.jsx)(t.code,{children:`0`}),`.`]}),`
|
|
84
|
+
`]}),`
|
|
85
|
+
`,(0,c.jsxs)(t.p,{children:[`Следствия стандартного `,(0,c.jsx)(t.code,{children:`Number`}),`:`]}),`
|
|
86
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`readPositiveInteger("1e2"); // 100.
|
|
87
|
+
readPositiveInteger("0x10"); // 16.
|
|
88
|
+
readPositiveInteger(""); // undefined, потому что Number("") = 0.
|
|
89
|
+
`})}),`
|
|
90
|
+
`,(0,c.jsx)(t.p,{children:`Если формат input должен быть только decimal digits, дополнительно проверьте строковую грамматику на своей boundary.`}),`
|
|
91
|
+
`,(0,c.jsx)(t.h2,{id:`image-extensions`,children:`Image extensions`}),`
|
|
92
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`isImageExtension("PNG"); // true.
|
|
93
|
+
isImageExtension("svg"); // true.
|
|
94
|
+
isImageExtension("pdf"); // false.
|
|
95
|
+
`})}),`
|
|
96
|
+
`,(0,c.jsx)(t.p,{children:`Список:`}),`
|
|
97
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`["png", "jpg", "jpeg", "gif", "webp", "svg"];
|
|
98
|
+
`})}),`
|
|
99
|
+
`,(0,c.jsxs)(t.p,{children:[`Проверка регистронезависима через `,(0,c.jsx)(t.code,{children:`toLowerCase`}),`, но не делает trim и ожидает расширение без точки:`]}),`
|
|
100
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`isImageExtension(".png"); // false.
|
|
101
|
+
isImageExtension(" png "); // false.
|
|
102
|
+
`})}),`
|
|
103
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`IMAGE_EXTENSIONS`}),` экспортирован как изменяемый array по текущему типу. Рассматривайте его как библиотечную константу и не вызывайте `,(0,c.jsx)(t.code,{children:`push/splice`}),`.`]}),`
|
|
104
|
+
`,(0,c.jsxs)(t.p,{children:[`Расширение имени не доказывает MIME/type и безопасность содержимого. Для file/image boundary используйте `,(0,c.jsx)(t.code,{children:`/file`}),` и server-side validation.`]}),`
|
|
105
|
+
`,(0,c.jsx)(t.h2,{id:`isdomreference`,children:(0,c.jsx)(t.code,{children:`isDomReference`})}),`
|
|
106
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`if (isDomReference(floatingReference)) {
|
|
107
|
+
floatingReference.focus();
|
|
108
|
+
}
|
|
109
|
+
`})}),`
|
|
110
|
+
`,(0,c.jsxs)(t.p,{children:[`Возвращает `,(0,c.jsx)(t.code,{children:`true`}),`, только если reference является browser `,(0,c.jsx)(t.code,{children:`Element`}),`. Virtual element Floating UI и `,(0,c.jsx)(t.code,{children:`null`}),` возвращают `,(0,c.jsx)(t.code,{children:`false`}),`.`]}),`
|
|
111
|
+
`,(0,c.jsxs)(t.p,{children:[`Функция выполняет `,(0,c.jsx)(t.code,{children:`ref instanceof Element`}),`. В server runtime без global `,(0,c.jsx)(t.code,{children:`Element`}),` её вызов может привести к `,(0,c.jsx)(t.code,{children:`ReferenceError`}),`; вызывайте только в browser boundary или после проверки DOM environment.`]}),`
|
|
112
|
+
`,(0,c.jsx)(t.h2,{id:`validateurl`,children:(0,c.jsx)(t.code,{children:`validateUrl`})}),`
|
|
113
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const result = validateUrl("https://example.com/path");
|
|
114
|
+
|
|
115
|
+
if (!result.isValid) {
|
|
116
|
+
showError(result.error);
|
|
117
|
+
}
|
|
118
|
+
`})}),`
|
|
119
|
+
`,(0,c.jsx)(t.p,{children:`Возможные результаты:`}),`
|
|
120
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`{ isValid: true, error: "" }
|
|
121
|
+
{ isValid: false, error: "URL не может быть пустым" }
|
|
122
|
+
{ isValid: false, error: "URL слишком длинный" }
|
|
123
|
+
{ isValid: false, error: "URL содержит недопустимые символы" }
|
|
124
|
+
{ isValid: false, error: "Некорректный формат URL" }
|
|
125
|
+
`})}),`
|
|
126
|
+
`,(0,c.jsx)(t.p,{children:`Алгоритм:`}),`
|
|
127
|
+
`,(0,c.jsxs)(t.ol,{children:[`
|
|
128
|
+
`,(0,c.jsx)(t.li,{children:`Отклоняет пустую строку.`}),`
|
|
129
|
+
`,(0,c.jsxs)(t.li,{children:[`Если строка не начинается с lowercase `,(0,c.jsx)(t.code,{children:`http`}),`, временно добавляет `,(0,c.jsx)(t.code,{children:`https://`}),` для `,(0,c.jsx)(t.code,{children:`new URL`}),`.`]}),`
|
|
130
|
+
`,(0,c.jsxs)(t.li,{children:[`Проверяет длину исходной строки не больше `,(0,c.jsx)(t.code,{children:`2048`}),`.`]}),`
|
|
131
|
+
`,(0,c.jsx)(t.li,{children:`Применяет консервативное регулярное выражение.`}),`
|
|
132
|
+
`]}),`
|
|
133
|
+
`,(0,c.jsx)(t.p,{children:`Поддерживаемая грамматика намеренно узкая:`}),`
|
|
134
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
135
|
+
`,(0,c.jsxs)(t.li,{children:[`optional `,(0,c.jsx)(t.code,{children:`http://`}),` или `,(0,c.jsx)(t.code,{children:`https://`}),`;`]}),`
|
|
136
|
+
`,(0,c.jsx)(t.li,{children:`domain с точкой;`}),`
|
|
137
|
+
`,(0,c.jsx)(t.li,{children:`lowercase TLD длиной 2–6 по regex;`}),`
|
|
138
|
+
`,(0,c.jsx)(t.li,{children:`простой path из ограниченного набора символов.`}),`
|
|
139
|
+
`]}),`
|
|
140
|
+
`,(0,c.jsx)(t.p,{children:`Query string, hash, port, localhost, IP-адреса, internationalized domains, многие валидные Unicode/path characters и длинные современные TLD могут быть отклонены.`}),`
|
|
141
|
+
`,(0,c.jsx)(t.h2,{id:`security-boundary`,children:`Security boundary`}),`
|
|
142
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`validateUrl`}),` — UI-проверка формата, не security policy. Она не:`]}),`
|
|
143
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
144
|
+
`,(0,c.jsx)(t.li,{children:`проверяет allowlist host/protocol;`}),`
|
|
145
|
+
`,(0,c.jsx)(t.li,{children:`делает DNS resolution;`}),`
|
|
146
|
+
`,(0,c.jsx)(t.li,{children:`защищает backend от SSRF;`}),`
|
|
147
|
+
`,(0,c.jsx)(t.li,{children:`гарантирует отсутствие redirect на опасный host;`}),`
|
|
148
|
+
`,(0,c.jsx)(t.li,{children:`проверяет доступность ресурса;`}),`
|
|
149
|
+
`,(0,c.jsx)(t.li,{children:`санитизирует HTML;`}),`
|
|
150
|
+
`,(0,c.jsx)(t.li,{children:`подтверждает, что URL ведёт на изображение.`}),`
|
|
151
|
+
`]}),`
|
|
152
|
+
`,(0,c.jsx)(t.p,{children:`Для внешней навигации/запроса применяйте отдельную security policy владельца boundary.`}),`
|
|
153
|
+
`,(0,c.jsx)(t.h2,{id:`полный-api`,children:`Полный API`}),`
|
|
154
|
+
`,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Export`}),(0,c.jsx)(t.th,{children:`Точное назначение`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isSafe`})}),(0,c.jsxs)(t.td,{children:[`Исключает `,(0,c.jsx)(t.code,{children:`null`}),`/`,(0,c.jsx)(t.code,{children:`undefined`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isObject`})}),(0,c.jsx)(t.td,{children:`Non-array truthy object`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isRecord`})}),(0,c.jsx)(t.td,{children:`Та же runtime-проверка с record type`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`asRecord`})}),(0,c.jsxs)(t.td,{children:[`Record или `,(0,c.jsx)(t.code,{children:`null`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isPlainObject`})}),(0,c.jsx)(t.td,{children:`Проверяет prototype`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`readPositiveInteger`})}),(0,c.jsxs)(t.td,{children:[`Positive integer number или `,(0,c.jsx)(t.code,{children:`undefined`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`IMAGE_EXTENSIONS`})}),(0,c.jsx)(t.td,{children:`Список поддерживаемых extensions`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isImageExtension`})}),(0,c.jsx)(t.td,{children:`Регистронезависимая проверка extension`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isDomReference`})}),(0,c.jsxs)(t.td,{children:[`Floating reference является `,(0,c.jsx)(t.code,{children:`Element`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`validateUrl`})}),(0,c.jsx)(t.td,{children:`Консервативный UI URL result`})]})]})]})]})}function s(e={}){let{wrapper:t}={...n(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(o,{...e})}):o(e)}var c;function l(){return(l=e((()=>{c=t(),r(),a()})))()}l();export{s as default};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import{n as e}from"./rolldown-runtime-DkW27tQK.js";import{n as t}from"./iframe-FSp_AjJa.js";import{i as n,r}from"./react-Bl2r1tuC.js";import{l as i,m as a}from"./blocks-B5YBxaaS.js";function o(e){let t={a:`a`,code:`code`,h1:`h1`,h2:`h2`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,table:`table`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,...n(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(i,{title:`Foundation Lib/Data/XML`}),`
|
|
2
|
+
`,(0,c.jsxs)(t.h1,{id:`простые-xml-helpers-через-ryuzaki13react-foundation-libxml`,children:[`Простые XML helpers через `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/xml`})]}),`
|
|
3
|
+
`,(0,c.jsxs)(t.p,{children:[`Модуль экранирует XML-текст, строит последовательность простых полей и читает текст первого тега через `,(0,c.jsx)(t.code,{children:`DOMParser`}),`.`]}),`
|
|
4
|
+
`,(0,c.jsx)(t.h2,{id:`содержание`,children:`Содержание`}),`
|
|
5
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
6
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BD%D0%B0%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%8B`,children:`Назначение и границы`})}),`
|
|
7
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D0%B8-%D0%B8%D0%BC%D0%BF%D0%BE%D1%80%D1%82`,children:`Установка и импорт`})}),`
|
|
8
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#escapexmlvalue`,children:(0,c.jsx)(t.code,{children:`escapeXmlValue`})})}),`
|
|
9
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#buildxmlfields`,children:(0,c.jsx)(t.code,{children:`buildXmlFields`})})}),`
|
|
10
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#getxmltagtext`,children:(0,c.jsx)(t.code,{children:`getXmlTagText`})})}),`
|
|
11
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C-%D0%B8-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D1%8F`,children:`Безопасность и ограничения`})}),`
|
|
12
|
+
`,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#api`,children:`API`})}),`
|
|
13
|
+
`]}),`
|
|
14
|
+
`,(0,c.jsx)(t.h2,{id:`назначение-и-границы`,children:`Назначение и границы`}),`
|
|
15
|
+
`,(0,c.jsx)(t.p,{children:`Подходит для небольших flat XML fragments:`}),`
|
|
16
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-xml`,children:`<ORDER_ID>42</ORDER_ID><COMMENT>A&B</COMMENT>
|
|
17
|
+
`})}),`
|
|
18
|
+
`,(0,c.jsx)(t.p,{children:`Модуль не является полноценным XML builder/parser:`}),`
|
|
19
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
20
|
+
`,(0,c.jsx)(t.li,{children:`не строит document/envelope;`}),`
|
|
21
|
+
`,(0,c.jsx)(t.li,{children:`не управляет namespaces и attributes;`}),`
|
|
22
|
+
`,(0,c.jsx)(t.li,{children:`не валидирует XSD;`}),`
|
|
23
|
+
`,(0,c.jsx)(t.li,{children:`не обрабатывает коллекции/вложенные объекты;`}),`
|
|
24
|
+
`,(0,c.jsx)(t.li,{children:`не проверяет parser errors;`}),`
|
|
25
|
+
`,(0,c.jsx)(t.li,{children:`не выполняет network request.`}),`
|
|
26
|
+
`]}),`
|
|
27
|
+
`,(0,c.jsx)(t.h2,{id:`установка-и-импорт`,children:`Установка и импорт`}),`
|
|
28
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { buildXmlFields, escapeXmlValue, getXmlTagText } from "@ryuzaki13/react-foundation-lib/xml";
|
|
29
|
+
|
|
30
|
+
import type { XmlPrimitive } from "@ryuzaki13/react-foundation-lib/xml";
|
|
31
|
+
`})}),`
|
|
32
|
+
`,(0,c.jsxs)(t.p,{children:[`Builder-функции не требуют DOM. `,(0,c.jsx)(t.code,{children:`getXmlTagText`}),` требует global `,(0,c.jsx)(t.code,{children:`DOMParser`}),`, доступный в браузере/jsdom, но обычно отсутствующий в чистом Node.js.`]}),`
|
|
33
|
+
`,(0,c.jsx)(t.h2,{id:`escapexmlvalue`,children:(0,c.jsx)(t.code,{children:`escapeXmlValue`})}),`
|
|
34
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`escapeXmlValue(\`a&b<c>d"e'f\`);
|
|
35
|
+
// "a&b<c>d"e'f"
|
|
36
|
+
`})}),`
|
|
37
|
+
`,(0,c.jsx)(t.p,{children:`Тип входа:`}),`
|
|
38
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type XmlPrimitive = string | number | null | undefined;
|
|
39
|
+
`})}),`
|
|
40
|
+
`,(0,c.jsx)(t.p,{children:`Правила:`}),`
|
|
41
|
+
`,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Символ`}),(0,c.jsx)(t.th,{children:`XML entity`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`&`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`&`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`<`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`<`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`>`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`>`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`"`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`"`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`'`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`'`})})]})]})]}),`
|
|
42
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`null`}),` и `,(0,c.jsx)(t.code,{children:`undefined`}),` превращаются в пустую строку. Number сначала преобразуется через `,(0,c.jsx)(t.code,{children:`String`}),`.`]}),`
|
|
43
|
+
`,(0,c.jsx)(t.p,{children:`Функция предназначена для текстового содержимого. Для attribute value она экранирует основные символы, но сам attribute builder модуль не предоставляет.`}),`
|
|
44
|
+
`,(0,c.jsx)(t.p,{children:`Не передавайте уже экранированную строку повторно:`}),`
|
|
45
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`escapeXmlValue("A&B"); // "A&amp;B".
|
|
46
|
+
`})}),`
|
|
47
|
+
`,(0,c.jsx)(t.h2,{id:`buildxmlfields`,children:(0,c.jsx)(t.code,{children:`buildXmlFields`})}),`
|
|
48
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const xml = buildXmlFields({
|
|
49
|
+
ORDER_ID: 42,
|
|
50
|
+
COMMENT: "A&B",
|
|
51
|
+
OPTIONAL: null
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// <ORDER_ID>42</ORDER_ID><COMMENT>A&B</COMMENT><OPTIONAL></OPTIONAL>
|
|
55
|
+
`})}),`
|
|
56
|
+
`,(0,c.jsx)(t.p,{children:`Функция:`}),`
|
|
57
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
58
|
+
`,(0,c.jsxs)(t.li,{children:[`обходит `,(0,c.jsx)(t.code,{children:`Object.entries`}),` в стандартном порядке ключей;`]}),`
|
|
59
|
+
`,(0,c.jsxs)(t.li,{children:[`строит для каждого поля `,(0,c.jsx)(t.code,{children:`<NAME>escaped value</NAME>`}),`;`]}),`
|
|
60
|
+
`,(0,c.jsx)(t.li,{children:`не добавляет переносы строк;`}),`
|
|
61
|
+
`,(0,c.jsxs)(t.li,{children:[`сохраняет поля с `,(0,c.jsx)(t.code,{children:`null`}),`/`,(0,c.jsx)(t.code,{children:`undefined`}),` как пустые теги;`]}),`
|
|
62
|
+
`,(0,c.jsx)(t.li,{children:`не изменяет исходный объект.`}),`
|
|
63
|
+
`]}),`
|
|
64
|
+
`,(0,c.jsx)(t.p,{children:`Имя тега вставляется без валидации и escaping. Ключи должны быть доверенными валидными XML names из программного contract:`}),`
|
|
65
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`// Нельзя строить key из пользовательского ввода.
|
|
66
|
+
buildXmlFields({ [userProvidedTagName]: value });
|
|
67
|
+
`})}),`
|
|
68
|
+
`,(0,c.jsxs)(t.p,{children:[`Для вложенной структуры передайте уже собранный fragment как часть внешнего builder-а; `,(0,c.jsx)(t.code,{children:`buildXmlFields`}),` сам воспринимает строку как текст и экранирует markup.`]}),`
|
|
69
|
+
`,(0,c.jsx)(t.h2,{id:`getxmltagtext`,children:(0,c.jsx)(t.code,{children:`getXmlTagText`})}),`
|
|
70
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const message = getXmlTagText("<root><EX_MESSAGE> Ошибка </EX_MESSAGE></root>", "EX_MESSAGE");
|
|
71
|
+
|
|
72
|
+
console.log(message); // "Ошибка".
|
|
73
|
+
`})}),`
|
|
74
|
+
`,(0,c.jsx)(t.p,{children:`Алгоритм:`}),`
|
|
75
|
+
`,(0,c.jsxs)(t.ol,{children:[`
|
|
76
|
+
`,(0,c.jsxs)(t.li,{children:[`Парсит всю строку как `,(0,c.jsx)(t.code,{children:`application/xml`}),`.`]}),`
|
|
77
|
+
`,(0,c.jsxs)(t.li,{children:[`Вызывает `,(0,c.jsx)(t.code,{children:`getElementsByTagName(tagName)`}),`.`]}),`
|
|
78
|
+
`,(0,c.jsx)(t.li,{children:`Берёт только первый найденный element.`}),`
|
|
79
|
+
`,(0,c.jsxs)(t.li,{children:[`Читает объединённый `,(0,c.jsx)(t.code,{children:`textContent`}),`.`]}),`
|
|
80
|
+
`,(0,c.jsx)(t.li,{children:`Обрезает пробелы.`}),`
|
|
81
|
+
`,(0,c.jsxs)(t.li,{children:[`Возвращает `,(0,c.jsx)(t.code,{children:`undefined`}),`, если элемента/непустого текста нет.`]}),`
|
|
82
|
+
`]}),`
|
|
83
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`getXmlTagText("<root />", "MESSAGE"); // undefined.
|
|
84
|
+
getXmlTagText("<root><MESSAGE> </MESSAGE></root>", "MESSAGE"); // undefined.
|
|
85
|
+
`})}),`
|
|
86
|
+
`,(0,c.jsxs)(t.p,{children:[`Для namespace-sensitive XML точное поведение `,(0,c.jsx)(t.code,{children:`getElementsByTagName`}),` зависит от переданного имени. Модуль не предоставляет `,(0,c.jsx)(t.code,{children:`getElementsByTagNameNS`}),`.`]}),`
|
|
87
|
+
`,(0,c.jsx)(t.h2,{id:`безопасность-и-ограничения`,children:`Безопасность и ограничения`}),`
|
|
88
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
89
|
+
`,(0,c.jsxs)(t.li,{children:[`Не вставляйте результат XML в HTML DOM через `,(0,c.jsx)(t.code,{children:`innerHTML`}),`.`]}),`
|
|
90
|
+
`,(0,c.jsx)(t.li,{children:`Не используйте dynamic tag names из недоверенного ввода.`}),`
|
|
91
|
+
`,(0,c.jsxs)(t.li,{children:[`Parser не проверяется на `,(0,c.jsx)(t.code,{children:`<parsererror>`}),`; malformed XML обычно даёт `,(0,c.jsx)(t.code,{children:`undefined`}),` или parser-specific tree, а не явное исключение этого helper.`]}),`
|
|
92
|
+
`,(0,c.jsx)(t.li,{children:`Читается только первое совпадение.`}),`
|
|
93
|
+
`,(0,c.jsx)(t.li,{children:`Большие documents лучше разбирать специализированным parser/streaming boundary.`}),`
|
|
94
|
+
`,(0,c.jsx)(t.li,{children:`Модуль не предотвращает XML signature wrapping и не предназначен для security validation.`}),`
|
|
95
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`XmlPrimitive`}),` number допускает `,(0,c.jsx)(t.code,{children:`NaN`}),`/`,(0,c.jsx)(t.code,{children:`Infinity`}),` на уровне TypeScript; они станут строками `,(0,c.jsx)(t.code,{children:`"NaN"`}),`/`,(0,c.jsx)(t.code,{children:`"Infinity"`}),`.`]}),`
|
|
96
|
+
`]}),`
|
|
97
|
+
`,(0,c.jsx)(t.h2,{id:`api`,children:`API`}),`
|
|
98
|
+
`,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Export`}),(0,c.jsx)(t.th,{children:`Результат`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`escapeXmlValue`})}),(0,c.jsx)(t.td,{children:`Экранированная строка`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`buildXmlFields`})}),(0,c.jsx)(t.td,{children:`Компактный XML fragment`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`getXmlTagText`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`string | undefined`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`XmlPrimitive`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`string | number | null | undefined`})})]})]})]})]})}function s(e={}){let{wrapper:t}={...n(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(o,{...e})}):o(e)}var c;function l(){return(l=e((()=>{c=t(),r(),a()})))()}l();export{s as default};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import{n as e}from"./rolldown-runtime-DkW27tQK.js";import{n as t}from"./iframe-FSp_AjJa.js";import{i as n,r}from"./react-Bl2r1tuC.js";import{l as i,m as a}from"./blocks-B5YBxaaS.js";function o(e){let t={code:`code`,h1:`h1`,h2:`h2`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,table:`table`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,...n(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(i,{title:`Foundation API/Errors/Error Report Delivery`}),`
|
|
2
|
+
`,(0,c.jsxs)(t.h1,{id:`доставка-error-reports-через-ryuzaki13react-foundation-apierror-report`,children:[`Доставка error reports через `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-api/error-report`})]}),`
|
|
3
|
+
`,(0,c.jsxs)(t.p,{children:[`Модуль превращает сохранённый черновик отчёта из `,(0,c.jsx)(t.code,{children:`foundation-lib`}),` в delivery body, вызывает adapter приложения и обновляет статус черновика.`]}),`
|
|
4
|
+
`,(0,c.jsx)(t.h2,{id:`граница-ответственности`,children:`Граница ответственности`}),`
|
|
5
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`foundation-lib/error-report foundation-api/error-report host backend adapter
|
|
6
|
+
collect + sanitize + draft store ──► lifecycle + delivery body ─────► HTTP/OData/serverFn
|
|
7
|
+
`})}),`
|
|
8
|
+
`,(0,c.jsxs)(t.p,{children:[`Модуль не собирает browser diagnostics, не выбирает endpoint и не отправляет запрос самостоятельно. Transport явно передаёт приложение через `,(0,c.jsx)(t.code,{children:`adapter`}),`.`]}),`
|
|
9
|
+
`,(0,c.jsx)(t.h2,{id:`установка-и-импорт`,children:`Установка и импорт`}),`
|
|
10
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import {
|
|
11
|
+
createErrorReportDeliveryBody,
|
|
12
|
+
sendErrorReport
|
|
13
|
+
} from "@ryuzaki13/react-foundation-api/error-report";
|
|
14
|
+
|
|
15
|
+
import type {
|
|
16
|
+
ErrorReportDeliveryAdapter,
|
|
17
|
+
ErrorReportDeliveryBody,
|
|
18
|
+
ErrorReportDeliveryContext,
|
|
19
|
+
SendErrorReportOptions
|
|
20
|
+
} from "@ryuzaki13/react-foundation-api/error-report";
|
|
21
|
+
`})}),`
|
|
22
|
+
`,(0,c.jsxs)(t.p,{children:[`Нужны `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib`}),` и `,(0,c.jsx)(t.code,{children:`@tanstack/react-query`}),`.`]}),`
|
|
23
|
+
`,(0,c.jsx)(t.h2,{id:`полный-сценарий`,children:`Полный сценарий`}),`
|
|
24
|
+
`,(0,c.jsxs)(t.p,{children:[`Сначала другой слой создаёт и сохраняет draft средствами `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/error-report`}),`. Затем API-слой получает только его `,(0,c.jsx)(t.code,{children:`reportId`}),`:`]}),`
|
|
25
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { httpFetchPayload } from "@ryuzaki13/react-foundation-api/http";
|
|
26
|
+
import { sendErrorReport } from "@ryuzaki13/react-foundation-api/error-report";
|
|
27
|
+
import type { ErrorReportDeliveryAdapter } from "@ryuzaki13/react-foundation-api/error-report";
|
|
28
|
+
|
|
29
|
+
const deliveryAdapter: ErrorReportDeliveryAdapter = async (body) => {
|
|
30
|
+
await httpFetchPayload("/api/error-reports", {
|
|
31
|
+
init: {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { "Content-Type": "application/json" },
|
|
34
|
+
body: JSON.stringify(body)
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
await sendErrorReport(reportId, {
|
|
40
|
+
adapter: deliveryAdapter,
|
|
41
|
+
queryClient
|
|
42
|
+
});
|
|
43
|
+
`})}),`
|
|
44
|
+
`,(0,c.jsx)(t.h2,{id:`createerrorreportdeliverybody`,children:(0,c.jsx)(t.code,{children:`createErrorReportDeliveryBody`})}),`
|
|
45
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const body = createErrorReportDeliveryBody(draft);
|
|
46
|
+
`})}),`
|
|
47
|
+
`,(0,c.jsx)(t.p,{children:`Результат:`}),`
|
|
48
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type ErrorReportDeliveryBody = {
|
|
49
|
+
reportId: string;
|
|
50
|
+
sessionId: string;
|
|
51
|
+
createdUtc: string;
|
|
52
|
+
category: ErrorReportCategory;
|
|
53
|
+
errorClass: string;
|
|
54
|
+
errorMessage: string;
|
|
55
|
+
stackTrace?: string;
|
|
56
|
+
payload: string;
|
|
57
|
+
};
|
|
58
|
+
`})}),`
|
|
59
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`payload`}),` — JSON string всего payload черновика, а не вложенный object. Это важно для backend contract.`]}),`
|
|
60
|
+
`,(0,c.jsxs)(t.p,{children:[`Если `,(0,c.jsx)(t.code,{children:`draft.payload.error.message`}),` пуст, обязательные `,(0,c.jsx)(t.code,{children:`errorMessage`}),` и message внутри сериализованного payload получают значение `,(0,c.jsx)(t.code,{children:`"Неизвестная ошибка"`}),`. Остальной draft не нормализуется.`]}),`
|
|
61
|
+
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`JSON.stringify`}),` может выбросить ошибку при циклических или неподдерживаемых данных. Draft должен соответствовать сериализуемому контракту `,(0,c.jsx)(t.code,{children:`foundation-lib`}),`.`]}),`
|
|
62
|
+
`,(0,c.jsx)(t.h2,{id:`senderrorreport`,children:(0,c.jsx)(t.code,{children:`sendErrorReport`})}),`
|
|
63
|
+
`,(0,c.jsx)(t.p,{children:`Lifecycle:`}),`
|
|
64
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`draft отсутствует ─────────► undefined
|
|
65
|
+
status sent/sending ───────► текущий draft, adapter не вызывается
|
|
66
|
+
остальной draft ───────────► sending
|
|
67
|
+
│
|
|
68
|
+
adapter success / error
|
|
69
|
+
│ │
|
|
70
|
+
▼ ▼
|
|
71
|
+
sent failed + failedReason
|
|
72
|
+
`})}),`
|
|
73
|
+
`,(0,c.jsx)(t.p,{children:`Пошагово функция:`}),`
|
|
74
|
+
`,(0,c.jsxs)(t.ol,{children:[`
|
|
75
|
+
`,(0,c.jsxs)(t.li,{children:[`Ищет draft по `,(0,c.jsx)(t.code,{children:`reportId`}),` в store из `,(0,c.jsx)(t.code,{children:`foundation-lib`}),`.`]}),`
|
|
76
|
+
`,(0,c.jsxs)(t.li,{children:[`Возвращает `,(0,c.jsx)(t.code,{children:`undefined`}),`, если draft не найден.`]}),`
|
|
77
|
+
`,(0,c.jsxs)(t.li,{children:[`Не отправляет повторно draft со статусом `,(0,c.jsx)(t.code,{children:`sent`}),` или `,(0,c.jsx)(t.code,{children:`sending`}),`.`]}),`
|
|
78
|
+
`,(0,c.jsxs)(t.li,{children:[`Устанавливает `,(0,c.jsx)(t.code,{children:`status: "sending"`}),` и очищает `,(0,c.jsx)(t.code,{children:`failedReason`}),`.`]}),`
|
|
79
|
+
`,(0,c.jsx)(t.li,{children:`Создаёт delivery body.`}),`
|
|
80
|
+
`,(0,c.jsxs)(t.li,{children:[`Вызывает `,(0,c.jsx)(t.code,{children:`adapter(body, { draft, queryClient })`}),`.`]}),`
|
|
81
|
+
`,(0,c.jsxs)(t.li,{children:[`При успехе устанавливает `,(0,c.jsx)(t.code,{children:`status: "sent"`}),` и `,(0,c.jsx)(t.code,{children:`sentUtc`}),`.`]}),`
|
|
82
|
+
`,(0,c.jsxs)(t.li,{children:[`При ошибке устанавливает `,(0,c.jsx)(t.code,{children:`status: "failed"`}),`, сохраняет нормализованное сообщение и повторно бросает исходную ошибку.`]}),`
|
|
83
|
+
`]}),`
|
|
84
|
+
`,(0,c.jsxs)(t.p,{children:[`Adapter получает исходный snapshot `,(0,c.jsx)(t.code,{children:`draft`}),`, прочитанный до перевода store в `,(0,c.jsx)(t.code,{children:`sending`}),`. Используйте `,(0,c.jsx)(t.code,{children:`body`}),` как delivery payload, а context — для query invalidation или transport, которому нужен `,(0,c.jsx)(t.code,{children:`QueryClient`}),`.`]}),`
|
|
85
|
+
`,(0,c.jsx)(t.h2,{id:`adapter-с-cache-invalidation`,children:`Adapter с cache invalidation`}),`
|
|
86
|
+
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const adapter: ErrorReportDeliveryAdapter = async (body, { queryClient }) => {
|
|
87
|
+
await postReport(body);
|
|
88
|
+
await queryClient.invalidateQueries({ queryKey: ["error-reports"] });
|
|
89
|
+
};
|
|
90
|
+
`})}),`
|
|
91
|
+
`,(0,c.jsxs)(t.p,{children:[`Если invalidation бросит ошибку, вся доставка считается неуспешной и draft станет `,(0,c.jsx)(t.code,{children:`failed`}),`, даже если backend уже принял отчёт. Для non-critical cache update обработайте ошибку внутри adapter-а.`]}),`
|
|
92
|
+
`,(0,c.jsx)(t.h2,{id:`повторная-отправка-и-concurrency`,children:`Повторная отправка и concurrency`}),`
|
|
93
|
+
`,(0,c.jsxs)(t.p,{children:[`После `,(0,c.jsx)(t.code,{children:`failed`}),` функцию можно вызвать повторно. Проверка `,(0,c.jsx)(t.code,{children:`sending`}),` защищает от обычного повторного нажатия, но это не распределённая блокировка: два практически одновременных вызова могут успеть прочитать старый статус до его обновления. Backend желательно сделать идемпотентным по `,(0,c.jsx)(t.code,{children:`reportId`}),`.`]}),`
|
|
94
|
+
`,(0,c.jsx)(t.h2,{id:`ошибки-и-безопасность`,children:`Ошибки и безопасность`}),`
|
|
95
|
+
`,(0,c.jsxs)(t.ul,{children:[`
|
|
96
|
+
`,(0,c.jsx)(t.li,{children:`Ошибка adapter-а не поглощается: вызывающий код обязан её обработать.`}),`
|
|
97
|
+
`,(0,c.jsx)(t.li,{children:`Не добавляйте secrets в draft. Delivery layer не выполняет дополнительную redaction всего payload.`}),`
|
|
98
|
+
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`queryClient`}),` передаётся adapter-у, но модуль сам не инвалидирует queries.`]}),`
|
|
99
|
+
`,(0,c.jsx)(t.li,{children:`Функция управляет локальным draft store; не вызывайте её в среде без подходящего storage/runtime, если draft store там недоступен.`}),`
|
|
100
|
+
`,(0,c.jsxs)(t.li,{children:[`Статус `,(0,c.jsx)(t.code,{children:`sent`}),` означает успешное завершение adapter-а, а не обязательное подтверждение бизнес-обработки backend-ом.`]}),`
|
|
101
|
+
`]}),`
|
|
102
|
+
`,(0,c.jsx)(t.h2,{id:`полный-api`,children:`Полный API`}),`
|
|
103
|
+
`,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Export`}),(0,c.jsx)(t.th,{children:`Назначение`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`createErrorReportDeliveryBody`})}),(0,c.jsx)(t.td,{children:`Строит сериализуемый backend body`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`sendErrorReport`})}),(0,c.jsx)(t.td,{children:`Управляет status и вызывает adapter`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ErrorReportDeliveryBody`})}),(0,c.jsx)(t.td,{children:`Поля delivery payload`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ErrorReportDeliveryContext`})}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`draft`}),` и `,(0,c.jsx)(t.code,{children:`queryClient`}),` для adapter-а`]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ErrorReportDeliveryAdapter`})}),(0,c.jsx)(t.td,{children:`Контракт функции доставки`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`SendErrorReportOptions`})}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`adapter`}),` и `,(0,c.jsx)(t.code,{children:`queryClient`})]})]})]})]})]})}function s(e={}){let{wrapper:t}={...n(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(o,{...e})}):o(e)}var c;function l(){return(l=e((()=>{c=t(),r(),a()})))()}l();export{s as default};
|