From 6afad5820b7872fe2da852f2570229be2d2d26ae Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Thu, 2 Jan 2025 16:11:59 +0100 Subject: [PATCH 01/14] init mig --- src/preview/elevated-modal/anchor.css | 7 ++++ src/preview/elevated-modal/anchor.tsx | 16 +++++++++ src/preview/elevated-modal/constants.ts | 3 ++ src/preview/elevated-modal/index.ts | 7 ++++ src/preview/elevated-modal/provider.tsx | 44 +++++++++++++++++++++++++ src/preview/index.ts | 0 tsconfig.json | 2 ++ 7 files changed, 79 insertions(+) create mode 100644 src/preview/elevated-modal/anchor.css create mode 100644 src/preview/elevated-modal/anchor.tsx create mode 100644 src/preview/elevated-modal/constants.ts create mode 100644 src/preview/elevated-modal/index.ts create mode 100644 src/preview/elevated-modal/provider.tsx create mode 100644 src/preview/index.ts diff --git a/src/preview/elevated-modal/anchor.css b/src/preview/elevated-modal/anchor.css new file mode 100644 index 0000000..938c87f --- /dev/null +++ b/src/preview/elevated-modal/anchor.css @@ -0,0 +1,7 @@ +#modal-anchor-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} diff --git a/src/preview/elevated-modal/anchor.tsx b/src/preview/elevated-modal/anchor.tsx new file mode 100644 index 0000000..af571f5 --- /dev/null +++ b/src/preview/elevated-modal/anchor.tsx @@ -0,0 +1,16 @@ +import { useModalContext } from "@preview/elevated-modal/provider"; + +import constants from "@preview/elevated-modal/constants"; +import "./anchor.css"; + +export default function ModalAnchor() { + const { Modal, isActivated } = useModalContext(); + + return ( + isActivated && ( +
+ {Modal && Modal} +
+ ) + ); +} diff --git a/src/preview/elevated-modal/constants.ts b/src/preview/elevated-modal/constants.ts new file mode 100644 index 0000000..bc63a60 --- /dev/null +++ b/src/preview/elevated-modal/constants.ts @@ -0,0 +1,3 @@ +export default { + modalAnchorContainerId: "modal-anchor-container", +}; diff --git a/src/preview/elevated-modal/index.ts b/src/preview/elevated-modal/index.ts new file mode 100644 index 0000000..317adc4 --- /dev/null +++ b/src/preview/elevated-modal/index.ts @@ -0,0 +1,7 @@ +import { useModalContext, ModalContextProvider } from "@preview/elevated-modal/provider"; + +import ModalAnchor from "@preview/elevated-modal/anchor"; + +import constants from "@preview/elevated-modal/constants"; + +export { useModalContext, ModalContextProvider, ModalAnchor, constants }; diff --git a/src/preview/elevated-modal/provider.tsx b/src/preview/elevated-modal/provider.tsx new file mode 100644 index 0000000..6d61b8f --- /dev/null +++ b/src/preview/elevated-modal/provider.tsx @@ -0,0 +1,44 @@ +import { createContext, useState, useContext, useMemo } from "react"; +import type { ReactNode, JSX, Dispatch, SetStateAction } from "react"; + +type TProps = { + isActivated: boolean; + setIsActivated: Dispatch>; + Modal: JSX.Element | null; + setModal: Dispatch>; +}; + +const ModalContext = createContext(undefined); + +function ModalContextProvider({ children }: { children: ReactNode }) { + const [Modal, setModal] = useState(null); + const [isActivated, setIsActivated] = useState(false); + + const contextValue = useMemo( + () => ({ + Modal, + setModal, + isActivated, + setIsActivated, + }), + [Modal, setModal, isActivated, setIsActivated], + ); + + return ( + + {children} + + ); +} + +function useModalContext() { + const context = useContext(ModalContext); + if (!context) { + throw new Error( + "useModalContext must be used within a ModalContextProvider", + ); + } + return context; +} + +export { useModalContext, ModalContextProvider }; diff --git a/src/preview/index.ts b/src/preview/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json index 18e8b91..ac93797 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,6 +24,8 @@ // Aliases "baseUrl": ".", "paths": { + "@preview*": ["src/preview/*"], + "@preview": ["src/preview/index.ts"], "@components/*": ["src/components/*"], "@components": ["src/components/index.ts"], "@hooks/*": ["src/hooks/*"], From 86ef21ebaa5ae293ebec6edc1c09a8993f310783 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Thu, 2 Jan 2025 16:15:10 +0100 Subject: [PATCH 02/14] Storybook example --- .../elevated-modal/example/example.tsx | 38 +++++++++++++++++++ src/preview/elevated-modal/example/func.tsx | 37 ++++++++++++++++++ src/preview/elevated-modal/example/index.ts | 3 ++ src/preview/elevated-modal/example/root.tsx | 11 ++++++ src/preview/elevated-modal/example/stories.ts | 14 +++++++ 5 files changed, 103 insertions(+) create mode 100644 src/preview/elevated-modal/example/example.tsx create mode 100644 src/preview/elevated-modal/example/func.tsx create mode 100644 src/preview/elevated-modal/example/index.ts create mode 100644 src/preview/elevated-modal/example/root.tsx create mode 100644 src/preview/elevated-modal/example/stories.ts diff --git a/src/preview/elevated-modal/example/example.tsx b/src/preview/elevated-modal/example/example.tsx new file mode 100644 index 0000000..8f3c4df --- /dev/null +++ b/src/preview/elevated-modal/example/example.tsx @@ -0,0 +1,38 @@ +/* eslint-disable react/button-has-type */ +type TProps = { + someString: string; + someNumber: number; + someObject: { + someKey: string; + }; + onAbort: () => void; +}; + +export default function ExampleModal({ + someString, + someNumber, + someObject, + onAbort, +}: TProps) { + return ( +
+
+

