diff --git a/.yarn/cache/@babel-code-frame-npm-7.23.4-6d00006250-29999d08c3.zip b/.yarn/cache/@babel-code-frame-npm-7.23.4-6d00006250-29999d08c3.zip new file mode 100644 index 0000000000..bdb4e67c63 Binary files /dev/null and b/.yarn/cache/@babel-code-frame-npm-7.23.4-6d00006250-29999d08c3.zip differ diff --git a/.yarn/cache/@babel-core-npm-7.23.3-9c9bbb2dbe-d306c1fa68.zip b/.yarn/cache/@babel-core-npm-7.23.3-9c9bbb2dbe-d306c1fa68.zip new file mode 100644 index 0000000000..48ba4856fa Binary files /dev/null and b/.yarn/cache/@babel-core-npm-7.23.3-9c9bbb2dbe-d306c1fa68.zip differ diff --git a/.yarn/cache/@babel-generator-npm-7.23.4-bcbc7aaa76-7403717002.zip b/.yarn/cache/@babel-generator-npm-7.23.4-bcbc7aaa76-7403717002.zip new file mode 100644 index 0000000000..3a30d5a1e6 Binary files /dev/null and b/.yarn/cache/@babel-generator-npm-7.23.4-bcbc7aaa76-7403717002.zip differ diff --git a/.yarn/cache/@babel-helper-compilation-targets-npm-7.22.15-7aac9e71ad-ce85196769.zip b/.yarn/cache/@babel-helper-compilation-targets-npm-7.22.15-7aac9e71ad-ce85196769.zip new file mode 100644 index 0000000000..263502bc8d Binary files /dev/null and b/.yarn/cache/@babel-helper-compilation-targets-npm-7.22.15-7aac9e71ad-ce85196769.zip differ diff --git a/.yarn/cache/@babel-helper-module-imports-npm-7.22.15-687e77ee50-ecd7e457df.zip b/.yarn/cache/@babel-helper-module-imports-npm-7.22.15-687e77ee50-ecd7e457df.zip new file mode 100644 index 0000000000..b200eaa8bf Binary files /dev/null and b/.yarn/cache/@babel-helper-module-imports-npm-7.22.15-687e77ee50-ecd7e457df.zip differ diff --git a/.yarn/cache/@babel-helper-module-transforms-npm-7.23.3-69078a931c-5d0895cfba.zip b/.yarn/cache/@babel-helper-module-transforms-npm-7.23.3-69078a931c-5d0895cfba.zip new file mode 100644 index 0000000000..1fbece28b4 Binary files /dev/null and b/.yarn/cache/@babel-helper-module-transforms-npm-7.23.3-69078a931c-5d0895cfba.zip differ diff --git a/.yarn/cache/@babel-helper-string-parser-npm-7.23.4-b1f0d030c3-c0641144cf.zip b/.yarn/cache/@babel-helper-string-parser-npm-7.23.4-b1f0d030c3-c0641144cf.zip new file mode 100644 index 0000000000..1cf46fb0b3 Binary files /dev/null and b/.yarn/cache/@babel-helper-string-parser-npm-7.23.4-b1f0d030c3-c0641144cf.zip differ diff --git a/.yarn/cache/@babel-helper-validator-option-npm-7.22.15-29aa330042-68da52b1e1.zip b/.yarn/cache/@babel-helper-validator-option-npm-7.22.15-29aa330042-68da52b1e1.zip new file mode 100644 index 0000000000..3ee766e0eb Binary files /dev/null and b/.yarn/cache/@babel-helper-validator-option-npm-7.22.15-29aa330042-68da52b1e1.zip differ diff --git a/.yarn/cache/@babel-helpers-npm-7.23.4-25daffa206-85677834f2.zip b/.yarn/cache/@babel-helpers-npm-7.23.4-25daffa206-85677834f2.zip new file mode 100644 index 0000000000..b0f1382b5e Binary files /dev/null and b/.yarn/cache/@babel-helpers-npm-7.23.4-25daffa206-85677834f2.zip differ diff --git a/.yarn/cache/@babel-highlight-npm-7.23.4-2a9f2d2538-643acecdc2.zip b/.yarn/cache/@babel-highlight-npm-7.23.4-2a9f2d2538-643acecdc2.zip new file mode 100644 index 0000000000..a2eba6d867 Binary files /dev/null and b/.yarn/cache/@babel-highlight-npm-7.23.4-2a9f2d2538-643acecdc2.zip differ diff --git a/.yarn/cache/@babel-parser-npm-7.23.4-f713fe348e-1d90e17d96.zip b/.yarn/cache/@babel-parser-npm-7.23.4-f713fe348e-1d90e17d96.zip new file mode 100644 index 0000000000..3604f27bca Binary files /dev/null and b/.yarn/cache/@babel-parser-npm-7.23.4-f713fe348e-1d90e17d96.zip differ diff --git a/.yarn/cache/@babel-traverse-npm-7.23.4-afa9bb9438-e8c9cd92cf.zip b/.yarn/cache/@babel-traverse-npm-7.23.4-afa9bb9438-e8c9cd92cf.zip new file mode 100644 index 0000000000..851f9e788d Binary files /dev/null and b/.yarn/cache/@babel-traverse-npm-7.23.4-afa9bb9438-e8c9cd92cf.zip differ diff --git a/.yarn/cache/@babel-types-npm-7.23.4-cd82933a3d-8a1ab20da6.zip b/.yarn/cache/@babel-types-npm-7.23.4-cd82933a3d-8a1ab20da6.zip new file mode 100644 index 0000000000..6ecd3b7ef9 Binary files /dev/null and b/.yarn/cache/@babel-types-npm-7.23.4-cd82933a3d-8a1ab20da6.zip differ diff --git a/.yarn/cache/@joshwooding-vite-plugin-react-docgen-typescript-npm-0.2.1-ea6cd6307b-91401505b3.zip b/.yarn/cache/@joshwooding-vite-plugin-react-docgen-typescript-npm-0.3.0-e20c4a4bd6-3fe2dc68dc.zip similarity index 53% rename from .yarn/cache/@joshwooding-vite-plugin-react-docgen-typescript-npm-0.2.1-ea6cd6307b-91401505b3.zip rename to .yarn/cache/@joshwooding-vite-plugin-react-docgen-typescript-npm-0.3.0-e20c4a4bd6-3fe2dc68dc.zip index 2f6fbc06e4..6f2ddef24b 100644 Binary files a/.yarn/cache/@joshwooding-vite-plugin-react-docgen-typescript-npm-0.2.1-ea6cd6307b-91401505b3.zip and b/.yarn/cache/@joshwooding-vite-plugin-react-docgen-typescript-npm-0.3.0-e20c4a4bd6-3fe2dc68dc.zip differ diff --git a/.yarn/cache/@radix-ui-react-roving-focus-npm-1.0.4-7106f3083a-69b1c82c2d.zip b/.yarn/cache/@radix-ui-react-roving-focus-npm-1.0.4-7106f3083a-69b1c82c2d.zip new file mode 100644 index 0000000000..4c80363c26 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-roving-focus-npm-1.0.4-7106f3083a-69b1c82c2d.zip differ diff --git a/.yarn/cache/@radix-ui-react-separator-npm-1.0.3-a8fd4c57de-42f8c95e40.zip b/.yarn/cache/@radix-ui-react-separator-npm-1.0.3-a8fd4c57de-42f8c95e40.zip new file mode 100644 index 0000000000..c8dc2401f0 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-separator-npm-1.0.3-a8fd4c57de-42f8c95e40.zip differ diff --git a/.yarn/cache/@radix-ui-react-toggle-group-npm-1.0.4-8ed5373168-b6c11fbbc3.zip b/.yarn/cache/@radix-ui-react-toggle-group-npm-1.0.4-8ed5373168-b6c11fbbc3.zip new file mode 100644 index 0000000000..eec9b3ac83 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-toggle-group-npm-1.0.4-8ed5373168-b6c11fbbc3.zip differ diff --git a/.yarn/cache/@radix-ui-react-toggle-npm-1.0.3-815cae4672-ed5407f482.zip b/.yarn/cache/@radix-ui-react-toggle-npm-1.0.3-815cae4672-ed5407f482.zip new file mode 100644 index 0000000000..65abcf1e0e Binary files /dev/null and b/.yarn/cache/@radix-ui-react-toggle-npm-1.0.3-815cae4672-ed5407f482.zip differ diff --git a/.yarn/cache/@radix-ui-react-toolbar-npm-1.0.4-0625e3aacc-7ebee1f8ad.zip b/.yarn/cache/@radix-ui-react-toolbar-npm-1.0.4-0625e3aacc-7ebee1f8ad.zip new file mode 100644 index 0000000000..22138a7d97 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-toolbar-npm-1.0.4-0625e3aacc-7ebee1f8ad.zip differ diff --git a/.yarn/cache/@storybook-addon-a11y-npm-7.2.0-883314ce28-255a8be298.zip b/.yarn/cache/@storybook-addon-a11y-npm-7.5.3-68759ed315-93cf28fcfc.zip similarity index 89% rename from .yarn/cache/@storybook-addon-a11y-npm-7.2.0-883314ce28-255a8be298.zip rename to .yarn/cache/@storybook-addon-a11y-npm-7.5.3-68759ed315-93cf28fcfc.zip index f4049c2afe..b6fc05c833 100644 Binary files a/.yarn/cache/@storybook-addon-a11y-npm-7.2.0-883314ce28-255a8be298.zip and b/.yarn/cache/@storybook-addon-a11y-npm-7.5.3-68759ed315-93cf28fcfc.zip differ diff --git a/.yarn/cache/@storybook-addon-actions-npm-7.2.0-ff0b8d5b1e-53a7aa40a8.zip b/.yarn/cache/@storybook-addon-actions-npm-7.5.3-7e0d06323f-d79baf1da3.zip similarity index 76% rename from .yarn/cache/@storybook-addon-actions-npm-7.2.0-ff0b8d5b1e-53a7aa40a8.zip rename to .yarn/cache/@storybook-addon-actions-npm-7.5.3-7e0d06323f-d79baf1da3.zip index ed3180f5cd..e575920eb2 100644 Binary files a/.yarn/cache/@storybook-addon-actions-npm-7.2.0-ff0b8d5b1e-53a7aa40a8.zip and b/.yarn/cache/@storybook-addon-actions-npm-7.5.3-7e0d06323f-d79baf1da3.zip differ diff --git a/.yarn/cache/@storybook-addon-backgrounds-npm-7.2.0-a6bbb634ce-3d727d1c72.zip b/.yarn/cache/@storybook-addon-backgrounds-npm-7.2.0-a6bbb634ce-3d727d1c72.zip deleted file mode 100644 index 9ba488ec30..0000000000 Binary files a/.yarn/cache/@storybook-addon-backgrounds-npm-7.2.0-a6bbb634ce-3d727d1c72.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-addon-backgrounds-npm-7.5.3-fc73c6cf8b-6a432d490a.zip b/.yarn/cache/@storybook-addon-backgrounds-npm-7.5.3-fc73c6cf8b-6a432d490a.zip new file mode 100644 index 0000000000..1acf1a1a3b Binary files /dev/null and b/.yarn/cache/@storybook-addon-backgrounds-npm-7.5.3-fc73c6cf8b-6a432d490a.zip differ diff --git a/.yarn/cache/@storybook-addon-controls-npm-7.2.0-c0c7de568a-078a833711.zip b/.yarn/cache/@storybook-addon-controls-npm-7.5.3-6e1a703c4e-c86f8da8a3.zip similarity index 50% rename from .yarn/cache/@storybook-addon-controls-npm-7.2.0-c0c7de568a-078a833711.zip rename to .yarn/cache/@storybook-addon-controls-npm-7.5.3-6e1a703c4e-c86f8da8a3.zip index 996cd79b1c..d644903745 100644 Binary files a/.yarn/cache/@storybook-addon-controls-npm-7.2.0-c0c7de568a-078a833711.zip and b/.yarn/cache/@storybook-addon-controls-npm-7.5.3-6e1a703c4e-c86f8da8a3.zip differ diff --git a/.yarn/cache/@storybook-addon-docs-npm-7.2.0-e411177355-c4ed5cbc8b.zip b/.yarn/cache/@storybook-addon-docs-npm-7.5.3-a70b3f79db-54ef17505c.zip similarity index 55% rename from .yarn/cache/@storybook-addon-docs-npm-7.2.0-e411177355-c4ed5cbc8b.zip rename to .yarn/cache/@storybook-addon-docs-npm-7.5.3-a70b3f79db-54ef17505c.zip index 42cedea197..62342c81ed 100644 Binary files a/.yarn/cache/@storybook-addon-docs-npm-7.2.0-e411177355-c4ed5cbc8b.zip and b/.yarn/cache/@storybook-addon-docs-npm-7.5.3-a70b3f79db-54ef17505c.zip differ diff --git a/.yarn/cache/@storybook-addon-essentials-npm-7.2.0-e689506b9c-3fe6fac252.zip b/.yarn/cache/@storybook-addon-essentials-npm-7.5.3-73eb43a281-57341a40f9.zip similarity index 79% rename from .yarn/cache/@storybook-addon-essentials-npm-7.2.0-e689506b9c-3fe6fac252.zip rename to .yarn/cache/@storybook-addon-essentials-npm-7.5.3-73eb43a281-57341a40f9.zip index eabe8084ed..c4620386a7 100644 Binary files a/.yarn/cache/@storybook-addon-essentials-npm-7.2.0-e689506b9c-3fe6fac252.zip and b/.yarn/cache/@storybook-addon-essentials-npm-7.5.3-73eb43a281-57341a40f9.zip differ diff --git a/.yarn/cache/@storybook-addon-highlight-npm-7.2.0-f98566dfbe-3c7af52c87.zip b/.yarn/cache/@storybook-addon-highlight-npm-7.5.3-b5dcb5a983-be468def9a.zip similarity index 51% rename from .yarn/cache/@storybook-addon-highlight-npm-7.2.0-f98566dfbe-3c7af52c87.zip rename to .yarn/cache/@storybook-addon-highlight-npm-7.5.3-b5dcb5a983-be468def9a.zip index f2e12b0d95..22c9c359b0 100644 Binary files a/.yarn/cache/@storybook-addon-highlight-npm-7.2.0-f98566dfbe-3c7af52c87.zip and b/.yarn/cache/@storybook-addon-highlight-npm-7.5.3-b5dcb5a983-be468def9a.zip differ diff --git a/.yarn/cache/@storybook-addon-interactions-npm-7.2.0-74b7b1bd7d-66891245ce.zip b/.yarn/cache/@storybook-addon-interactions-npm-7.5.3-facbb38e88-fec8909767.zip similarity index 96% rename from .yarn/cache/@storybook-addon-interactions-npm-7.2.0-74b7b1bd7d-66891245ce.zip rename to .yarn/cache/@storybook-addon-interactions-npm-7.5.3-facbb38e88-fec8909767.zip index cca1afe529..b688c4878b 100644 Binary files a/.yarn/cache/@storybook-addon-interactions-npm-7.2.0-74b7b1bd7d-66891245ce.zip and b/.yarn/cache/@storybook-addon-interactions-npm-7.5.3-facbb38e88-fec8909767.zip differ diff --git a/.yarn/cache/@storybook-addon-links-npm-7.2.0-0b5fae3657-ec27a9a0ea.zip b/.yarn/cache/@storybook-addon-links-npm-7.5.3-bec669dc6d-cc1f425b85.zip similarity index 83% rename from .yarn/cache/@storybook-addon-links-npm-7.2.0-0b5fae3657-ec27a9a0ea.zip rename to .yarn/cache/@storybook-addon-links-npm-7.5.3-bec669dc6d-cc1f425b85.zip index 322d1a8815..2ead64ea22 100644 Binary files a/.yarn/cache/@storybook-addon-links-npm-7.2.0-0b5fae3657-ec27a9a0ea.zip and b/.yarn/cache/@storybook-addon-links-npm-7.5.3-bec669dc6d-cc1f425b85.zip differ diff --git a/.yarn/cache/@storybook-addon-mdx-gfm-npm-7.2.0-900aaf57f6-1861374d1b.zip b/.yarn/cache/@storybook-addon-mdx-gfm-npm-7.5.3-3d61e8bd7a-6814b9c042.zip similarity index 78% rename from .yarn/cache/@storybook-addon-mdx-gfm-npm-7.2.0-900aaf57f6-1861374d1b.zip rename to .yarn/cache/@storybook-addon-mdx-gfm-npm-7.5.3-3d61e8bd7a-6814b9c042.zip index fbf28d0b05..56864ad704 100644 Binary files a/.yarn/cache/@storybook-addon-mdx-gfm-npm-7.2.0-900aaf57f6-1861374d1b.zip and b/.yarn/cache/@storybook-addon-mdx-gfm-npm-7.5.3-3d61e8bd7a-6814b9c042.zip differ diff --git a/.yarn/cache/@storybook-addon-measure-npm-7.2.0-ec32721fc6-e7efc9b0cd.zip b/.yarn/cache/@storybook-addon-measure-npm-7.5.3-a0465a629b-a0b6cf0a4d.zip similarity index 83% rename from .yarn/cache/@storybook-addon-measure-npm-7.2.0-ec32721fc6-e7efc9b0cd.zip rename to .yarn/cache/@storybook-addon-measure-npm-7.5.3-a0465a629b-a0b6cf0a4d.zip index ecabe23f28..ed97207e10 100644 Binary files a/.yarn/cache/@storybook-addon-measure-npm-7.2.0-ec32721fc6-e7efc9b0cd.zip and b/.yarn/cache/@storybook-addon-measure-npm-7.5.3-a0465a629b-a0b6cf0a4d.zip differ diff --git a/.yarn/cache/@storybook-addon-outline-npm-7.2.0-56b02f15a8-c7af27abc9.zip b/.yarn/cache/@storybook-addon-outline-npm-7.5.3-1997ab169c-07bf04a642.zip similarity index 88% rename from .yarn/cache/@storybook-addon-outline-npm-7.2.0-56b02f15a8-c7af27abc9.zip rename to .yarn/cache/@storybook-addon-outline-npm-7.5.3-1997ab169c-07bf04a642.zip index cd09816363..0f30e91eab 100644 Binary files a/.yarn/cache/@storybook-addon-outline-npm-7.2.0-56b02f15a8-c7af27abc9.zip and b/.yarn/cache/@storybook-addon-outline-npm-7.5.3-1997ab169c-07bf04a642.zip differ diff --git a/.yarn/cache/@storybook-addon-toolbars-npm-7.2.0-936a57aea3-bba2e288f7.zip b/.yarn/cache/@storybook-addon-toolbars-npm-7.5.3-09dda01d80-c61d953a53.zip similarity index 79% rename from .yarn/cache/@storybook-addon-toolbars-npm-7.2.0-936a57aea3-bba2e288f7.zip rename to .yarn/cache/@storybook-addon-toolbars-npm-7.5.3-09dda01d80-c61d953a53.zip index 6fd869ef09..75dde80c01 100644 Binary files a/.yarn/cache/@storybook-addon-toolbars-npm-7.2.0-936a57aea3-bba2e288f7.zip and b/.yarn/cache/@storybook-addon-toolbars-npm-7.5.3-09dda01d80-c61d953a53.zip differ diff --git a/.yarn/cache/@storybook-addon-viewport-npm-7.2.0-a8f837200b-d8d9aec6e6.zip b/.yarn/cache/@storybook-addon-viewport-npm-7.5.3-7f76a863dc-4b324c9edc.zip similarity index 86% rename from .yarn/cache/@storybook-addon-viewport-npm-7.2.0-a8f837200b-d8d9aec6e6.zip rename to .yarn/cache/@storybook-addon-viewport-npm-7.5.3-7f76a863dc-4b324c9edc.zip index b7a8889511..3d2212b7dc 100644 Binary files a/.yarn/cache/@storybook-addon-viewport-npm-7.2.0-a8f837200b-d8d9aec6e6.zip and b/.yarn/cache/@storybook-addon-viewport-npm-7.5.3-7f76a863dc-4b324c9edc.zip differ diff --git a/.yarn/cache/@storybook-addons-npm-7.2.0-321b0d0904-0ea6c3dffb.zip b/.yarn/cache/@storybook-addons-npm-7.5.3-1e623b1dca-8f0ff3cbff.zip similarity index 56% rename from .yarn/cache/@storybook-addons-npm-7.2.0-321b0d0904-0ea6c3dffb.zip rename to .yarn/cache/@storybook-addons-npm-7.5.3-1e623b1dca-8f0ff3cbff.zip index 4a089ae926..af0247e909 100644 Binary files a/.yarn/cache/@storybook-addons-npm-7.2.0-321b0d0904-0ea6c3dffb.zip and b/.yarn/cache/@storybook-addons-npm-7.5.3-1e623b1dca-8f0ff3cbff.zip differ diff --git a/.yarn/cache/@storybook-api-npm-7.2.0-68b5185478-38c6b96299.zip b/.yarn/cache/@storybook-api-npm-7.2.0-68b5185478-38c6b96299.zip deleted file mode 100644 index 183f05bf82..0000000000 Binary files a/.yarn/cache/@storybook-api-npm-7.2.0-68b5185478-38c6b96299.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-api-npm-7.5.3-708ff2c4c7-14c28a8564.zip b/.yarn/cache/@storybook-api-npm-7.5.3-708ff2c4c7-14c28a8564.zip new file mode 100644 index 0000000000..d8cda5b048 Binary files /dev/null and b/.yarn/cache/@storybook-api-npm-7.5.3-708ff2c4c7-14c28a8564.zip differ diff --git a/.yarn/cache/@storybook-blocks-npm-7.2.0-56eb3ac9c9-371cc26f54.zip b/.yarn/cache/@storybook-blocks-npm-7.2.0-56eb3ac9c9-371cc26f54.zip deleted file mode 100644 index 35362d935e..0000000000 Binary files a/.yarn/cache/@storybook-blocks-npm-7.2.0-56eb3ac9c9-371cc26f54.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-blocks-npm-7.5.3-30c3e26bbd-0b7506a529.zip b/.yarn/cache/@storybook-blocks-npm-7.5.3-30c3e26bbd-0b7506a529.zip new file mode 100644 index 0000000000..8758f16552 Binary files /dev/null and b/.yarn/cache/@storybook-blocks-npm-7.5.3-30c3e26bbd-0b7506a529.zip differ diff --git a/.yarn/cache/@storybook-builder-manager-npm-7.2.0-9ae50537b8-80fa828ab9.zip b/.yarn/cache/@storybook-builder-manager-npm-7.2.0-9ae50537b8-80fa828ab9.zip deleted file mode 100644 index 4d3b70d601..0000000000 Binary files a/.yarn/cache/@storybook-builder-manager-npm-7.2.0-9ae50537b8-80fa828ab9.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-builder-manager-npm-7.5.3-1bca594f4b-dab636019e.zip b/.yarn/cache/@storybook-builder-manager-npm-7.5.3-1bca594f4b-dab636019e.zip new file mode 100644 index 0000000000..18fc772ff9 Binary files /dev/null and b/.yarn/cache/@storybook-builder-manager-npm-7.5.3-1bca594f4b-dab636019e.zip differ diff --git a/.yarn/cache/@storybook-builder-vite-npm-7.2.0-dee2cc8d23-baacd75b0c.zip b/.yarn/cache/@storybook-builder-vite-npm-7.2.0-dee2cc8d23-baacd75b0c.zip deleted file mode 100644 index deb88e6c75..0000000000 Binary files a/.yarn/cache/@storybook-builder-vite-npm-7.2.0-dee2cc8d23-baacd75b0c.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-builder-vite-npm-7.5.3-7fa68aa729-5b323bfc89.zip b/.yarn/cache/@storybook-builder-vite-npm-7.5.3-7fa68aa729-5b323bfc89.zip new file mode 100644 index 0000000000..d05c8b3e69 Binary files /dev/null and b/.yarn/cache/@storybook-builder-vite-npm-7.5.3-7fa68aa729-5b323bfc89.zip differ diff --git a/.yarn/cache/@storybook-channels-npm-7.2.0-6f3bc7c42c-2ec3202722.zip b/.yarn/cache/@storybook-channels-npm-7.2.0-6f3bc7c42c-2ec3202722.zip deleted file mode 100644 index a899dd1bba..0000000000 Binary files a/.yarn/cache/@storybook-channels-npm-7.2.0-6f3bc7c42c-2ec3202722.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-cli-npm-7.2.0-8c5a4ca8eb-0364f1ed06.zip b/.yarn/cache/@storybook-cli-npm-7.5.3-d9d410c4e8-1c65a34271.zip similarity index 83% rename from .yarn/cache/@storybook-cli-npm-7.2.0-8c5a4ca8eb-0364f1ed06.zip rename to .yarn/cache/@storybook-cli-npm-7.5.3-d9d410c4e8-1c65a34271.zip index 2bb626b51a..676a5c9e2e 100644 Binary files a/.yarn/cache/@storybook-cli-npm-7.2.0-8c5a4ca8eb-0364f1ed06.zip and b/.yarn/cache/@storybook-cli-npm-7.5.3-d9d410c4e8-1c65a34271.zip differ diff --git a/.yarn/cache/@storybook-client-api-npm-7.2.0-b445236bf4-4e96d44190.zip b/.yarn/cache/@storybook-client-api-npm-7.2.0-b445236bf4-4e96d44190.zip deleted file mode 100644 index 8f2176f140..0000000000 Binary files a/.yarn/cache/@storybook-client-api-npm-7.2.0-b445236bf4-4e96d44190.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-client-api-npm-7.5.3-61f2fd8271-3add5c85b1.zip b/.yarn/cache/@storybook-client-api-npm-7.5.3-61f2fd8271-3add5c85b1.zip new file mode 100644 index 0000000000..15b3969223 Binary files /dev/null and b/.yarn/cache/@storybook-client-api-npm-7.5.3-61f2fd8271-3add5c85b1.zip differ diff --git a/.yarn/cache/@storybook-client-logger-npm-7.2.0-528401d554-8484aac2d4.zip b/.yarn/cache/@storybook-client-logger-npm-7.2.0-528401d554-8484aac2d4.zip deleted file mode 100644 index 1dcb0e4de5..0000000000 Binary files a/.yarn/cache/@storybook-client-logger-npm-7.2.0-528401d554-8484aac2d4.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-codemod-npm-7.2.0-c6583801e7-f1a2ce2f5c.zip b/.yarn/cache/@storybook-codemod-npm-7.5.3-57e0a8ca29-e701293d23.zip similarity index 68% rename from .yarn/cache/@storybook-codemod-npm-7.2.0-c6583801e7-f1a2ce2f5c.zip rename to .yarn/cache/@storybook-codemod-npm-7.5.3-57e0a8ca29-e701293d23.zip index 8a6a53c36f..17537a3fc0 100644 Binary files a/.yarn/cache/@storybook-codemod-npm-7.2.0-c6583801e7-f1a2ce2f5c.zip and b/.yarn/cache/@storybook-codemod-npm-7.5.3-57e0a8ca29-e701293d23.zip differ diff --git a/.yarn/cache/@storybook-components-npm-7.2.0-5e0bb16196-3885975480.zip b/.yarn/cache/@storybook-components-npm-7.5.3-e100fae588-a73dbc33e0.zip similarity index 56% rename from .yarn/cache/@storybook-components-npm-7.2.0-5e0bb16196-3885975480.zip rename to .yarn/cache/@storybook-components-npm-7.5.3-e100fae588-a73dbc33e0.zip index 132565fab6..4b9e68f886 100644 Binary files a/.yarn/cache/@storybook-components-npm-7.2.0-5e0bb16196-3885975480.zip and b/.yarn/cache/@storybook-components-npm-7.5.3-e100fae588-a73dbc33e0.zip differ diff --git a/.yarn/cache/@storybook-core-client-npm-7.2.0-9de79d438d-0984e2a576.zip b/.yarn/cache/@storybook-core-client-npm-7.5.3-03bbd2d434-9533de3f66.zip similarity index 82% rename from .yarn/cache/@storybook-core-client-npm-7.2.0-9de79d438d-0984e2a576.zip rename to .yarn/cache/@storybook-core-client-npm-7.5.3-03bbd2d434-9533de3f66.zip index 0c99de81f8..58a7179887 100644 Binary files a/.yarn/cache/@storybook-core-client-npm-7.2.0-9de79d438d-0984e2a576.zip and b/.yarn/cache/@storybook-core-client-npm-7.5.3-03bbd2d434-9533de3f66.zip differ diff --git a/.yarn/cache/@storybook-core-common-npm-7.2.0-21589a82f1-806b444413.zip b/.yarn/cache/@storybook-core-common-npm-7.2.0-21589a82f1-806b444413.zip deleted file mode 100644 index 13a926b567..0000000000 Binary files a/.yarn/cache/@storybook-core-common-npm-7.2.0-21589a82f1-806b444413.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-core-common-npm-7.5.3-017b14e33d-152816728c.zip b/.yarn/cache/@storybook-core-common-npm-7.5.3-017b14e33d-152816728c.zip new file mode 100644 index 0000000000..e4db712984 Binary files /dev/null and b/.yarn/cache/@storybook-core-common-npm-7.5.3-017b14e33d-152816728c.zip differ diff --git a/.yarn/cache/@storybook-core-events-npm-7.2.0-fbefb7ce68-a88cc65115.zip b/.yarn/cache/@storybook-core-events-npm-7.2.0-fbefb7ce68-a88cc65115.zip deleted file mode 100644 index 78cbdfbfb1..0000000000 Binary files a/.yarn/cache/@storybook-core-events-npm-7.2.0-fbefb7ce68-a88cc65115.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-core-server-npm-7.2.0-4aea186790-489d00d836.zip b/.yarn/cache/@storybook-core-server-npm-7.2.0-4aea186790-489d00d836.zip deleted file mode 100644 index 3870b22ba7..0000000000 Binary files a/.yarn/cache/@storybook-core-server-npm-7.2.0-4aea186790-489d00d836.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-core-server-npm-7.5.3-fb6a4f7bf0-8d5da88223.zip b/.yarn/cache/@storybook-core-server-npm-7.5.3-fb6a4f7bf0-8d5da88223.zip new file mode 100644 index 0000000000..4a583d423a Binary files /dev/null and b/.yarn/cache/@storybook-core-server-npm-7.5.3-fb6a4f7bf0-8d5da88223.zip differ diff --git a/.yarn/cache/@storybook-csf-plugin-npm-7.2.0-d96cc401fa-0dc4d2b80c.zip b/.yarn/cache/@storybook-csf-plugin-npm-7.5.3-80c717f1fd-3252d8834e.zip similarity index 51% rename from .yarn/cache/@storybook-csf-plugin-npm-7.2.0-d96cc401fa-0dc4d2b80c.zip rename to .yarn/cache/@storybook-csf-plugin-npm-7.5.3-80c717f1fd-3252d8834e.zip index 0b1ad00cc1..f57737bd18 100644 Binary files a/.yarn/cache/@storybook-csf-plugin-npm-7.2.0-d96cc401fa-0dc4d2b80c.zip and b/.yarn/cache/@storybook-csf-plugin-npm-7.5.3-80c717f1fd-3252d8834e.zip differ diff --git a/.yarn/cache/@storybook-csf-tools-npm-7.2.0-a50e8074c5-26b55e16c2.zip b/.yarn/cache/@storybook-csf-tools-npm-7.2.0-a50e8074c5-26b55e16c2.zip deleted file mode 100644 index 7ed9c78a5d..0000000000 Binary files a/.yarn/cache/@storybook-csf-tools-npm-7.2.0-a50e8074c5-26b55e16c2.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-docs-tools-npm-7.2.0-b272c4a0e4-0da7425dee.zip b/.yarn/cache/@storybook-docs-tools-npm-7.2.0-b272c4a0e4-0da7425dee.zip deleted file mode 100644 index 589e525273..0000000000 Binary files a/.yarn/cache/@storybook-docs-tools-npm-7.2.0-b272c4a0e4-0da7425dee.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-docs-tools-npm-7.5.3-78b9dff9b4-27d8e55927.zip b/.yarn/cache/@storybook-docs-tools-npm-7.5.3-78b9dff9b4-27d8e55927.zip new file mode 100644 index 0000000000..550de65d62 Binary files /dev/null and b/.yarn/cache/@storybook-docs-tools-npm-7.5.3-78b9dff9b4-27d8e55927.zip differ diff --git a/.yarn/cache/@storybook-instrumenter-npm-7.2.0-5868a07280-2967478b6e.zip b/.yarn/cache/@storybook-instrumenter-npm-7.5.3-4b7d2774f2-32a63211ba.zip similarity index 88% rename from .yarn/cache/@storybook-instrumenter-npm-7.2.0-5868a07280-2967478b6e.zip rename to .yarn/cache/@storybook-instrumenter-npm-7.5.3-4b7d2774f2-32a63211ba.zip index 34654837fe..8ee14d5eb1 100644 Binary files a/.yarn/cache/@storybook-instrumenter-npm-7.2.0-5868a07280-2967478b6e.zip and b/.yarn/cache/@storybook-instrumenter-npm-7.5.3-4b7d2774f2-32a63211ba.zip differ diff --git a/.yarn/cache/@storybook-manager-api-npm-7.2.0-2392033d3f-54e99fa6db.zip b/.yarn/cache/@storybook-manager-api-npm-7.2.0-2392033d3f-54e99fa6db.zip deleted file mode 100644 index 5a53b16dee..0000000000 Binary files a/.yarn/cache/@storybook-manager-api-npm-7.2.0-2392033d3f-54e99fa6db.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-manager-api-npm-7.5.3-068a46f956-82bb352a4e.zip b/.yarn/cache/@storybook-manager-api-npm-7.5.3-068a46f956-82bb352a4e.zip new file mode 100644 index 0000000000..142d69a863 Binary files /dev/null and b/.yarn/cache/@storybook-manager-api-npm-7.5.3-068a46f956-82bb352a4e.zip differ diff --git a/.yarn/cache/@storybook-manager-npm-7.2.0-3120e54368-1cbb47c3af.zip b/.yarn/cache/@storybook-manager-npm-7.2.0-3120e54368-1cbb47c3af.zip deleted file mode 100644 index e6b32bdffc..0000000000 Binary files a/.yarn/cache/@storybook-manager-npm-7.2.0-3120e54368-1cbb47c3af.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-manager-npm-7.5.3-41c6b0d1e9-8f508f09a8.zip b/.yarn/cache/@storybook-manager-npm-7.5.3-41c6b0d1e9-8f508f09a8.zip new file mode 100644 index 0000000000..596bdca4e9 Binary files /dev/null and b/.yarn/cache/@storybook-manager-npm-7.5.3-41c6b0d1e9-8f508f09a8.zip differ diff --git a/.yarn/cache/@storybook-node-logger-npm-7.2.0-f6226ab45b-a8a2a110da.zip b/.yarn/cache/@storybook-node-logger-npm-7.5.3-44fd33314c-9dec669a9a.zip similarity index 90% rename from .yarn/cache/@storybook-node-logger-npm-7.2.0-f6226ab45b-a8a2a110da.zip rename to .yarn/cache/@storybook-node-logger-npm-7.5.3-44fd33314c-9dec669a9a.zip index 307a4f2f7d..6892cac985 100644 Binary files a/.yarn/cache/@storybook-node-logger-npm-7.2.0-f6226ab45b-a8a2a110da.zip and b/.yarn/cache/@storybook-node-logger-npm-7.5.3-44fd33314c-9dec669a9a.zip differ diff --git a/.yarn/cache/@storybook-postinstall-npm-7.2.0-0bc4cb9a99-26c2f6c335.zip b/.yarn/cache/@storybook-postinstall-npm-7.2.0-0bc4cb9a99-26c2f6c335.zip deleted file mode 100644 index 01d6548e1f..0000000000 Binary files a/.yarn/cache/@storybook-postinstall-npm-7.2.0-0bc4cb9a99-26c2f6c335.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-postinstall-npm-7.5.3-1f9822546e-66e54ca864.zip b/.yarn/cache/@storybook-postinstall-npm-7.5.3-1f9822546e-66e54ca864.zip new file mode 100644 index 0000000000..d4e664174c Binary files /dev/null and b/.yarn/cache/@storybook-postinstall-npm-7.5.3-1f9822546e-66e54ca864.zip differ diff --git a/.yarn/cache/@storybook-preview-api-npm-7.2.0-cf1ab6be88-6e57e6ab43.zip b/.yarn/cache/@storybook-preview-api-npm-7.2.0-cf1ab6be88-6e57e6ab43.zip deleted file mode 100644 index 948cac45aa..0000000000 Binary files a/.yarn/cache/@storybook-preview-api-npm-7.2.0-cf1ab6be88-6e57e6ab43.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-preview-api-npm-7.5.3-24f57cbbe7-9e75ad27a0.zip b/.yarn/cache/@storybook-preview-api-npm-7.5.3-24f57cbbe7-9e75ad27a0.zip new file mode 100644 index 0000000000..21dcbcf066 Binary files /dev/null and b/.yarn/cache/@storybook-preview-api-npm-7.5.3-24f57cbbe7-9e75ad27a0.zip differ diff --git a/.yarn/cache/@storybook-preview-npm-7.2.0-a5873f2cb0-bb70028a24.zip b/.yarn/cache/@storybook-preview-npm-7.2.0-a5873f2cb0-bb70028a24.zip deleted file mode 100644 index 348c9d8d03..0000000000 Binary files a/.yarn/cache/@storybook-preview-npm-7.2.0-a5873f2cb0-bb70028a24.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-preview-npm-7.5.3-0a63d7d3e9-4eac804aff.zip b/.yarn/cache/@storybook-preview-npm-7.5.3-0a63d7d3e9-4eac804aff.zip new file mode 100644 index 0000000000..54803175e2 Binary files /dev/null and b/.yarn/cache/@storybook-preview-npm-7.5.3-0a63d7d3e9-4eac804aff.zip differ diff --git a/.yarn/cache/@storybook-react-dom-shim-npm-7.2.0-a2bb1d7ee1-577469305f.zip b/.yarn/cache/@storybook-react-dom-shim-npm-7.2.0-a2bb1d7ee1-577469305f.zip deleted file mode 100644 index 90ba2d6728..0000000000 Binary files a/.yarn/cache/@storybook-react-dom-shim-npm-7.2.0-a2bb1d7ee1-577469305f.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-react-dom-shim-npm-7.5.3-37f853b59c-41071d4102.zip b/.yarn/cache/@storybook-react-dom-shim-npm-7.5.3-37f853b59c-41071d4102.zip new file mode 100644 index 0000000000..2b5df2bb36 Binary files /dev/null and b/.yarn/cache/@storybook-react-dom-shim-npm-7.5.3-37f853b59c-41071d4102.zip differ diff --git a/.yarn/cache/@storybook-react-npm-7.2.0-0ae2f0b6c0-61267be8ca.zip b/.yarn/cache/@storybook-react-npm-7.2.0-0ae2f0b6c0-61267be8ca.zip deleted file mode 100644 index db6f0d0420..0000000000 Binary files a/.yarn/cache/@storybook-react-npm-7.2.0-0ae2f0b6c0-61267be8ca.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-react-npm-7.5.3-f062764ec5-0b931d4feb.zip b/.yarn/cache/@storybook-react-npm-7.5.3-f062764ec5-0b931d4feb.zip new file mode 100644 index 0000000000..aa260b35ba Binary files /dev/null and b/.yarn/cache/@storybook-react-npm-7.5.3-f062764ec5-0b931d4feb.zip differ diff --git a/.yarn/cache/@storybook-react-vite-npm-7.2.0-efd64073c5-f43fb8c81c.zip b/.yarn/cache/@storybook-react-vite-npm-7.2.0-efd64073c5-f43fb8c81c.zip deleted file mode 100644 index e56280ed01..0000000000 Binary files a/.yarn/cache/@storybook-react-vite-npm-7.2.0-efd64073c5-f43fb8c81c.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-react-vite-npm-7.5.3-731ba29685-701ae04b08.zip b/.yarn/cache/@storybook-react-vite-npm-7.5.3-731ba29685-701ae04b08.zip new file mode 100644 index 0000000000..595751fc09 Binary files /dev/null and b/.yarn/cache/@storybook-react-vite-npm-7.5.3-731ba29685-701ae04b08.zip differ diff --git a/.yarn/cache/@storybook-router-npm-7.2.0-5e5b95cfa1-2f879c399b.zip b/.yarn/cache/@storybook-router-npm-7.5.3-6ada0b847e-7c7c9a6f6e.zip similarity index 96% rename from .yarn/cache/@storybook-router-npm-7.2.0-5e5b95cfa1-2f879c399b.zip rename to .yarn/cache/@storybook-router-npm-7.5.3-6ada0b847e-7c7c9a6f6e.zip index 054643479a..3dba0a9540 100644 Binary files a/.yarn/cache/@storybook-router-npm-7.2.0-5e5b95cfa1-2f879c399b.zip and b/.yarn/cache/@storybook-router-npm-7.5.3-6ada0b847e-7c7c9a6f6e.zip differ diff --git a/.yarn/cache/@storybook-telemetry-npm-7.2.0-a46e0f88ef-4e9eba1f0c.zip b/.yarn/cache/@storybook-telemetry-npm-7.2.0-a46e0f88ef-4e9eba1f0c.zip deleted file mode 100644 index 04fb582d77..0000000000 Binary files a/.yarn/cache/@storybook-telemetry-npm-7.2.0-a46e0f88ef-4e9eba1f0c.zip and /dev/null differ diff --git a/.yarn/cache/@storybook-telemetry-npm-7.5.3-e316a3ef1f-b031ace4e1.zip b/.yarn/cache/@storybook-telemetry-npm-7.5.3-e316a3ef1f-b031ace4e1.zip new file mode 100644 index 0000000000..0a2ad47f74 Binary files /dev/null and b/.yarn/cache/@storybook-telemetry-npm-7.5.3-e316a3ef1f-b031ace4e1.zip differ diff --git a/.yarn/cache/@storybook-theming-npm-7.2.0-eeba03afdf-c1ce1e4875.zip b/.yarn/cache/@storybook-theming-npm-7.5.3-a6fe77f29c-e9769d0ad9.zip similarity index 67% rename from .yarn/cache/@storybook-theming-npm-7.2.0-eeba03afdf-c1ce1e4875.zip rename to .yarn/cache/@storybook-theming-npm-7.5.3-a6fe77f29c-e9769d0ad9.zip index a78eba5a20..eb9bcde435 100644 Binary files a/.yarn/cache/@storybook-theming-npm-7.2.0-eeba03afdf-c1ce1e4875.zip and b/.yarn/cache/@storybook-theming-npm-7.5.3-a6fe77f29c-e9769d0ad9.zip differ diff --git a/.yarn/cache/@storybook-types-npm-7.2.0-85e097da95-af845fc2cc.zip b/.yarn/cache/@storybook-types-npm-7.2.0-85e097da95-af845fc2cc.zip deleted file mode 100644 index 4381d49ce7..0000000000 Binary files a/.yarn/cache/@storybook-types-npm-7.2.0-85e097da95-af845fc2cc.zip and /dev/null differ diff --git a/.yarn/cache/@types-babel__core-npm-7.20.5-4d95f75eab-a3226f7930.zip b/.yarn/cache/@types-babel__core-npm-7.20.5-4d95f75eab-a3226f7930.zip new file mode 100644 index 0000000000..89f59ad602 Binary files /dev/null and b/.yarn/cache/@types-babel__core-npm-7.20.5-4d95f75eab-a3226f7930.zip differ diff --git a/.yarn/cache/@types-babel__traverse-npm-7.20.4-49941d89c4-f044ba80e0.zip b/.yarn/cache/@types-babel__traverse-npm-7.20.4-49941d89c4-f044ba80e0.zip new file mode 100644 index 0000000000..25a4d7f8bf Binary files /dev/null and b/.yarn/cache/@types-babel__traverse-npm-7.20.4-49941d89c4-f044ba80e0.zip differ diff --git a/.yarn/cache/@types-doctrine-npm-0.0.6-51078a5eaa-6b042161d5.zip b/.yarn/cache/@types-doctrine-npm-0.0.6-51078a5eaa-6b042161d5.zip new file mode 100644 index 0000000000..434643b3d8 Binary files /dev/null and b/.yarn/cache/@types-doctrine-npm-0.0.6-51078a5eaa-6b042161d5.zip differ diff --git a/.yarn/cache/@types-resolve-npm-1.20.6-6ab126a04b-dc35f55176.zip b/.yarn/cache/@types-resolve-npm-1.20.6-6ab126a04b-dc35f55176.zip new file mode 100644 index 0000000000..81e1dac2fa Binary files /dev/null and b/.yarn/cache/@types-resolve-npm-1.20.6-6ab126a04b-dc35f55176.zip differ diff --git a/.yarn/cache/ast-types-npm-0.14.2-43c4ac4b0d-8674a77307.zip b/.yarn/cache/ast-types-npm-0.14.2-43c4ac4b0d-8674a77307.zip deleted file mode 100644 index 55180aaf37..0000000000 Binary files a/.yarn/cache/ast-types-npm-0.14.2-43c4ac4b0d-8674a77307.zip and /dev/null differ diff --git a/.yarn/cache/c8-npm-7.13.0-9ac8f17e2c-491abf4cf3.zip b/.yarn/cache/c8-npm-7.13.0-9ac8f17e2c-491abf4cf3.zip deleted file mode 100644 index a457d8fb70..0000000000 Binary files a/.yarn/cache/c8-npm-7.13.0-9ac8f17e2c-491abf4cf3.zip and /dev/null differ diff --git a/.yarn/cache/esbuild-register-npm-3.5.0-d823f64ce0-f4307753c9.zip b/.yarn/cache/esbuild-register-npm-3.5.0-d823f64ce0-f4307753c9.zip new file mode 100644 index 0000000000..dae5978d5c Binary files /dev/null and b/.yarn/cache/esbuild-register-npm-3.5.0-d823f64ce0-f4307753c9.zip differ diff --git a/.yarn/cache/escodegen-npm-2.1.0-e0bf940745-096696407e.zip b/.yarn/cache/escodegen-npm-2.1.0-e0bf940745-096696407e.zip new file mode 100644 index 0000000000..d28acf846b Binary files /dev/null and b/.yarn/cache/escodegen-npm-2.1.0-e0bf940745-096696407e.zip differ diff --git a/.yarn/cache/estree-to-babel-npm-3.2.1-1f7b35cad6-a4584d0c60.zip b/.yarn/cache/estree-to-babel-npm-3.2.1-1f7b35cad6-a4584d0c60.zip deleted file mode 100644 index 0a6094f0d0..0000000000 Binary files a/.yarn/cache/estree-to-babel-npm-3.2.1-1f7b35cad6-a4584d0c60.zip and /dev/null differ diff --git a/.yarn/cache/ms-npm-2.1.1-5b4fd72c86-0078a23cd9.zip b/.yarn/cache/ms-npm-2.1.1-5b4fd72c86-0078a23cd9.zip deleted file mode 100644 index 32b935a33c..0000000000 Binary files a/.yarn/cache/ms-npm-2.1.1-5b4fd72c86-0078a23cd9.zip and /dev/null differ diff --git a/.yarn/cache/react-docgen-npm-6.0.0-alpha.3-a0cd4811b0-db4c300910.zip b/.yarn/cache/react-docgen-npm-6.0.0-alpha.3-a0cd4811b0-db4c300910.zip deleted file mode 100644 index 9cb2cfc2fe..0000000000 Binary files a/.yarn/cache/react-docgen-npm-6.0.0-alpha.3-a0cd4811b0-db4c300910.zip and /dev/null differ diff --git a/.yarn/cache/react-docgen-npm-6.0.4-455e82197a-2cb3de8ff4.zip b/.yarn/cache/react-docgen-npm-6.0.4-455e82197a-2cb3de8ff4.zip new file mode 100644 index 0000000000..976267eb1a Binary files /dev/null and b/.yarn/cache/react-docgen-npm-6.0.4-455e82197a-2cb3de8ff4.zip differ diff --git a/.yarn/cache/safe-buffer-npm-5.1.1-cdaab52fc6-7f117b6045.zip b/.yarn/cache/safe-buffer-npm-5.1.1-cdaab52fc6-7f117b6045.zip deleted file mode 100644 index 1eba9b405d..0000000000 Binary files a/.yarn/cache/safe-buffer-npm-5.1.1-cdaab52fc6-7f117b6045.zip and /dev/null differ diff --git a/.yarn/cache/serve-favicon-npm-2.5.0-c5088a9dbc-f4dd0fbee3.zip b/.yarn/cache/serve-favicon-npm-2.5.0-c5088a9dbc-f4dd0fbee3.zip deleted file mode 100644 index 25424284af..0000000000 Binary files a/.yarn/cache/serve-favicon-npm-2.5.0-c5088a9dbc-f4dd0fbee3.zip and /dev/null differ diff --git a/.yarn/cache/storybook-npm-7.2.0-9ae0d819bb-4c0b84edec.zip b/.yarn/cache/storybook-npm-7.5.3-84a2852c39-d5263aa78f.zip similarity index 68% rename from .yarn/cache/storybook-npm-7.2.0-9ae0d819bb-4c0b84edec.zip rename to .yarn/cache/storybook-npm-7.5.3-84a2852c39-d5263aa78f.zip index 8cd03a6a74..2c0d1c9374 100644 Binary files a/.yarn/cache/storybook-npm-7.2.0-9ae0d819bb-4c0b84edec.zip and b/.yarn/cache/storybook-npm-7.5.3-84a2852c39-d5263aa78f.zip differ diff --git a/packages/odyssey-react-mui/src/@types/react-augment.d.ts b/packages/odyssey-react-mui/src/@types/react-augment.d.ts new file mode 100644 index 0000000000..e6d1d7dd34 --- /dev/null +++ b/packages/odyssey-react-mui/src/@types/react-augment.d.ts @@ -0,0 +1,19 @@ +/*! + * Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +import { FC } from "react"; + +export interface ForwardRefWithType extends FC> { + (props: WithForwardRefProps): ReturnType< + FC> + >; +} diff --git a/packages/odyssey-react-mui/src/Autocomplete.tsx b/packages/odyssey-react-mui/src/Autocomplete.tsx index de61217bd8..b1a1d987d9 100644 --- a/packages/odyssey-react-mui/src/Autocomplete.tsx +++ b/packages/odyssey-react-mui/src/Autocomplete.tsx @@ -17,12 +17,16 @@ import { UseAutocompleteProps, AutocompleteValue, } from "@mui/material"; -import { memo, useCallback, useMemo } from "react"; +import { memo, useCallback, useMemo, useRef } from "react"; import { Field } from "./Field"; import { FieldComponentProps } from "./FieldComponentProps"; import type { SeleniumProps } from "./SeleniumProps"; -import { useControlledState } from "./useControlledState"; +import { + ComponentControlledState, + useInputValues, + getControlState, +} from "./inputUtils"; export type AutocompleteProps< OptionType, @@ -31,7 +35,6 @@ export type AutocompleteProps< > = { /** * The default value. Use when the component is not controlled. - * @default props.multiple ? [] : null */ defaultValue?: UseAutocompleteProps< OptionType, @@ -189,6 +192,45 @@ const Autocomplete = < getIsOptionEqualToValue, testId, }: AutocompleteProps) => { + const controlledStateRef = useRef( + getControlState({ controlledValue: value, uncontrolledValue: defaultValue }) + ); + const defaultValueProp = useMemo< + | AutocompleteValue< + OptionType, + HasMultipleChoices, + undefined, + IsCustomValueAllowed + > + | undefined + >(() => { + if (hasMultipleChoices) { + if (value === undefined) { + return defaultValue; + } + return [] as AutocompleteValue< + OptionType, + HasMultipleChoices, + undefined, + IsCustomValueAllowed + >; + } + return value === undefined ? defaultValue : undefined; + }, [defaultValue, hasMultipleChoices, value]); + + const valueProps = useInputValues({ + defaultValue: defaultValueProp, + value: value, + controlState: controlledStateRef.current, + }); + + const inputValueProp = useMemo(() => { + if (controlledStateRef.current === ComponentControlledState.CONTROLLED) { + return { inputValue }; + } + return undefined; + }, [inputValue]); + const renderInput = useCallback( ({ InputLabelProps, InputProps, ...params }) => ( - | undefined - >(() => { - if (hasMultipleChoices) { - return defaultValue === undefined - ? ([] as AutocompleteValue< - OptionType, - HasMultipleChoices, - undefined, - IsCustomValueAllowed - >) - : defaultValue; - } - return defaultValue ?? undefined; - }, [defaultValue, hasMultipleChoices]); - - const [localValue, setLocalValue] = useControlledState({ - controlledValue: value, - uncontrolledValue: defaultValuesProp, - }); - - const [localInputValue, setLocalInputValue] = useControlledState({ - controlledValue: inputValue, - uncontrolledValue: undefined, - }); - const onChange = useCallback< NonNullable< UseAutocompleteProps< @@ -267,10 +276,9 @@ const Autocomplete = < > >( (event, value, reason, details) => { - setLocalValue(value); onChangeProp?.(event, value, reason, details); }, - [onChangeProp, setLocalValue] + [onChangeProp] ); const onInputChange = useCallback< @@ -284,18 +292,18 @@ const Autocomplete = < > >( (event, value, reason) => { - setLocalInputValue(value); onInputChangeProp?.(event, value, reason); }, - [onInputChangeProp, setLocalInputValue] + [onInputChangeProp] ); return ( ); diff --git a/packages/odyssey-react-mui/src/Checkbox.tsx b/packages/odyssey-react-mui/src/Checkbox.tsx index b7e31db70f..6585d72b18 100644 --- a/packages/odyssey-react-mui/src/Checkbox.tsx +++ b/packages/odyssey-react-mui/src/Checkbox.tsx @@ -11,7 +11,7 @@ */ import { useTranslation } from "react-i18next"; -import { memo, useCallback, useMemo } from "react"; +import { memo, useCallback, useMemo, useRef } from "react"; import { Checkbox as MuiCheckbox, CheckboxProps as MuiCheckboxProps, @@ -22,7 +22,7 @@ import { import { FieldComponentProps } from "./FieldComponentProps"; import { Typography } from "./Typography"; import type { SeleniumProps } from "./SeleniumProps"; -import { useControlledState } from "./useControlledState"; +import { ComponentControlledState, getControlState } from "./inputUtils"; import { CheckedFieldProps } from "./FormCheckedProps"; export const checkboxValidityValues = ["valid", "invalid", "inherit"] as const; @@ -90,10 +90,18 @@ const Checkbox = ({ value, }: CheckboxProps) => { const { t } = useTranslation(); - const [isLocalChecked, setIsLocalChecked] = useControlledState({ - controlledValue: isChecked, - uncontrolledValue: isDefaultChecked, - }); + const controlledStateRef = useRef( + getControlState({ + controlledValue: isChecked, + uncontrolledValue: isDefaultChecked, + }) + ); + const inputValues = useMemo(() => { + if (controlledStateRef.current === ComponentControlledState.CONTROLLED) { + return { checked: isChecked }; + } + return { defaultChecked: isDefaultChecked }; + }, [isDefaultChecked, isChecked]); const label = useMemo(() => { return ( @@ -114,10 +122,9 @@ const Checkbox = ({ const onChange = useCallback>( (event, checked) => { - setIsLocalChecked(checked); onChangeProp?.(event, checked); }, - [onChangeProp, setIsLocalChecked] + [onChangeProp] ); return ( @@ -134,7 +141,7 @@ const Checkbox = ({ } control={ = + HasMultipleChoices extends true ? string[] : string; + +export type NativeSelectProps< + Value extends NativeSelectValueType, + HasMultipleChoices extends boolean +> = { /** * The options or optgroup elements within the NativeSelect */ children?: ReactElement<"option"> | ReactElement<"optgroup">; /** - * The default value of the NativeSelect. Only applicable if `value` is not provided + * The default value of the NativeSelect. Use when component is uncontrolled + */ + defaultValue?: Value; + /** + * If `true`, the Select allows multiple selections */ - defaultValue?: string; + hasMultipleChoices?: HasMultipleChoices; /** - * If `true`, the NativeSelect allows multiple selections + * @deprecated Use `hasMultipleChoices` instead */ - isMultiSelect?: boolean; + /** **Deprecated:** use `hasMultipleChoices` */ + isMultiSelect?: HasMultipleChoices; /** * The label text for the NativeSelect */ @@ -43,78 +65,109 @@ export type NativeSelectProps = { /** * Callback fired when the NativeSelect loses focus */ - onBlur?: MuiSelectProps["onBlur"]; + onBlur?: MuiSelectProps["onBlur"]; /** * Callback fired when the value of the NativeSelect changes */ - onChange?: MuiSelectProps["onChange"]; + onChange?: MuiSelectProps["onChange"]; /** * Callback fired when the NativeSelect gains focus */ - onFocus?: MuiSelectProps["onFocus"]; + onFocus?: MuiSelectProps["onFocus"]; + options: Value; /** - * The value or values selected in the NativeSelect + * The value or values selected in the NativeSelect. Use when component is controlled */ - value?: string | string[]; + value?: Value; } & Pick< FieldComponentProps, "errorMessage" | "hint" | "id" | "isDisabled" | "isOptional" > & SeleniumProps; -const NativeSelect = forwardRef( - ( +const NativeSelect: ForwardRefWithType = forwardRef( + < + Value extends NativeSelectValueType, + HasMultipleChoices extends boolean + >( { defaultValue, errorMessage, + hasMultipleChoices: hasMultipleChoicesProp, hint, id: idOverride, isDisabled = false, - isMultiSelect = false, + isMultiSelect, isOptional = false, label, onBlur, - onChange, + onChange: onChangeProp, onFocus, testId, value, children, - }, - ref + }: NativeSelectProps, + ref?: React.Ref ) => { + const controlledStateRef = useRef( + getControlState({ + controlledValue: value, + uncontrolledValue: defaultValue, + }) + ); + const inputValues = useInputValues({ + defaultValue, + value, + controlState: controlledStateRef.current, + }); + + const onChange = useCallback< + NonNullable["onChange"]> + >( + (event, child) => { + onChangeProp?.(event, child); + }, + [onChangeProp] + ); + + const hasMultipleChoices = useMemo( + () => + hasMultipleChoicesProp === undefined + ? isMultiSelect + : hasMultipleChoicesProp, + [hasMultipleChoicesProp, isMultiSelect] + ); const renderFieldComponent = useCallback( ({ ariaDescribedBy, errorMessageElementId, labelElementId }) => ( ), [ children, - defaultValue, idOverride, - isMultiSelect, + inputValues, + hasMultipleChoices, onBlur, onChange, onFocus, ref, testId, - value, ] ); diff --git a/packages/odyssey-react-mui/src/PasswordField.tsx b/packages/odyssey-react-mui/src/PasswordField.tsx index 2347938d28..4ccc491d2f 100644 --- a/packages/odyssey-react-mui/src/PasswordField.tsx +++ b/packages/odyssey-react-mui/src/PasswordField.tsx @@ -17,6 +17,7 @@ import { forwardRef, memo, useCallback, + useRef, useState, } from "react"; @@ -25,6 +26,7 @@ import { Field } from "./Field"; import { FieldComponentProps } from "./FieldComponentProps"; import type { SeleniumProps } from "./SeleniumProps"; import { useTranslation } from "react-i18next"; +import { getControlState, useInputValues } from "./inputUtils"; export type PasswordFieldProps = { /** @@ -33,6 +35,10 @@ export type PasswordFieldProps = { * You can learn more about it [following the specification](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill). */ autoCompleteType?: "current-password" | "new-password"; + /** + * initial value for input. Use when component in uncontrolled. + */ + defaultValue?: string; /** * If `true`, the component will receive focus automatically. */ @@ -62,7 +68,7 @@ export type PasswordFieldProps = { */ placeholder?: string; /** - * The value of the `input` element, required for a controlled component. + * The value of the `input` element. Use when component is controlled. */ value?: string; } & FieldComponentProps & @@ -72,6 +78,7 @@ const PasswordField = forwardRef( ( { autoCompleteType, + defaultValue, errorMessage, hasInitialFocus, hint, @@ -82,7 +89,7 @@ const PasswordField = forwardRef( isReadOnly, label, name: nameOverride, - onChange, + onChange: onChangeProp, onFocus, onBlur, placeholder, @@ -100,9 +107,31 @@ const PasswordField = forwardRef( ); }, []); + const controlledStateRef = useRef( + getControlState({ + controlledValue: value, + uncontrolledValue: defaultValue, + }) + ); + const inputValues = useInputValues({ + defaultValue, + value, + controlState: controlledStateRef.current, + }); + + const onChange = useCallback< + ChangeEventHandler + >( + (event) => { + onChangeProp?.(event); + }, + [onChangeProp] + ); + const renderFieldComponent = useCallback( ({ ariaDescribedBy, errorMessageElementId, id, labelElementId }) => ( ( ref={ref} required={!isOptional} type={inputType} - value={value} /> ), [ autoCompleteType, hasInitialFocus, + inputValues, t, togglePasswordVisibility, inputType, @@ -159,7 +188,6 @@ const PasswordField = forwardRef( hasShowPassword, ref, testId, - value, ] ); diff --git a/packages/odyssey-react-mui/src/RadioGroup.tsx b/packages/odyssey-react-mui/src/RadioGroup.tsx index 5274c1f232..d3d24c28d1 100644 --- a/packages/odyssey-react-mui/src/RadioGroup.tsx +++ b/packages/odyssey-react-mui/src/RadioGroup.tsx @@ -14,13 +14,13 @@ import { RadioGroup as MuiRadioGroup, type RadioGroupProps as MuiRadioGroupProps, } from "@mui/material"; -import { memo, ReactElement, useCallback } from "react"; +import { memo, ReactElement, useCallback, useRef } from "react"; import { Radio, RadioProps } from "./Radio"; import { Field } from "./Field"; import { FieldComponentProps } from "./FieldComponentProps"; import type { SeleniumProps } from "./SeleniumProps"; -import { useControlledState } from "./useControlledState"; +import { getControlState, useInputValues } from "./inputUtils"; export type RadioGroupProps = { /** @@ -62,35 +62,37 @@ const RadioGroup = ({ testId, value, }: RadioGroupProps) => { - const [localValue, setLocalValue] = useControlledState({ - controlledValue: value, - uncontrolledValue: defaultValue, + const controlledStateRef = useRef( + getControlState({ controlledValue: value, uncontrolledValue: defaultValue }) + ); + const inputValues = useInputValues({ + defaultValue, + value, + controlState: controlledStateRef.current, }); const onChange = useCallback>( (event, value) => { - setLocalValue(value); onChangeProp?.(event, value); }, - [onChangeProp, setLocalValue] + [onChangeProp] ); const renderFieldComponent = useCallback( ({ ariaDescribedBy, errorMessageElementId, id, labelElementId }) => ( {children} ), - [children, defaultValue, nameOverride, onChange, testId, localValue] + [children, inputValues, nameOverride, onChange, testId] ); return ( diff --git a/packages/odyssey-react-mui/src/SearchField.tsx b/packages/odyssey-react-mui/src/SearchField.tsx index d6122823f4..7290ca77d9 100644 --- a/packages/odyssey-react-mui/src/SearchField.tsx +++ b/packages/odyssey-react-mui/src/SearchField.tsx @@ -10,7 +10,6 @@ * See the License for the specific language governing permissions and limitations under the License. */ -import { useState, useEffect } from "react"; import { InputAdornment, InputBase, IconButton } from "@mui/material"; import { ChangeEventHandler, @@ -19,12 +18,14 @@ import { InputHTMLAttributes, memo, useCallback, + useRef, } from "react"; import { CloseCircleFilledIcon, SearchIcon } from "./icons.generated"; import { Field } from "./Field"; import { FieldComponentProps } from "./FieldComponentProps"; import type { SeleniumProps } from "./SeleniumProps"; +import { getControlState, useInputValues } from "./inputUtils"; export type SearchFieldProps = { /** @@ -33,6 +34,10 @@ export type SearchFieldProps = { * You can learn more about it [following the specification](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill). */ autoCompleteType?: InputHTMLAttributes["autoComplete"]; + /** + * The value of the `input` element to use when uncontrolled. + */ + defaultValue?: string; /** * If `true`, the component will receive focus automatically. */ @@ -70,7 +75,7 @@ export type SearchFieldProps = { */ placeholder?: string; /** - * The value of the `input` element, required for a controlled component. + * The value of the `input` element, to use when controlled. */ value?: string; } & Pick & @@ -80,6 +85,7 @@ const SearchField = forwardRef( ( { autoCompleteType, + defaultValue, hasInitialFocus, id: idOverride, isDisabled = false, @@ -91,42 +97,45 @@ const SearchField = forwardRef( onClear: onClearProp, placeholder, testId, - value: controlledValue, + value, }, ref ) => { - const [uncontrolledValue, setUncontrolledValue] = useState(""); - const onChange: ChangeEventHandler = useCallback( (event) => { - setUncontrolledValue(event.currentTarget.value); onChangeProp?.(event); }, [onChangeProp] ); const onClear = useCallback(() => { - setUncontrolledValue(""); onClearProp?.(); }, [onClearProp]); - useEffect(() => { - if (controlledValue !== undefined) { - setUncontrolledValue(controlledValue); - } - }, [controlledValue]); + const controlledStateRef = useRef( + getControlState({ + controlledValue: value, + uncontrolledValue: defaultValue, + }) + ); + const inputValues = useInputValues({ + defaultValue, + value, + controlState: controlledStateRef.current, + }); const renderFieldComponent = useCallback( ({ ariaDescribedBy, id }) => ( ( } type="search" - value={ - controlledValue === undefined ? uncontrolledValue : controlledValue - } /> ), [ autoCompleteType, - controlledValue, + defaultValue, hasInitialFocus, + inputValues, isDisabled, nameOverride, onBlur, @@ -170,7 +177,6 @@ const SearchField = forwardRef( placeholder, ref, testId, - uncontrolledValue, ] ); diff --git a/packages/odyssey-react-mui/src/Select.tsx b/packages/odyssey-react-mui/src/Select.tsx index a8078494c8..5faeeaf274 100644 --- a/packages/odyssey-react-mui/src/Select.tsx +++ b/packages/odyssey-react-mui/src/Select.tsx @@ -10,7 +10,7 @@ * See the License for the specific language governing permissions and limitations under the License. */ -import { memo, useCallback, useMemo, useState } from "react"; +import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Box, Checkbox as MuiCheckbox, @@ -26,6 +26,11 @@ import { Field } from "./Field"; import { FieldComponentProps } from "./FieldComponentProps"; import { CheckIcon } from "./icons.generated"; import type { SeleniumProps } from "./SeleniumProps"; +import { + ComponentControlledState, + useInputValues, + getControlState, +} from "./inputUtils"; export type SelectOption = { text: string; @@ -40,6 +45,10 @@ export type SelectProps< Value extends SelectValueType, HasMultipleChoices extends boolean > = { + /** + * The default value. Use when the component is not controlled. + */ + defaultValue?: MuiSelectProps["defaultValue"]; /** * If `true`, the Select allows multiple selections */ @@ -94,10 +103,12 @@ export type SelectProps< * - { text: string, type: "heading" } — Used to display a group heading with the text */ +const { CONTROLLED } = ComponentControlledState; const Select = < Value extends SelectValueType, HasMultipleChoices extends boolean >({ + defaultValue, errorMessage, hasMultipleChoices: hasMultipleChoicesProp, hint, @@ -121,32 +132,38 @@ const Select = < : hasMultipleChoicesProp, [hasMultipleChoicesProp, isMultiSelect] ); + const controlledStateRef = useRef( + getControlState({ controlledValue: value, uncontrolledValue: defaultValue }) + ); + const [internalSelectedValues, setInternalSelectedValues] = useState( + controlledStateRef.current === CONTROLLED ? value : defaultValue + ); - const formattedValueForMultiSelect = isMultiSelect - ? ([] as string[] as Value) - : ("" as string as Value); + useEffect(() => { + if (controlledStateRef.current === CONTROLLED) { + setInternalSelectedValues(value); + } + }, [value]); - const [selectedValue, setSelectedValue] = useState( - value === undefined ? formattedValueForMultiSelect : value - ); + const inputValues = useInputValues({ + defaultValue, + value, + controlState: controlledStateRef.current, + }); const onChange = useCallback["onChange"]>>( (event, child) => { - const valueFromEvent = event.target.value; - - if (typeof valueFromEvent === "string") { - if (hasMultipleChoices) { - setSelectedValue(valueFromEvent.split(",") as Value); - } else { - setSelectedValue(valueFromEvent as Value); - } - } else { - setSelectedValue(valueFromEvent); + const { + target: { value }, + } = event; + if (controlledStateRef.current !== CONTROLLED) { + setInternalSelectedValues( + (typeof value === "string" ? value.split(",") : value) as Value + ); } - onChangeProp?.(event, child); }, - [hasMultipleChoices, onChangeProp, setSelectedValue] + [onChangeProp] ); // Normalize the options array to accommodate the various @@ -207,14 +224,15 @@ const Select = < if (option.type === "heading") { return {option.text}; } - return ( {hasMultipleChoices && ( - + )} {option.text} - {selectedValue == option.value && ( + {internalSelectedValues === option.value && ( @@ -222,12 +240,13 @@ const Select = < ); }), - [hasMultipleChoices, normalizedOptions, selectedValue] + [hasMultipleChoices, normalizedOptions, internalSelectedValues] ); const renderFieldComponent = useCallback( ({ ariaDescribedBy, errorMessageElementId, id, labelElementId }) => ( ), [ children, + inputValues, hasMultipleChoices, nameOverride, onBlur, onChange, onFocus, renderValue, - selectedValue, testId, ] ); diff --git a/packages/odyssey-react-mui/src/TextField.tsx b/packages/odyssey-react-mui/src/TextField.tsx index c37a3bac3c..60fa8a7714 100644 --- a/packages/odyssey-react-mui/src/TextField.tsx +++ b/packages/odyssey-react-mui/src/TextField.tsx @@ -18,12 +18,14 @@ import { memo, ReactElement, useCallback, + useRef, } from "react"; import { InputAdornment, InputBase } from "@mui/material"; import { FieldComponentProps } from "./FieldComponentProps"; import { Field } from "./Field"; import { SeleniumProps } from "./SeleniumProps"; +import { useInputValues, getControlState } from "./inputUtils"; export const textFieldTypeValues = [ "email", @@ -40,6 +42,10 @@ export type TextFieldProps = { * You can learn more about it [following the specification](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill). */ autoCompleteType?: InputHTMLAttributes["autoComplete"]; + /** + * The default value. Use when the component is not controlled. + */ + defaultValue?: string; /** * End `InputAdornment` for this component. */ @@ -91,6 +97,7 @@ const TextField = forwardRef( ( { autoCompleteType, + defaultValue, hasInitialFocus, endAdornment, errorMessage, @@ -103,19 +110,41 @@ const TextField = forwardRef( label, name: nameOverride, onBlur, - onChange, + onChange: onChangeProp, onFocus, placeholder, startAdornment, testId, type = "text", - value, + value: value, }, ref ) => { + const controlledStateRef = useRef( + getControlState({ + controlledValue: value, + uncontrolledValue: defaultValue, + }) + ); + const inputValues = useInputValues({ + defaultValue, + value, + controlState: controlledStateRef.current, + }); + + const onChange = useCallback< + NonNullable> + >( + (event) => { + onChangeProp?.(event); + }, + [onChangeProp] + ); + const renderFieldComponent = useCallback( ({ ariaDescribedBy, errorMessageElementId, id, labelElementId }) => ( ( ) } type={type} - value={value} /> ), [ autoCompleteType, + inputValues, hasInitialFocus, endAdornment, isMultiline, nameOverride, + onBlur, onChange, onFocus, - onBlur, placeholder, isOptional, isReadOnly, @@ -165,7 +194,6 @@ const TextField = forwardRef( startAdornment, testId, type, - value, ] ); diff --git a/packages/odyssey-react-mui/src/inputUtils.ts b/packages/odyssey-react-mui/src/inputUtils.ts new file mode 100644 index 0000000000..fc30b3539d --- /dev/null +++ b/packages/odyssey-react-mui/src/inputUtils.ts @@ -0,0 +1,76 @@ +/*! + * Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +import { useMemo } from "react"; + +type UseControlledStateProps = { + controlledValue?: Value; + uncontrolledValue?: Value; +}; + +export const ComponentControlledState = { + CONTROLLED: "CONTROLLED", + UNCONTROLLED: "UNCONTROLLED", +}; + +export type ModeType = keyof typeof ComponentControlledState; +export type ModeTypeValue = (typeof ComponentControlledState)[ModeType]; + +export const getControlState = ({ + controlledValue, + uncontrolledValue, +}: UseControlledStateProps): ModeTypeValue => { + if (uncontrolledValue !== undefined || controlledValue === undefined) { + return ComponentControlledState.UNCONTROLLED; + } + return ComponentControlledState.CONTROLLED; +}; + +type InputValueProps = { + defaultValue?: Value; + value?: Value; + controlState: ModeTypeValue; +}; + +type InputValue = + | { + defaultValue: Value | undefined; + value?: undefined; + } + | { + value: Value | undefined; + defaultValue?: undefined; + }; + +/** + * In components that support being used in a controlled or uncontrolled way, the defaultValue and value props need + * to be suppled values in a mutually exclusive way. + * If a `value` is being provided to the component, then it is being used in a controlled manner and `defaultValue` needs to be undefined. + * If `value` is undefined, then that means the component is being used in an uncontrolled way and `defaultValue` is either Value or undefined. + * This helper helps ensure this mutual exclusivity between the 2 props so the component can operate as expected. + * + * @param {InputValueProps}: { defaultValue: Value | undefined, value: Value | undefined } + * @returns {InputValue}: { defaultValue: Value | undefined, value?: undefined } | { defaultValue?: undefined, value: Value } + */ +export const useInputValues = ({ + defaultValue, + value, + controlState, +}: InputValueProps): InputValue => { + const inputValues = useMemo(() => { + if (controlState === ComponentControlledState.CONTROLLED) { + return { value }; + } + return { defaultValue }; + }, [defaultValue, value]); + return inputValues; +}; diff --git a/packages/odyssey-react-mui/src/labs/VirtualizedAutocomplete.tsx b/packages/odyssey-react-mui/src/labs/VirtualizedAutocomplete.tsx index 5797e6917d..5a2bdfce22 100644 --- a/packages/odyssey-react-mui/src/labs/VirtualizedAutocomplete.tsx +++ b/packages/odyssey-react-mui/src/labs/VirtualizedAutocomplete.tsx @@ -17,12 +17,16 @@ import { UseAutocompleteProps, AutocompleteValue, } from "@mui/material"; -import { memo, useCallback, useMemo } from "react"; +import { memo, useCallback, useMemo, useRef } from "react"; import { Field } from "../Field"; import { FieldComponentProps } from "../FieldComponentProps"; import type { SeleniumProps } from "../SeleniumProps"; -import { useControlledState } from "../useControlledState"; +import { + ComponentControlledState, + getControlState, + useInputValues, +} from "../inputUtils"; export type AutocompleteProps< OptionType, @@ -196,6 +200,44 @@ const VirtualizedAutocomplete = < getIsOptionEqualToValue, testId, }: AutocompleteProps) => { + const controlledStateRef = useRef( + getControlState({ controlledValue: value, uncontrolledValue: defaultValue }) + ); + const defaultValueProp = useMemo< + | AutocompleteValue< + OptionType, + HasMultipleChoices, + undefined, + IsCustomValueAllowed + > + | undefined + >(() => { + if (hasMultipleChoices) { + return defaultValue === undefined + ? ([] as AutocompleteValue< + OptionType, + HasMultipleChoices, + undefined, + IsCustomValueAllowed + >) + : defaultValue; + } + return defaultValue ?? undefined; + }, [defaultValue, hasMultipleChoices]); + + const valueProps = useInputValues({ + defaultValue: defaultValueProp, + value: value, + controlState: controlledStateRef.current, + }); + + const inputValueProp = useMemo(() => { + if (controlledStateRef.current === ComponentControlledState.CONTROLLED) { + return { inputValue }; + } + return undefined; + }, [inputValue]); + const renderInput = useCallback( ({ InputLabelProps, InputProps, ...params }) => ( - | undefined - >(() => { - if (hasMultipleChoices) { - return defaultValue === undefined - ? ([] as AutocompleteValue< - OptionType, - HasMultipleChoices, - undefined, - IsCustomValueAllowed - >) - : defaultValue; - } - return defaultValue ?? undefined; - }, [defaultValue, hasMultipleChoices]); - - const [localValue, setLocalValue] = useControlledState({ - controlledValue: value, - uncontrolledValue: defaultValuesProp, - }); - - const [localInputValue, setLocalInputValue] = useControlledState({ - controlledValue: inputValue, - uncontrolledValue: undefined, - }); - const onChange = useCallback< NonNullable< UseAutocompleteProps< @@ -274,10 +283,9 @@ const VirtualizedAutocomplete = < > >( (event, value, reason, details) => { - setLocalValue(value); onChangeProp?.(event, value, reason, details); }, - [onChangeProp, setLocalValue] + [onChangeProp] ); const onInputChange = useCallback< @@ -291,18 +299,18 @@ const VirtualizedAutocomplete = < > >( (event, value, reason) => { - setLocalInputValue(value); onInputChangeProp?.(event, value, reason); }, - [onInputChangeProp, setLocalInputValue] + [onInputChangeProp] ); return ( ); diff --git a/packages/odyssey-react-mui/src/useControlledState.ts b/packages/odyssey-react-mui/src/useControlledState.ts deleted file mode 100644 index 3354b716f1..0000000000 --- a/packages/odyssey-react-mui/src/useControlledState.ts +++ /dev/null @@ -1,56 +0,0 @@ -/*! - * Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved. - * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") - * - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and limitations under the License. - */ - -import { useEffect, useRef, useState } from "react"; - -type UseControlledStateProps = { - controlledValue?: Value; // isChecked - uncontrolledValue?: Value; // isDefaultChecked -}; - -/** - * Use the same way as `useState`. Returns a stateful value, and a function to update it. - * When `initialState` is passed, the returned function to update it does nothing. This is - * useful to handle values in components that may be controlled externally when that value is - * passed in props and thus wish to prevent internal updates of the same value. - * - * @param initialState - * @see https://react.dev/reference/react/useState - */ -export const useControlledState = ({ - controlledValue, - uncontrolledValue, -}: UseControlledStateProps) => { - const isControlledMode = useRef(controlledValue !== undefined); - const [stateValue, setStateValue] = useState( - isControlledMode.current ? controlledValue : uncontrolledValue - ); - - useEffect(() => { - if (isControlledMode.current) { - setStateValue(controlledValue); - } - }, [controlledValue]); - - const setState: typeof setStateValue = (value) => { - if (!isControlledMode.current) { - setStateValue(value); - } - }; - - return [ - stateValue, - // If `value` is controlled externally, ignore calls to the setter. - // eslint-disable-next-line @typescript-eslint/no-unused-vars - setState, - ] as const; -}; diff --git a/packages/odyssey-storybook/package.json b/packages/odyssey-storybook/package.json index fa4fe2f5a9..3e1c40c43b 100644 --- a/packages/odyssey-storybook/package.json +++ b/packages/odyssey-storybook/package.json @@ -26,24 +26,24 @@ "@okta/odyssey-lifecycle": "workspace:*", "@okta/odyssey-typescript": "workspace:*", "@pxblue/storybook-rtl-addon": "^1.1.0", - "@storybook/addon-a11y": "^7.2.0", - "@storybook/addon-essentials": "^7.2.0", - "@storybook/addon-interactions": "^7.2.0", - "@storybook/addon-links": "^7.2.0", - "@storybook/addon-mdx-gfm": "^7.2.0", - "@storybook/addons": "^7.2.0", - "@storybook/api": "^7.2.0", - "@storybook/blocks": "^7.2.0", - "@storybook/client-api": "^7.2.0", - "@storybook/components": "^7.2.0", - "@storybook/core-events": "^7.2.0", + "@storybook/addon-a11y": "^7.4.0", + "@storybook/addon-essentials": "^7.4.0", + "@storybook/addon-interactions": "^7.4.0", + "@storybook/addon-links": "^7.4.0", + "@storybook/addon-mdx-gfm": "^7.4.0", + "@storybook/addons": "^7.4.0", + "@storybook/api": "^7.4.0", + "@storybook/blocks": "^7.4.0", + "@storybook/client-api": "^7.4.0", + "@storybook/components": "^7.4.0", + "@storybook/core-events": "^7.4.0", "@storybook/jest": "^0.1.0", - "@storybook/manager-api": "^7.2.0", - "@storybook/react": "^7.2.0", - "@storybook/react-vite": "^7.2.0", + "@storybook/manager-api": "^7.4.0", + "@storybook/react": "^7.4.0", + "@storybook/react-vite": "^7.4.0", "@storybook/test-runner": "^0.10.0", "@storybook/testing-library": "^0.1.0", - "@storybook/theming": "^7.2.0", + "@storybook/theming": "^7.4.0", "@types/mdx": "^2.0.1", "@types/react": "^17.0.11", "@types/react-dom": "^17.0.2", @@ -57,7 +57,7 @@ "prop-types": "^15.8.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "storybook": "^7.2.0", + "storybook": "^7.4.0", "storybook-addon-rtl-direction": "^0.0.19", "typescript": "^5.1.6", "vite": "^4.3.2" diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/Autocomplete/Autocomplete.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/Autocomplete/Autocomplete.stories.tsx index c687ec9688..62f6744cf0 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/Autocomplete/Autocomplete.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/Autocomplete/Autocomplete.stories.tsx @@ -10,7 +10,7 @@ * See the License for the specific language governing permissions and limitations under the License. */ -import { Autocomplete, AutocompleteProps } from "@okta/odyssey-react-mui"; +import { Autocomplete } from "@okta/odyssey-react-mui"; import { Meta, StoryObj } from "@storybook/react"; import { expect } from "@storybook/jest"; import { userEvent, waitFor, within, screen } from "@storybook/testing-library"; @@ -176,11 +176,7 @@ const storybookMeta: Meta = { export default storybookMeta; type StationType = { label: string }; -type AutocompleteType = AutocompleteProps< - StationType | undefined, - boolean | undefined, - boolean | undefined ->; +type AutocompleteType = typeof Autocomplete; export const Default: StoryObj = { play: async ({ canvasElement, step }) => { @@ -224,6 +220,7 @@ export const Disabled: StoryObj = { args: { isDisabled: true, value: { label: "Tycho Station" }, + getIsOptionEqualToValue: (option, value) => option.label === value.label, }, }; @@ -310,7 +307,8 @@ export const MultipleDisabled: StoryObj = { args: { hasMultipleChoices: true, isDisabled: true, - value: [{ label: "Tycho Station" }], + defaultValue: [{ label: "Tycho Station" }], + getIsOptionEqualToValue: (option, value) => option.label === value.label, }, }; @@ -318,7 +316,8 @@ export const MultipleReadOnly: StoryObj = { args: { hasMultipleChoices: true, isReadOnly: true, - value: [{ label: "Tycho Station" }], + defaultValue: [{ label: "Tycho Station" }], + getIsOptionEqualToValue: (option, value) => option.label === value.label, }, }; @@ -331,7 +330,8 @@ export const Optional: StoryObj = { export const ReadOnly: StoryObj = { args: { isReadOnly: true, - value: { label: "Tycho Station" }, + defaultValue: { label: "Tycho Station" }, + getIsOptionEqualToValue: (option, value) => option.label === value.label, }, }; @@ -377,6 +377,14 @@ const jupiterGalileanMoons: MoonMeta[] = [ export const ControlledMultipleAutocomplete: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for managing the state of Autocomplete. `onChange` should be used to listen for component changes and to update the values in the `value` prop.", + }, + }, + }, args: { options: jupiterGalileanMoons, value: jupiterGalileanMoons.slice(0, 2), @@ -407,6 +415,14 @@ export const UnontrolledMultipleAutocomplete: StoryObj }; export const ControlledAutocomplete: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for managing the state of Autocomplete. `onChange` should be used to listen for component changes and to update the values in the `value` prop.", + }, + }, + }, args: { options: jupiterGalileanMoons, value: jupiterGalileanMoons[0], diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/Checkbox/Checkbox.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/Checkbox/Checkbox.stories.tsx index f428401592..3bc0ebc2d0 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/Checkbox/Checkbox.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/Checkbox/Checkbox.stories.tsx @@ -161,6 +161,7 @@ const checkTheBox = export const Default: StoryObj = { args: { label: "Enable warp drive recalibration", + isDefaultChecked: false, }, play: async ({ canvasElement, step }) => { checkTheBox({ canvasElement, step })("Checkbox Default"); @@ -179,6 +180,7 @@ export const Required: StoryObj = { args: { label: "I agree to the terms and conditions", isRequired: true, + isDefaultChecked: false, }, play: async ({ canvasElement, step }) => { checkTheBox({ canvasElement, step })("Checkbox Required"); @@ -204,6 +206,7 @@ export const Disabled: StoryObj = { args: { label: "Pre-flight systems check complete", isDisabled: true, + isDefaultChecked: false, }, }; @@ -227,6 +230,7 @@ export const Invalid: StoryObj = { args: { label: "Pre-flight systems check complete", validity: "invalid", + isDefaultChecked: false, }, play: async ({ canvasElement, step }) => { checkTheBox({ canvasElement, step })("Checkbox Disabled"); @@ -250,14 +254,15 @@ export const Hint: StoryObj = { }, }; -export const Uncontrolled: StoryObj = { - args: { - label: "Pre-flight systems check complete", - isDefaultChecked: true, - }, -}; - export const Controlled: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for managing the state of `Checkbox`. `onChange` should be used to listen for component changes and to update the values in the `value` prop.", + }, + }, + }, args: { label: "Pre-flight systems check complete", isChecked: true, diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/NativeSelect/NativeSelect.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/NativeSelect/NativeSelect.stories.tsx index ba3865d651..67af7300b7 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/NativeSelect/NativeSelect.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/NativeSelect/NativeSelect.stories.tsx @@ -11,12 +11,13 @@ */ import { Meta, StoryObj } from "@storybook/react"; -import { NativeSelect, NativeSelectProps } from "@okta/odyssey-react-mui"; +import { NativeSelect } from "@okta/odyssey-react-mui"; import { fieldComponentPropsMetaData } from "../../../fieldComponentPropsMetaData"; import { MuiThemeDecorator } from "../../../../.storybook/components"; +import { useCallback, useState } from "react"; -const storybookMeta: Meta = { +const storybookMeta: Meta = { title: "MUI Components/Forms/NativeSelect", component: NativeSelect, argTypes: { @@ -37,7 +38,7 @@ const storybookMeta: Meta = { "The default value of the native select component. Only applicable if `value` is not provided", table: { type: { - summary: "string | undefined", + summary: "string | string[] | undefined", }, }, }, @@ -119,6 +120,7 @@ const storybookMeta: Meta = { isOptional: false, label: "Destination", id: "SolarDestination", + defaultValue: "", }, decorators: [MuiThemeDecorator], tags: ["autodocs"], @@ -126,7 +128,7 @@ const storybookMeta: Meta = { export default storybookMeta; -const Template: StoryObj = { +const Template: StoryObj = { render: function C(args) { return ( = { }, }; -const GroupTemplate: StoryObj = { +const GroupTemplate: StoryObj = { render: function C(args) { return ( @@ -190,31 +186,225 @@ const GroupTemplate: StoryObj = { }, }; -export const Default: StoryObj = { +export const Default: StoryObj = { ...Template, }; -export const DefaultDisabled: StoryObj = { +export const DefaultDisabled: StoryObj = { ...Template, args: { isDisabled: true, }, }; -export const DefaultError: StoryObj = { +export const DefaultError: StoryObj = { ...Template, args: { errorMessage: "Select your destination.", }, }; -export const DefaultGrouped: StoryObj = { +export const DefaultGrouped: StoryObj = { ...GroupTemplate, }; -export const Multi: StoryObj = { +export const Multi: StoryObj = { ...Template, args: { isMultiSelect: true, + defaultValue: [], + }, +}; + +export const Controlled: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for passing `value` to the component and listening for changes with `onChange`", + }, + }, + }, + args: {}, + render: function C(args) { + const [localValue, setLocalValue] = useState(""); + const onChange = useCallback( + (event) => setLocalValue(event.target.value), + [] + ); + return ( + + + + + + + + + + + + + + + + + + + } + /> + ); + }, +}; + +export const ControlledMultiselect: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for passing `value` to the component and listening for changes with `onChange`", + }, + }, + }, + render: function C(args) { + const [localValue, setLocalValue] = useState([""]); + const onChange = useCallback((event) => { + const options = (event as React.ChangeEvent).target + .options; + const selectedOptions: string[] = [...options] + .filter((option) => option.selected) + .map((selectedOption) => selectedOption.value); + setLocalValue(selectedOptions); + }, []); + return ( + + + + + + + + + + + + + + + + + + + } + /> + ); + }, +}; + +export const ControlledPreselected: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for passing `value` to the component and listening for changes with `onChange`", + }, + }, + }, + args: {}, + render: function C(args) { + const [localValue, setLocalValue] = useState("Laconia"); + const onChange = useCallback( + (event) => setLocalValue(event.target.value), + [] + ); + return ( + + + + + + + + + + + + + + + + + + + } + /> + ); + }, +}; + +export const ControlledPreselectedMultiselect: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for passing `value` to the component and listening for changes with `onChange`.\n\nPreselected values are referenced by the value of the `value` attritube on `option` elements.", + }, + }, + }, + render: function C(args) { + const [localValue, setLocalValue] = useState(["laconia", "new-terra"]); + const onChange = useCallback((event) => { + const options = event.target.options; + const selectedOptions: string[] = [...options] + .filter((option) => option.selected) + .map((selectedOption) => selectedOption.value); + setLocalValue(selectedOptions); + }, []); + return ( + + + + + + + + + + + + + + + + + + + } + /> + ); }, }; diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/PasswordField/PasswordField.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/PasswordField/PasswordField.stories.tsx index f200136fd7..c5356c5def 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/PasswordField/PasswordField.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/PasswordField/PasswordField.stories.tsx @@ -12,11 +12,7 @@ import { Meta, StoryObj } from "@storybook/react"; import { within } from "@storybook/testing-library"; -import { - PasswordField, - PasswordFieldProps, - odysseyTranslate, -} from "@okta/odyssey-react-mui"; +import { PasswordField, odysseyTranslate } from "@okta/odyssey-react-mui"; import { userEvent, waitFor } from "@storybook/testing-library"; import { expect } from "@storybook/jest"; @@ -24,8 +20,9 @@ import { fieldComponentPropsMetaData } from "../../../fieldComponentPropsMetaDat import { axeRun } from "../../../axe-util"; import { MuiThemeDecorator } from "../../../../.storybook/components"; +import { useCallback, useState } from "react"; -const storybookMeta: Meta = { +const storybookMeta: Meta = { title: "MUI Components/Forms/PasswordField", component: PasswordField, argTypes: { @@ -39,6 +36,19 @@ const storybookMeta: Meta = { }, }, }, + defaultValue: { + control: "text", + description: + "The value of the `input` element. Use when the component is not controlled", + table: { + type: { + summary: "string", + }, + defaultValue: { + summary: undefined, + }, + }, + }, errorMessage: fieldComponentPropsMetaData.errorMessage, hasInitialFocus: { control: "boolean", @@ -121,7 +131,7 @@ const storybookMeta: Meta = { value: { control: "text", description: - "The value of the `input` element, required for a controlled component", + "The value of the `input` element. Use when component is controlled", table: { type: { summary: "string", @@ -141,7 +151,7 @@ const storybookMeta: Meta = { export default storybookMeta; -export const Default: StoryObj = { +export const Default: StoryObj = { play: async ({ canvasElement, step }) => { await step("toggle password", async () => { const canvas = within(canvasElement); @@ -178,7 +188,7 @@ export const Default: StoryObj = { }, }; -export const Disabled: StoryObj = { +export const Disabled: StoryObj = { parameters: { docs: { description: { @@ -188,25 +198,28 @@ export const Disabled: StoryObj = { }, args: { isDisabled: true, - value: "PasswordValue", + defaultValue: "PasswordValue", }, }; -export const Error: StoryObj = { +export const Error: StoryObj = { args: { errorMessage: "This password is incorrect", + defaultValue: "", }, }; -export const Hint: StoryObj = { +export const Hint: StoryObj = { args: { hint: "Your first pet's name", + defaultValue: "", }, }; -export const NoShowPassword: StoryObj = { +export const NoShowPassword: StoryObj = { args: { hasShowPassword: false, + defaultValue: "", }, play: async ({ canvasElement, step }) => { await step("toggle password", async () => { @@ -224,13 +237,14 @@ export const NoShowPassword: StoryObj = { }, }; -export const Optional: StoryObj = { +export const Optional: StoryObj = { args: { isOptional: true, + defaultValue: "", }, }; -export const ReadOnly: StoryObj = { +export const ReadOnly: StoryObj = { parameters: { docs: { description: { @@ -240,6 +254,64 @@ export const ReadOnly: StoryObj = { }, args: { isReadOnly: true, + defaultValue: "PasswordValue", + }, +}; + +export const Controlled: StoryObj = { + parameters: { + docs: { + description: { + story: + "Provide `value` when component is to be controlled by parent. Update `value` based on updates from `onChange` event.", + }, + }, + }, + args: { + value: "", + }, + render: function C(props) { + const [localValue, setLocalValue] = useState(""); + const onChange = useCallback( + (event) => setLocalValue(event?.target.value), + [] + ); + return ( + + ); + }, +}; + +export const ControlledDefaultInput: StoryObj = { + parameters: { + docs: { + description: { + story: + "Provide `value` when component is to be controlled by parent. Update `value` based on updates from `onChange` event.", + }, + }, + }, + args: { value: "PasswordValue", }, + render: function C(props) { + const [localValue, setLocalValue] = useState("PasswordValue"); + const onChange = useCallback( + (event) => setLocalValue(event?.target.value), + [] + ); + return ( + + ); + }, }; diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/RadioGroup/RadioGroup.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/RadioGroup/RadioGroup.stories.tsx index 1113a2c702..61812c9134 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/RadioGroup/RadioGroup.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/RadioGroup/RadioGroup.stories.tsx @@ -10,7 +10,7 @@ * See the License for the specific language governing permissions and limitations under the License. */ -import { Radio, RadioGroup, RadioGroupProps } from "@okta/odyssey-react-mui"; +import { Radio, RadioGroup } from "@okta/odyssey-react-mui"; import { Meta, StoryObj } from "@storybook/react"; import { expect } from "@storybook/jest"; @@ -93,7 +93,7 @@ const storybookMeta: Meta = { export default storybookMeta; -const Template: StoryObj = { +const Template: StoryObj = { render: function C(props) { return ( @@ -105,25 +105,30 @@ const Template: StoryObj = { }, }; -export const Default: StoryObj = { +export const Default: StoryObj = { ...Template, + args: { + defaultValue: "", + }, }; -export const Hint: StoryObj = { +export const Hint: StoryObj = { ...Template, args: { hint: "Select the speed at which you wish to travel.", + defaultValue: "", }, }; -export const Disabled: StoryObj = { +export const Disabled: StoryObj = { ...Template, args: { isDisabled: true, + defaultValue: "", }, }; -export const Error: StoryObj = { +export const Error: StoryObj = { ...Template, parameters: { docs: { @@ -135,10 +140,11 @@ export const Error: StoryObj = { }, args: { errorMessage: "This field is required.", + defaultValue: "", }, }; -export const UncontrolledRadioGroup: StoryObj = { +export const UncontrolledRadioGroup: StoryObj = { ...Template, args: { defaultValue: "Warp Speed", @@ -159,8 +165,15 @@ export const UncontrolledRadioGroup: StoryObj = { }, }; -export const ControlledRadioGroup: StoryObj = { - ...Template, +export const ControlledRadioGroup: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for managing the state of `RadioGroup`. `onChange` should be used to listen for component changes and to update the values in the `value` prop.", + }, + }, + }, args: { value: "Ludicrous Speed", }, diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/SearchField/SearchField.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/SearchField/SearchField.stories.tsx index d0d000ffb6..aa577a412c 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/SearchField/SearchField.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/SearchField/SearchField.stories.tsx @@ -11,12 +11,13 @@ */ import { Meta, StoryObj } from "@storybook/react"; -import { SearchField, SearchFieldProps } from "@okta/odyssey-react-mui"; +import { SearchField } from "@okta/odyssey-react-mui"; import { fieldComponentPropsMetaData } from "../../../fieldComponentPropsMetaData"; import { MuiThemeDecorator } from "../../../../.storybook/components"; +import { useCallback, useState } from "react"; -const storybookMeta: Meta = { +const storybookMeta: Meta = { title: "MUI Components/Forms/SearchField", component: SearchField, argTypes: { @@ -28,6 +29,22 @@ const storybookMeta: Meta = { type: { summary: "string", }, + defaultValue: { + summary: undefined, + }, + }, + }, + defaultValue: { + control: "text", + description: + "The value of the `input` element. Use when the component is not controlled", + table: { + type: { + summary: "string", + }, + defaultValue: { + summary: undefined, + }, }, }, hasInitialFocus: { @@ -105,11 +122,14 @@ const storybookMeta: Meta = { value: { control: "text", description: - "The value of the `input` element, required for a controlled component", + "The value of the `input` element. Use when the component is controlled", table: { type: { summary: "string", }, + defaultValue: { + summary: undefined, + }, }, }, }, @@ -123,4 +143,32 @@ const storybookMeta: Meta = { export default storybookMeta; -export const Default: StoryObj = {}; +export const Default: StoryObj = { + args: { + defaultValue: "", + }, +}; + +export const ControlledSearch: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for managing the state of `SearchField`. `onChange` should be used to listen for component changes and to update the values in the `value` prop.", + }, + }, + }, + args: { + defaultValue: undefined, + }, + render: function C(props) { + const [constrolledValue, setControlledValue] = useState("Jupiter"); + const onChange = useCallback( + (event) => setControlledValue(event.target.value), + [] + ); + return ( + + ); + }, +}; diff --git a/packages/odyssey-storybook/src/components/odyssey-mui/Select/Select.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-mui/Select/Select.stories.tsx index c391871568..39a361abfd 100644 --- a/packages/odyssey-storybook/src/components/odyssey-mui/Select/Select.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-mui/Select/Select.stories.tsx @@ -16,6 +16,7 @@ import { MuiThemeDecorator } from "../../../../.storybook/components"; import { userEvent, waitFor, screen } from "@storybook/testing-library"; import { axeRun } from "../../../axe-util"; import { expect } from "@storybook/jest"; +import { useCallback, useState } from "react"; const optionsArray: SelectProps["options"] = [ "Earth", @@ -106,6 +107,19 @@ const storybookMeta: Meta> = { title: "MUI Components/Forms/Select", component: Select, argTypes: { + defaultValue: { + control: "text", + description: + "The default value. Use when the component is not controlled.", + table: { + type: { + summary: "string | string[]", + }, + defaultValue: { + summary: undefined, + }, + }, + }, errorMessage: { control: "text", description: "The error message for the select component", @@ -236,7 +250,8 @@ const storybookMeta: Meta> = { }, value: { control: "text", - description: "The value or values selected in the select component", + description: + "The `input` value. Use when the component is controlled.\n\nProviding an empty string will select no options.\n\nSet to an empty string `''` if you don't want any of the available options to be selected.", table: { type: { summary: "string | string[]", @@ -255,7 +270,7 @@ const storybookMeta: Meta> = { export default storybookMeta; -export const Default: StoryObj> = { +export const Default: StoryObj = { play: async ({ canvasElement, step }) => { await step("Select Earth from the listbox", async () => { const comboBoxElement = canvasElement.querySelector( @@ -276,17 +291,19 @@ export const Default: StoryObj> = { }); }, }; -Default.args = {}; +Default.args = { defaultValue: "" }; -export const Disabled: StoryObj> = { +export const Disabled: StoryObj = { args: { isDisabled: true, + defaultValue: "", }, }; -export const Error: StoryObj> = { +export const Error: StoryObj = { args: { errorMessage: "Select your destination.", + defaultValue: "", }, play: async ({ step }) => { await step("Check for a11y errors on Select Error", async () => { @@ -295,39 +312,40 @@ export const Error: StoryObj> = { }, }; -export const OptionsObject: StoryObj> = - { - args: { - options: optionsObject, - }, - parameters: { - docs: { - description: { - story: - "Select can accept `options` as a flat array, an array of objects, or both. This demonstrates an array of objects with `value` and `name`.", - }, +export const OptionsObject: StoryObj = { + args: { + options: optionsObject, + defaultValue: "", + }, + parameters: { + docs: { + description: { + story: + "Select can accept `options` as a flat array, an array of objects, or both. This demonstrates an array of objects with `value` and `name`.", }, }, - }; + }, +}; -export const OptionsGrouped: StoryObj> = - { - args: { - options: optionsGrouped, - }, - parameters: { - docs: { - description: { - story: - 'Objects with `type: "heading"` will have their `text` displayed as a heading.', - }, +export const OptionsGrouped: StoryObj = { + args: { + options: optionsGrouped, + defaultValue: "", + }, + parameters: { + docs: { + description: { + story: + 'Objects with `type: "heading"` will have their `text` displayed as a heading.', }, }, - }; + }, +}; -export const MultiSelect: StoryObj> = { +export const MultiSelect: StoryObj = { args: { isMultiSelect: true, + defaultValue: [], }, play: async ({ canvasElement, step }) => { await step("Select Multiple items from the listbox", async () => { @@ -351,3 +369,71 @@ export const MultiSelect: StoryObj> = { }); }, }; + +export const ControlledSelect: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for managing the state of `Select`. `onChange` should be used to listen for component changes and to update the values in the `value` prop.", + }, + }, + }, + args: { + value: "", + }, + render: function C(props) { + const [localValue, setLocalValue] = useState(""); + const onChange = useCallback( + (event) => setLocalValue(event.target.value), + [] + ); + return ; + }, +}; + +export const ControlledPreselectedMultipleSelect: StoryObj = { + parameters: { + docs: { + description: { + story: + "When the component is controlled, the parent component is responsible for managing the state of `Select`. `onChange` should be used to listen for component changes and to update the values in the `value` prop.", + }, + }, + }, + args: { + value: [], + hasMultipleChoices: true, + }, + render: function C(props) { + const [localValue, setLocalValue] = useState(["Earth", "Mars"]); + const onChange = useCallback( + (event) => setLocalValue(event.target.value), + [] + ); + return