Modal Header with {someString}

+

+ Modal Content this number: {someNumber} and this key{" "} + {someObject.someKey} +

+ +
+
+ ); +} diff --git a/src/preview/elevated-modal/example/func.tsx b/src/preview/elevated-modal/example/func.tsx new file mode 100644 index 0000000..2ce13ef --- /dev/null +++ b/src/preview/elevated-modal/example/func.tsx @@ -0,0 +1,37 @@ +/* eslint-disable react/button-has-type */ +import { useModalContext } from "src/lib"; +import ExampleModal from "@preview/elevated-modal/example/example"; + +export default function App() { + const { setIsActivated, setModal } = useModalContext(); + return ( +
+ +
+ ); +} diff --git a/src/preview/elevated-modal/example/index.ts b/src/preview/elevated-modal/example/index.ts new file mode 100644 index 0000000..79343d0 --- /dev/null +++ b/src/preview/elevated-modal/example/index.ts @@ -0,0 +1,3 @@ +import App from "@preview/elevated-modal/example/func"; + +export default App; diff --git a/src/preview/elevated-modal/example/root.tsx b/src/preview/elevated-modal/example/root.tsx new file mode 100644 index 0000000..3d6479c --- /dev/null +++ b/src/preview/elevated-modal/example/root.tsx @@ -0,0 +1,11 @@ +import { ModalContextProvider, ModalAnchor } from "@preview/elevated-modal"; +import App from "@preview/elevated-modal/example"; + +export default function Root() { + return ( + + + + + ); +} diff --git a/src/preview/elevated-modal/example/stories.ts b/src/preview/elevated-modal/example/stories.ts new file mode 100644 index 0000000..bfafc3d --- /dev/null +++ b/src/preview/elevated-modal/example/stories.ts @@ -0,0 +1,14 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import Root from "@preview/elevated-modal/example/root"; + +const meta: Meta = { + title: "Preview/Elevated Modal", + component: Root, + args: {}, +}; + +export default meta; + +type Story = StoryObj; + +export const Index: Story = {}; From 8787d121b9c092593c0420b6616d44855cb4bc8e Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Thu, 2 Jan 2025 15:33:14 +0000 Subject: [PATCH 03/14] example migration --- src/preview/elevated-modal/example/func.tsx | 2 +- .../elevated-modal/example/{stories.ts => stories.tsx} | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) rename src/preview/elevated-modal/example/{stories.ts => stories.tsx} (59%) diff --git a/src/preview/elevated-modal/example/func.tsx b/src/preview/elevated-modal/example/func.tsx index 2ce13ef..60c2157 100644 --- a/src/preview/elevated-modal/example/func.tsx +++ b/src/preview/elevated-modal/example/func.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/button-has-type */ -import { useModalContext } from "src/lib"; +import { useModalContext } from "@preview/elevated-modal"; import ExampleModal from "@preview/elevated-modal/example/example"; export default function App() { diff --git a/src/preview/elevated-modal/example/stories.ts b/src/preview/elevated-modal/example/stories.tsx similarity index 59% rename from src/preview/elevated-modal/example/stories.ts rename to src/preview/elevated-modal/example/stories.tsx index bfafc3d..f1cc263 100644 --- a/src/preview/elevated-modal/example/stories.ts +++ b/src/preview/elevated-modal/example/stories.tsx @@ -5,6 +5,16 @@ const meta: Meta = { title: "Preview/Elevated Modal", component: Root, args: {}, + parameters: { + layout: "fullscreen", + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], }; export default meta; From b700e665e407da397fb75e07c981e40a0e799913 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 16:58:03 +0000 Subject: [PATCH 04/14] init adds --- .editorconfig | 21 +++++++++++++++++++++ makefile | 10 +++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..40c1cfa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false + +[*.mk] +indent_style = tab +indent_size = 2 + +[makefile] +indent_style = tab +indent_size = 2 \ No newline at end of file diff --git a/makefile b/makefile index c31c8fd..d0d56bd 100644 --- a/makefile +++ b/makefile @@ -28,4 +28,12 @@ endef define echo_purple echo -e ${PURPLE}$1${NC} -endef \ No newline at end of file +endef + +git-sync-prod: + @echo "Syncing with prod branch" + git fetch origin production:production + +git-sync-dev: + @echo "Syncing with dev branch" + git fetch origin development:development From 8d9aca1a7fb76befccaea0b6c1f7b53ab1b0fc71 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:10:00 +0000 Subject: [PATCH 05/14] added previews --- package-lock.json | 12 ++-- package.json | 2 + .../StrippedDialogSurface/func.tsx | 60 +++++++++++++++++++ .../StrippedDialogSurface/index.ts | 3 + .../StrippedDialogSurface/styles.ts | 18 ++++++ .../elevated-modal/example/example.tsx | 51 ++++++++++------ 6 files changed, 122 insertions(+), 24 deletions(-) create mode 100644 src/preview/elevated-modal/StrippedDialogSurface/func.tsx create mode 100644 src/preview/elevated-modal/StrippedDialogSurface/index.ts create mode 100644 src/preview/elevated-modal/StrippedDialogSurface/styles.ts diff --git a/package-lock.json b/package-lock.json index 4d6eab1..6b0aa6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,19 @@ { "name": "fluentui-helpers", - "version": "0.1.0", + "version": "0.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "fluentui-helpers", - "version": "0.1.0", + "version": "0.2.2", "license": "MIT", "devDependencies": { "@babel/preset-env": "^7.25.9", "@babel/preset-typescript": "^7.25.9", "@fluentui/react-components": "^9.55.0", "@fluentui/react-icons": "^2.0.261", + "@fluentui/react-motion-components-preview": "^0.4.1", "@griffel/react": "^1.5.25", "@griffel/tag-processor": "^1.0.7", "@griffel/vite-plugin": "^0.1.7", @@ -63,9 +64,10 @@ "vite-tsconfig-paths": "^5.0.1" }, "peerDependencies": { - "@fluentui/react-components": "^9.55.0", - "@fluentui/react-icons": "^2.0.261", - "@griffel/react": "^1.5.25", + "@fluentui/react-components": "^9", + "@fluentui/react-icons": "^2", + "@fluentui/react-motion-components-preview": "^0.4.1", + "@griffel/react": "^1.5", "react": "^18 || ^17", "react-dom": "^18 || ^17" } diff --git a/package.json b/package.json index 6b8346f..86ab120 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "peerDependencies": { "@fluentui/react-components": "^9", "@fluentui/react-icons": "^2", + "@fluentui/react-motion-components-preview": "^0.4.1", "@griffel/react": "^1.5", "react": "^18 || ^17", "react-dom": "^18 || ^17" @@ -22,6 +23,7 @@ "@babel/preset-typescript": "^7.25.9", "@fluentui/react-components": "^9.55.0", "@fluentui/react-icons": "^2.0.261", + "@fluentui/react-motion-components-preview": "^0.4.1", "@griffel/react": "^1.5.25", "@griffel/tag-processor": "^1.0.7", "@griffel/vite-plugin": "^0.1.7", diff --git a/src/preview/elevated-modal/StrippedDialogSurface/func.tsx b/src/preview/elevated-modal/StrippedDialogSurface/func.tsx new file mode 100644 index 0000000..c75f10e --- /dev/null +++ b/src/preview/elevated-modal/StrippedDialogSurface/func.tsx @@ -0,0 +1,60 @@ +import type { JSX } from "react"; + +import { mergeClasses } from "@fluentui/react-components"; +import { Fade } from "@fluentui/react-motion-components-preview"; + +import { Flex } from "@components/layout"; + +import useStrippedDialogSurfaceClasses from "./styles"; + +type TProps = { + enhancementOptions?: { + rootSurfaceStyles?: boolean; + defaultDimensions?: boolean; + parentCenteringContainer?: boolean; + fadeInFadeOutEffect?: boolean; + }; + children: JSX.Element; + className?: string; +}; + +export default function StrippedDialogSurface({ + enhancementOptions = { + rootSurfaceStyles: true, + defaultDimensions: true, + parentCenteringContainer: true, + fadeInFadeOutEffect: true, + }, + children, + className = undefined, +}: TProps): JSX.Element { + const classes = useStrippedDialogSurfaceClasses(); + const bareSurface = ( +
+ {children} +
+ ); + return enhancementOptions.parentCenteringContainer ? ( + + {bareSurface} + + ) : ( + bareSurface + ); +} diff --git a/src/preview/elevated-modal/StrippedDialogSurface/index.ts b/src/preview/elevated-modal/StrippedDialogSurface/index.ts new file mode 100644 index 0000000..701a066 --- /dev/null +++ b/src/preview/elevated-modal/StrippedDialogSurface/index.ts @@ -0,0 +1,3 @@ +import StrippedDialogSurface from "@previewelevated-modal/StrippedDialogSurface/func"; + +export default StrippedDialogSurface; diff --git a/src/preview/elevated-modal/StrippedDialogSurface/styles.ts b/src/preview/elevated-modal/StrippedDialogSurface/styles.ts new file mode 100644 index 0000000..b018d1d --- /dev/null +++ b/src/preview/elevated-modal/StrippedDialogSurface/styles.ts @@ -0,0 +1,18 @@ +import { makeStyles, tokens } from "@fluentui/react-components"; +import { EThemeSpacing } from "@theme/tokens"; + +const useElevatedModalClasses = makeStyles({ + root: { + padding: EThemeSpacing.XXL, + border: `1px solid ${tokens.colorTransparentStroke}`, + borderRadius: tokens.borderRadiusXLarge, + boxShadow: tokens.shadow64, + backgroundColor: tokens.colorNeutralBackground1, + }, + defaultDimensions: { + maxWidth: "600px", + height: "fit-content", + }, +}); + +export default useElevatedModalClasses; diff --git a/src/preview/elevated-modal/example/example.tsx b/src/preview/elevated-modal/example/example.tsx index 8f3c4df..4382fe0 100644 --- a/src/preview/elevated-modal/example/example.tsx +++ b/src/preview/elevated-modal/example/example.tsx @@ -1,4 +1,16 @@ /* eslint-disable react/button-has-type */ + +import { + DialogTrigger, + DialogTitle, + DialogBody, + DialogActions, + DialogContent, + Button, +} from "@fluentui/react-components"; + +import StrippedDialogSurface from "@previewelevated-modal/StrippedDialogSurface"; + type TProps = { someString: string; someNumber: number; @@ -15,24 +27,25 @@ export default function ExampleModal({ onAbort, }: TProps) { return ( -
-
-

Modal Header with {someString}

-

- Modal Content this number: {someNumber} and this key{" "} - {someObject.someKey} -

- -
-
+ + + Dialog title -- {someString} + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam + exercitationem cumque repellendus eaque est dolor eius expedita nulla + ullam? Tenetur reprehenderit aut voluptatum impedit voluptates in + natus iure cumque eaque? Some number: {someNumber} and some object + key: {someObject.someKey} + + + + + + + + + ); } From cb86c2372902ba64e47c4d32dd7ced7817e99f79 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:21:22 +0000 Subject: [PATCH 06/14] unfinished wrapper, prob not needed --- .../StrippedDialogSurface/func.tsx | 21 ++++++++++++------- .../StrippedDialogSurface/styles.ts | 11 ++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/preview/elevated-modal/StrippedDialogSurface/func.tsx b/src/preview/elevated-modal/StrippedDialogSurface/func.tsx index c75f10e..5610aa9 100644 --- a/src/preview/elevated-modal/StrippedDialogSurface/func.tsx +++ b/src/preview/elevated-modal/StrippedDialogSurface/func.tsx @@ -46,14 +46,19 @@ export default function StrippedDialogSurface({ ); return enhancementOptions.parentCenteringContainer ? ( - - {bareSurface} - + +
+ + {bareSurface} + +
+
) : ( bareSurface ); diff --git a/src/preview/elevated-modal/StrippedDialogSurface/styles.ts b/src/preview/elevated-modal/StrippedDialogSurface/styles.ts index b018d1d..48eaadd 100644 --- a/src/preview/elevated-modal/StrippedDialogSurface/styles.ts +++ b/src/preview/elevated-modal/StrippedDialogSurface/styles.ts @@ -13,6 +13,17 @@ const useElevatedModalClasses = makeStyles({ maxWidth: "600px", height: "fit-content", }, + centerRoot: { + // fade in animation for the modal + backgroundColor: "rgba(0, 0, 0, 0.4)", + // animationName: { + // to: { + // backgroundColor: "rgba(0, 0, 0, 0.4)", + // }, + // }, + // animationDuration: "0.5s", + // animationFillMode: "forwards", + }, }); export default useElevatedModalClasses; From e6d32afa4bc4df32cd097a01b11798acf6ba4c55 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:26:20 +0000 Subject: [PATCH 07/14] added preview export --- src/index.ts | 7 +++++++ src/preview/elevated-modal/index.ts | 15 +++++++++++++-- src/preview/index.ts | 7 +++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9244973..55ec370 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,10 @@ export { EThemeSpacing, EThemeIconSizes, EThemeDimensions } from "@theme"; export { useFuiProviderNode } from "@hooks"; export { Flex, ButtonGroup } from "@components"; +export { + useModalContext, + ModalAnchor, + ModalContextProvider, + EXP_StrippedDialogSurface, + ElevatedModalConstants, +} from "@preview"; diff --git a/src/preview/elevated-modal/index.ts b/src/preview/elevated-modal/index.ts index 317adc4..f910de4 100644 --- a/src/preview/elevated-modal/index.ts +++ b/src/preview/elevated-modal/index.ts @@ -1,7 +1,18 @@ -import { useModalContext, ModalContextProvider } from "@preview/elevated-modal/provider"; +import { + useModalContext, + ModalContextProvider, +} from "@preview/elevated-modal/provider"; import ModalAnchor from "@preview/elevated-modal/anchor"; import constants from "@preview/elevated-modal/constants"; -export { useModalContext, ModalContextProvider, ModalAnchor, constants }; +import StrippedDialogSurface from "@previewelevated-modal/StrippedDialogSurface"; + +export { + useModalContext, + ModalContextProvider, + ModalAnchor, + constants, + StrippedDialogSurface as EXP_StrippedDialogSurface, +}; diff --git a/src/preview/index.ts b/src/preview/index.ts index e69de29..9b84c83 100644 --- a/src/preview/index.ts +++ b/src/preview/index.ts @@ -0,0 +1,7 @@ +export { + useModalContext, + ModalAnchor, + ModalContextProvider, + EXP_StrippedDialogSurface, + constants as ElevatedModalConstants, +} from "@preview/elevated-modal"; From c1be81d5c46af26f8b0b2f41fe47a055389b26c9 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:36:13 +0000 Subject: [PATCH 08/14] story rn --- src/preview/elevated-modal/example/index.ts | 3 --- src/preview/elevated-modal/{example => stories}/example.tsx | 0 src/preview/elevated-modal/{example => stories}/func.tsx | 2 +- src/preview/elevated-modal/stories/index.ts | 3 +++ src/preview/elevated-modal/{example => stories}/root.tsx | 2 +- src/preview/elevated-modal/{example => stories}/stories.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 src/preview/elevated-modal/example/index.ts rename src/preview/elevated-modal/{example => stories}/example.tsx (100%) rename src/preview/elevated-modal/{example => stories}/func.tsx (92%) create mode 100644 src/preview/elevated-modal/stories/index.ts rename src/preview/elevated-modal/{example => stories}/root.tsx (81%) rename src/preview/elevated-modal/{example => stories}/stories.tsx (88%) diff --git a/src/preview/elevated-modal/example/index.ts b/src/preview/elevated-modal/example/index.ts deleted file mode 100644 index 79343d0..0000000 --- a/src/preview/elevated-modal/example/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import App from "@preview/elevated-modal/example/func"; - -export default App; diff --git a/src/preview/elevated-modal/example/example.tsx b/src/preview/elevated-modal/stories/example.tsx similarity index 100% rename from src/preview/elevated-modal/example/example.tsx rename to src/preview/elevated-modal/stories/example.tsx diff --git a/src/preview/elevated-modal/example/func.tsx b/src/preview/elevated-modal/stories/func.tsx similarity index 92% rename from src/preview/elevated-modal/example/func.tsx rename to src/preview/elevated-modal/stories/func.tsx index 60c2157..b8777a3 100644 --- a/src/preview/elevated-modal/example/func.tsx +++ b/src/preview/elevated-modal/stories/func.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/button-has-type */ import { useModalContext } from "@preview/elevated-modal"; -import ExampleModal from "@preview/elevated-modal/example/example"; +import ExampleModal from "@previewelevated-modal/stories/example"; export default function App() { const { setIsActivated, setModal } = useModalContext(); diff --git a/src/preview/elevated-modal/stories/index.ts b/src/preview/elevated-modal/stories/index.ts new file mode 100644 index 0000000..7699c70 --- /dev/null +++ b/src/preview/elevated-modal/stories/index.ts @@ -0,0 +1,3 @@ +import App from "@previewelevated-modal/stories/func"; + +export default App; diff --git a/src/preview/elevated-modal/example/root.tsx b/src/preview/elevated-modal/stories/root.tsx similarity index 81% rename from src/preview/elevated-modal/example/root.tsx rename to src/preview/elevated-modal/stories/root.tsx index 3d6479c..b552dc2 100644 --- a/src/preview/elevated-modal/example/root.tsx +++ b/src/preview/elevated-modal/stories/root.tsx @@ -1,5 +1,5 @@ import { ModalContextProvider, ModalAnchor } from "@preview/elevated-modal"; -import App from "@preview/elevated-modal/example"; +import App from "@previewelevated-modal/stories"; export default function Root() { return ( diff --git a/src/preview/elevated-modal/example/stories.tsx b/src/preview/elevated-modal/stories/stories.tsx similarity index 88% rename from src/preview/elevated-modal/example/stories.tsx rename to src/preview/elevated-modal/stories/stories.tsx index f1cc263..69583a3 100644 --- a/src/preview/elevated-modal/example/stories.tsx +++ b/src/preview/elevated-modal/stories/stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; -import Root from "@preview/elevated-modal/example/root"; +import Root from "@previewelevated-modal/stories/root"; const meta: Meta = { title: "Preview/Elevated Modal", From 615d5a5ac3113670633fc48264d3c908eb4cf996 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:42:15 +0000 Subject: [PATCH 09/14] mvd files with trapp --- .../elevated-modal/{ => Anchor}/anchor.css | 0 .../Anchor/branches/Trapped.tsx | 56 +++++++++++++++++++ .../branches/Untrapped.tsx} | 12 ++-- .../elevated-modal/Anchor/branches/index.ts | 2 + src/preview/elevated-modal/Anchor/func.tsx | 14 +++++ 5 files changed, 80 insertions(+), 4 deletions(-) rename src/preview/elevated-modal/{ => Anchor}/anchor.css (100%) create mode 100644 src/preview/elevated-modal/Anchor/branches/Trapped.tsx rename src/preview/elevated-modal/{anchor.tsx => Anchor/branches/Untrapped.tsx} (55%) create mode 100644 src/preview/elevated-modal/Anchor/branches/index.ts create mode 100644 src/preview/elevated-modal/Anchor/func.tsx diff --git a/src/preview/elevated-modal/anchor.css b/src/preview/elevated-modal/Anchor/anchor.css similarity index 100% rename from src/preview/elevated-modal/anchor.css rename to src/preview/elevated-modal/Anchor/anchor.css diff --git a/src/preview/elevated-modal/Anchor/branches/Trapped.tsx b/src/preview/elevated-modal/Anchor/branches/Trapped.tsx new file mode 100644 index 0000000..46d7fdd --- /dev/null +++ b/src/preview/elevated-modal/Anchor/branches/Trapped.tsx @@ -0,0 +1,56 @@ +import { useEffect, useRef } from "react"; +import { useModalContext } from "@preview/elevated-modal/provider"; +import constants from "@preview/elevated-modal/constants"; + +export default function Trapped() { + const { Modal, isActivated } = useModalContext(); + const modalRef = useRef(null); + + useEffect(() => { + if (!isActivated || !modalRef.current) return; + + const focusableElements = modalRef.current.querySelectorAll( + 'a[href], button, textarea, input[type="text"], input[type="radio"], input[type="checkbox"], select, [tabindex]:not([tabindex="-1"])', + ); + const firstElement = focusableElements[0]; + const lastElement = focusableElements[focusableElements.length - 1]; + + const trapFocus = (e: KeyboardEvent) => { + if (e.key !== "Tab") return; + + if (e.shiftKey) { + if (document.activeElement === firstElement) { + lastElement.focus(); + e.preventDefault(); + } + } else { + if (document.activeElement === lastElement) { + firstElement.focus(); + e.preventDefault(); + } + } + }; + + modalRef.current.addEventListener("keydown", trapFocus); + + // Focus the first element when the modal is activated + firstElement.focus(); + + return () => { + modalRef.current?.removeEventListener("keydown", trapFocus); + }; + }, [isActivated]); + + return ( + isActivated && ( + + ) + ); +} diff --git a/src/preview/elevated-modal/anchor.tsx b/src/preview/elevated-modal/Anchor/branches/Untrapped.tsx similarity index 55% rename from src/preview/elevated-modal/anchor.tsx rename to src/preview/elevated-modal/Anchor/branches/Untrapped.tsx index af571f5..23d2b0d 100644 --- a/src/preview/elevated-modal/anchor.tsx +++ b/src/preview/elevated-modal/Anchor/branches/Untrapped.tsx @@ -1,15 +1,19 @@ import { useModalContext } from "@preview/elevated-modal/provider"; import constants from "@preview/elevated-modal/constants"; -import "./anchor.css"; -export default function ModalAnchor() { +export default function Untrapped() { const { Modal, isActivated } = useModalContext(); return ( isActivated && ( -
- {Modal && Modal} + ) ); diff --git a/src/preview/elevated-modal/Anchor/branches/index.ts b/src/preview/elevated-modal/Anchor/branches/index.ts new file mode 100644 index 0000000..5f4fbae --- /dev/null +++ b/src/preview/elevated-modal/Anchor/branches/index.ts @@ -0,0 +1,2 @@ +export { default as UntrappedBranch } from "@previewelevated-modal/Anchor/branches/Untrapped"; +export { default as TrappedBranch } from "@previewelevated-modal/Anchor/branches/Trapped"; diff --git a/src/preview/elevated-modal/Anchor/func.tsx b/src/preview/elevated-modal/Anchor/func.tsx new file mode 100644 index 0000000..e4ca111 --- /dev/null +++ b/src/preview/elevated-modal/Anchor/func.tsx @@ -0,0 +1,14 @@ +import "./anchor.css"; + +import { + TrappedBranch, + UntrappedBranch, +} from "@previewelevated-modal/Anchor/branches"; + +type TProps = { + disableTrapping?: boolean; +}; + +export default function ModalAnchor({ disableTrapping = false }: TProps) { + return disableTrapping ? : ; +} From c61790727a09b3c3a9b38bb0858ba04788aec940 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:47:03 +0000 Subject: [PATCH 10/14] with trapping addition --- src/preview/elevated-modal/{Anchor => ModalAnchor}/anchor.css | 0 .../{Anchor => ModalAnchor}/branches/Trapped.tsx | 0 .../{Anchor => ModalAnchor}/branches/Untrapped.tsx | 0 .../elevated-modal/{Anchor => ModalAnchor}/branches/index.ts | 4 ++-- src/preview/elevated-modal/{Anchor => ModalAnchor}/func.tsx | 2 +- src/preview/elevated-modal/ModalAnchor/index.ts | 3 +++ src/preview/elevated-modal/index.ts | 2 +- 7 files changed, 7 insertions(+), 4 deletions(-) rename src/preview/elevated-modal/{Anchor => ModalAnchor}/anchor.css (100%) rename src/preview/elevated-modal/{Anchor => ModalAnchor}/branches/Trapped.tsx (100%) rename src/preview/elevated-modal/{Anchor => ModalAnchor}/branches/Untrapped.tsx (100%) rename src/preview/elevated-modal/{Anchor => ModalAnchor}/branches/index.ts (65%) rename src/preview/elevated-modal/{Anchor => ModalAnchor}/func.tsx (83%) create mode 100644 src/preview/elevated-modal/ModalAnchor/index.ts diff --git a/src/preview/elevated-modal/Anchor/anchor.css b/src/preview/elevated-modal/ModalAnchor/anchor.css similarity index 100% rename from src/preview/elevated-modal/Anchor/anchor.css rename to src/preview/elevated-modal/ModalAnchor/anchor.css diff --git a/src/preview/elevated-modal/Anchor/branches/Trapped.tsx b/src/preview/elevated-modal/ModalAnchor/branches/Trapped.tsx similarity index 100% rename from src/preview/elevated-modal/Anchor/branches/Trapped.tsx rename to src/preview/elevated-modal/ModalAnchor/branches/Trapped.tsx diff --git a/src/preview/elevated-modal/Anchor/branches/Untrapped.tsx b/src/preview/elevated-modal/ModalAnchor/branches/Untrapped.tsx similarity index 100% rename from src/preview/elevated-modal/Anchor/branches/Untrapped.tsx rename to src/preview/elevated-modal/ModalAnchor/branches/Untrapped.tsx diff --git a/src/preview/elevated-modal/Anchor/branches/index.ts b/src/preview/elevated-modal/ModalAnchor/branches/index.ts similarity index 65% rename from src/preview/elevated-modal/Anchor/branches/index.ts rename to src/preview/elevated-modal/ModalAnchor/branches/index.ts index 5f4fbae..c27768e 100644 --- a/src/preview/elevated-modal/Anchor/branches/index.ts +++ b/src/preview/elevated-modal/ModalAnchor/branches/index.ts @@ -1,2 +1,2 @@ -export { default as UntrappedBranch } from "@previewelevated-modal/Anchor/branches/Untrapped"; -export { default as TrappedBranch } from "@previewelevated-modal/Anchor/branches/Trapped"; +export { default as UntrappedBranch } from "@previewelevated-modal/ModalAnchor/branches/Untrapped"; +export { default as TrappedBranch } from "@previewelevated-modal/ModalAnchor/branches/Trapped"; diff --git a/src/preview/elevated-modal/Anchor/func.tsx b/src/preview/elevated-modal/ModalAnchor/func.tsx similarity index 83% rename from src/preview/elevated-modal/Anchor/func.tsx rename to src/preview/elevated-modal/ModalAnchor/func.tsx index e4ca111..bca9ec4 100644 --- a/src/preview/elevated-modal/Anchor/func.tsx +++ b/src/preview/elevated-modal/ModalAnchor/func.tsx @@ -3,7 +3,7 @@ import "./anchor.css"; import { TrappedBranch, UntrappedBranch, -} from "@previewelevated-modal/Anchor/branches"; +} from "@previewelevated-modal/ModalAnchor/branches"; type TProps = { disableTrapping?: boolean; diff --git a/src/preview/elevated-modal/ModalAnchor/index.ts b/src/preview/elevated-modal/ModalAnchor/index.ts new file mode 100644 index 0000000..4c61596 --- /dev/null +++ b/src/preview/elevated-modal/ModalAnchor/index.ts @@ -0,0 +1,3 @@ +import ModalAnchor from "@previewelevated-modal/ModalAnchor/func"; + +export default ModalAnchor; diff --git a/src/preview/elevated-modal/index.ts b/src/preview/elevated-modal/index.ts index f910de4..a03e292 100644 --- a/src/preview/elevated-modal/index.ts +++ b/src/preview/elevated-modal/index.ts @@ -3,7 +3,7 @@ import { ModalContextProvider, } from "@preview/elevated-modal/provider"; -import ModalAnchor from "@preview/elevated-modal/anchor"; +import ModalAnchor from "@preview/elevated-modal/ModalAnchor"; import constants from "@preview/elevated-modal/constants"; From 1381818a4d86fbbb68014846195c00a5920333b0 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:49:05 +0000 Subject: [PATCH 11/14] fix for preview tmp --- .../elevated-modal/ModalAnchor/branches/Trapped.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/preview/elevated-modal/ModalAnchor/branches/Trapped.tsx b/src/preview/elevated-modal/ModalAnchor/branches/Trapped.tsx index 46d7fdd..fbb5134 100644 --- a/src/preview/elevated-modal/ModalAnchor/branches/Trapped.tsx +++ b/src/preview/elevated-modal/ModalAnchor/branches/Trapped.tsx @@ -1,3 +1,5 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +/* eslint-disable consistent-return */ import { useEffect, useRef } from "react"; import { useModalContext } from "@preview/elevated-modal/provider"; import constants from "@preview/elevated-modal/constants"; @@ -23,11 +25,9 @@ export default function Trapped() { lastElement.focus(); e.preventDefault(); } - } else { - if (document.activeElement === lastElement) { - firstElement.focus(); - e.preventDefault(); - } + } else if (document.activeElement === lastElement) { + firstElement.focus(); + e.preventDefault(); } }; From 1118fd7f6e845519a42dfe2c74262e16c667a9fb Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 18:50:25 +0000 Subject: [PATCH 12/14] rm exp s --- src/index.ts | 8 +------- src/preview/index.ts | 2 -- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index 55ec370..e5c2b27 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,4 @@ export { EThemeSpacing, EThemeIconSizes, EThemeDimensions } from "@theme"; export { useFuiProviderNode } from "@hooks"; export { Flex, ButtonGroup } from "@components"; -export { - useModalContext, - ModalAnchor, - ModalContextProvider, - EXP_StrippedDialogSurface, - ElevatedModalConstants, -} from "@preview"; +export { useModalContext, ModalAnchor, ModalContextProvider } from "@preview"; diff --git a/src/preview/index.ts b/src/preview/index.ts index 9b84c83..1c5dad6 100644 --- a/src/preview/index.ts +++ b/src/preview/index.ts @@ -2,6 +2,4 @@ export { useModalContext, ModalAnchor, ModalContextProvider, - EXP_StrippedDialogSurface, - constants as ElevatedModalConstants, } from "@preview/elevated-modal"; From 14c1c0b3dbebac599868590de5b39e5860fccdda Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 19:12:15 +0000 Subject: [PATCH 13/14] added docs --- package.json | 2 - .../StrippedDialogSurface/func.tsx | 37 ++++---- .../StrippedDialogSurface/index.ts | 2 +- .../elevated-modal/stories/example.tsx | 2 +- src/preview/elevated-modal/stories/root.tsx | 85 +++++++++++++++++++ 5 files changed, 104 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 86ab120..6b8346f 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "peerDependencies": { "@fluentui/react-components": "^9", "@fluentui/react-icons": "^2", - "@fluentui/react-motion-components-preview": "^0.4.1", "@griffel/react": "^1.5", "react": "^18 || ^17", "react-dom": "^18 || ^17" @@ -23,7 +22,6 @@ "@babel/preset-typescript": "^7.25.9", "@fluentui/react-components": "^9.55.0", "@fluentui/react-icons": "^2.0.261", - "@fluentui/react-motion-components-preview": "^0.4.1", "@griffel/react": "^1.5.25", "@griffel/tag-processor": "^1.0.7", "@griffel/vite-plugin": "^0.1.7", diff --git a/src/preview/elevated-modal/StrippedDialogSurface/func.tsx b/src/preview/elevated-modal/StrippedDialogSurface/func.tsx index 5610aa9..816e5d0 100644 --- a/src/preview/elevated-modal/StrippedDialogSurface/func.tsx +++ b/src/preview/elevated-modal/StrippedDialogSurface/func.tsx @@ -1,18 +1,17 @@ import type { JSX } from "react"; import { mergeClasses } from "@fluentui/react-components"; -import { Fade } from "@fluentui/react-motion-components-preview"; import { Flex } from "@components/layout"; -import useStrippedDialogSurfaceClasses from "./styles"; +import useStrippedDialogSurfaceClasses from "@previewelevated-modal/StrippedDialogSurface/styles"; type TProps = { enhancementOptions?: { rootSurfaceStyles?: boolean; defaultDimensions?: boolean; - parentCenteringContainer?: boolean; - fadeInFadeOutEffect?: boolean; + parentCentering?: boolean; + parentDimming?: boolean; }; children: JSX.Element; className?: string; @@ -22,8 +21,8 @@ export default function StrippedDialogSurface({ enhancementOptions = { rootSurfaceStyles: true, defaultDimensions: true, - parentCenteringContainer: true, - fadeInFadeOutEffect: true, + parentCentering: true, + parentDimming: true, }, children, className = undefined, @@ -45,20 +44,18 @@ export default function StrippedDialogSurface({ {children}
); - return enhancementOptions.parentCenteringContainer ? ( - -
- - {bareSurface} - -
-
+ return enhancementOptions.parentCentering ? ( + + {bareSurface} + ) : ( bareSurface ); diff --git a/src/preview/elevated-modal/StrippedDialogSurface/index.ts b/src/preview/elevated-modal/StrippedDialogSurface/index.ts index 701a066..79777fc 100644 --- a/src/preview/elevated-modal/StrippedDialogSurface/index.ts +++ b/src/preview/elevated-modal/StrippedDialogSurface/index.ts @@ -1,3 +1,3 @@ -import StrippedDialogSurface from "@previewelevated-modal/StrippedDialogSurface/func"; +import StrippedDialogSurface from "@preview/elevated-modal/StrippedDialogSurface/func"; export default StrippedDialogSurface; diff --git a/src/preview/elevated-modal/stories/example.tsx b/src/preview/elevated-modal/stories/example.tsx index 4382fe0..6dcd54b 100644 --- a/src/preview/elevated-modal/stories/example.tsx +++ b/src/preview/elevated-modal/stories/example.tsx @@ -9,7 +9,7 @@ import { Button, } from "@fluentui/react-components"; -import StrippedDialogSurface from "@previewelevated-modal/StrippedDialogSurface"; +import StrippedDialogSurface from "@preview/elevated-modal/StrippedDialogSurface"; type TProps = { someString: string; diff --git a/src/preview/elevated-modal/stories/root.tsx b/src/preview/elevated-modal/stories/root.tsx index b552dc2..49a359f 100644 --- a/src/preview/elevated-modal/stories/root.tsx +++ b/src/preview/elevated-modal/stories/root.tsx @@ -1,6 +1,91 @@ import { ModalContextProvider, ModalAnchor } from "@preview/elevated-modal"; import App from "@previewelevated-modal/stories"; +/** + * ### NOTE: This is currently highly experimental, and thus in `preview`, its not recommended to be used + * + * @description + * - in drag and drop enviroments, state is seldomly preserved between re-ordering + * - this makes using modals a bit tricky which rely on state transitions via portals + * - because the state is kept at the caller level, the modal will be unmounted and re-mounted, thus losing state + * - to solve this, we will use a similiar approach to toasting libraries, which instead of using portals, use a single anchor point to which a JSX element is dispatched (via Context API) + * - this way, no matter what happens to the caller state, the modal will always be mounted to the anchor point, preserving state etc. + * + * @accessibility apart from focus trapping, not really accessible + * + * @example + * + * ```jsx + * // setting up the root configuration + * import { ModalContextProvider, ModalAnchor } from "fluentui-helpers"; + * + * export default function Root() { + * return ( + * + * + * // if there are issues with trapping focus, use disableTrapping flag on ModalAnchor + * + * + * ); + * + * + * // the ModalAnchor itself provides a shell container for the actual modal, it has 100% width and height of the viewport + * // an example could be: + * + * + * import { + * DialogTrigger, + * DialogTitle, + * DialogBody, + * DialogActions, + * DialogContent, + * Button, + * } from "@fluentui/react-components"; + * + * // this one is not available, the gist is, is that the DialogSurface cannot be used directly, issues with the way the container spreads + * import StrippedDialogSurface from "@preview/elevated-modal/StrippedDialogSurface"; + * + * type TProps = { + * someString: string; + * someNumber: number; + * someObject: { + * someKey: string; + * }; + * onAbort: () => void; + * }; + * + * export default function ExampleModal({ + * someString, + * someNumber, + * someObject, + * onAbort, + * }: TProps) { + * return ( + * + * + * Dialog title -- {someString} + * + * Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam + * exercitationem cumque repellendus eaque est dolor eius expedita nulla + * ullam? Tenetur reprehenderit aut voluptatum impedit voluptates in + * natus iure cumque eaque? Some number: {someNumber} and some object + * key: {someObject.someKey} + * + * + * + * + * + * + * + * + * + * ); + * } + * ``` + * + */ export default function Root() { return ( From 8af83d5046c3a83ceaa3c42f05535277bff90b49 Mon Sep 17 00:00:00 2001 From: Samuil Berenzon Date: Fri, 3 Jan 2025 19:14:19 +0000 Subject: [PATCH 14/14] inc version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b8346f..1398719 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fluentui-helpers", - "version": "0.2.2", + "version": "0.3.2", "description": "Helper library for microsofts fluentui react library", "main": "dist/index.js", "module": "dist/index.mjs",