Skip to content

Commit

Permalink
dev: Refactored dialogs reducer to be more scalable
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-crowell committed Jun 29, 2024
1 parent f617c8b commit 1677ce5
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 100 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"react-aria": "nightly",
"react-aria-components": "nightly",
"react-dom": "19.0.0-rc-8971381549-20240625",
"reselect": "^5.1.1",
"storybook": "^8.2.0-alpha.10",
"tailwind-merge": "^2.3.0",
"tailwindcss": "^3.4.3",
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Button as AriaButton, Link as AriaLink } from 'react-aria-components';
import { fillStyles, emptyStyles, cn, interactiveStyles } from '@do-ob/ui/utility';
import { ButtonProps, ButtonVariant, ButtonSize } from './Button.types';
import { Polymorphic } from '@do-ob/ui/types';
import { useDialogControl } from '@do-ob/ui/hooks';

/**
* Define tailwind classes for the variants.
Expand Down Expand Up @@ -59,9 +60,12 @@ export function Button<
endContent = null,
iconify = false,
href,
dialog,
...props
}: ButtonProps & Polymorphic<Element>) {

const dialogControlProps = useDialogControl(dialog);

const Tag = as ?? (href ? AriaLink : AriaButton);

const isExternal = href && (href.startsWith('http://') || href.startsWith('https://'));
Expand Down Expand Up @@ -101,6 +105,7 @@ export function Button<
className
)}
{...linkProps}
{...dialogControlProps}
{...props}
>
{startContent && <span className="mr-2">{startContent}</span>}
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/Button/Button.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export interface ButtonProps {
className?: string;
iconify?: boolean;
href?: string;
dialog?: string;
}
5 changes: 1 addition & 4 deletions packages/ui/src/components/Drawer/Drawer.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { Meta, StoryObj } from '@storybook/react';

import { Drawer } from './Drawer';
import { Button } from '@do-ob/ui/components';
import { useDrawerControl } from '@do-ob/ui/hooks';

const meta = {
component: Drawer,
Expand All @@ -15,10 +14,8 @@ type Story = StoryObj<typeof meta>;
export const Controlled: Story = {
render: function Render(args) {

const controllerProps = useDrawerControl('example');

return (<>
<Button {...controllerProps}>Click me</Button>
<Button dialog="example">Click me</Button>
<Drawer {...args} />
</>);
},
Expand Down
17 changes: 8 additions & 9 deletions packages/ui/src/components/Drawer/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use client';

import { ModalOverlay, Modal, Dialog } from 'react-aria-components';
import { ModalOverlay, Modal, Dialog, Heading } from 'react-aria-components';
// import { cn } from '@do-ob/ui/utility';
import type { DrawerProps } from './Drawer.types';
import { nop } from '@do-ob/core';
import { dialogActions } from '@do-ob/ui/reducer';
import { useDebounce, useDispatch, useSelector } from '@do-ob/ui/hooks';
import { useEffect } from 'react';
import { useDebounce } from '@do-ob/ui/hooks';
import { use, useEffect } from 'react';
import { DialogContext, DialogDispatchContext } from '@do-ob/ui/context';

export function Drawer({
name,
Expand All @@ -19,9 +20,9 @@ export function Drawer({
// ...props
}: DrawerProps & React.HTMLAttributes<HTMLElement>) {

const id = `drawer/${name}`;
const drawer = useSelector((state) => state.dialog.items[id]) ?? { id, open: false };
const dispatch = useDispatch();
const id = name;
const drawer = use(DialogContext).items[id] ?? { id, open: false };
const dispatch = use(DialogDispatchContext);
const isOpen = useDebounce(!!drawer.open, 300);

const handleOpenChange = (next: boolean) => {
Expand All @@ -37,13 +38,10 @@ export function Drawer({
};

useEffect(() => {

dispatch(dialogActions.register(id));

return () => {
dispatch(dialogActions.unregister(id));
};

}, [ dispatch, id ]);

return (
Expand All @@ -64,6 +62,7 @@ export function Drawer({
}}
>
<Dialog>
<Heading slot="title">{name}</Heading>
{children}
</Dialog>
</Modal>
Expand Down
16 changes: 2 additions & 14 deletions packages/ui/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import React from 'react';
import { ThemeMode } from '@do-ob/ui/types';
import { nop } from '@do-ob/core';
import { createContext } from 'react';
import type { Action, State } from './reducer';
import { initialState } from './reducer';

export * from './context/DialogsContext';

/**
* Context properties for the do-ob ui provider
Expand Down Expand Up @@ -38,16 +38,6 @@ export interface DoobUiContextProps {
* Toggle the theme mode.
*/
modeToggle?: () => void;

/**
* The user interface (ui) state.
*/
state: State;

/**
* The user interface (ui) dispatch.
*/
dispatch: React.Dispatch<Action>;
}

/**
Expand All @@ -59,8 +49,6 @@ export const doobUiContextDefaultProps: DoobUiContextProps = {
pathname: '',
mode: 'light',
modeToggle: nop,
state: initialState,
dispatch: nop
};

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/ui/src/context/DialogsContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Dispatch, createContext } from 'react';
import { reducer as dialogReducer } from '../reducers/dialog.reducer';
import { DialogAction } from '../reducers/dialog.actions';
import { nop } from '@do-ob/core';

export const DialogContext = createContext(dialogReducer());

export const DialogDispatchContext = createContext<Dispatch<DialogAction>>(nop);
4 changes: 1 addition & 3 deletions packages/ui/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ export * from './hooks/useTypewriter';
export * from './hooks/useOverflow';
export * from './hooks/useDebounce';
export * from './hooks/usePathname';
export * from './hooks/useSelector';
export * from './hooks/useDispatch';
export * from './hooks/useDrawerControl';
export * from './hooks/useDialogControl';
15 changes: 15 additions & 0 deletions packages/ui/src/hooks/useDialogControl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { dialogActions } from '@do-ob/ui/reducer';
import { use, useCallback } from 'react';
import { DialogDispatchContext } from '@do-ob/ui/context';

export function useDialogControl(name: string = '') {
const dispatch = use(DialogDispatchContext);

const onPress = useCallback(() => {
dispatch(dialogActions.toggle(name));
}, [ dispatch, name ]);

return {
onPress,
};
};
7 changes: 0 additions & 7 deletions packages/ui/src/hooks/useDispatch.ts

This file was deleted.

26 changes: 0 additions & 26 deletions packages/ui/src/hooks/useDrawerControl.ts

This file was deleted.

8 changes: 0 additions & 8 deletions packages/ui/src/hooks/useSelector.ts

This file was deleted.

20 changes: 14 additions & 6 deletions packages/ui/src/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@

import React from 'react';
import { RouterProvider } from 'react-aria-components';
import { DoobUiContext, DoobUiContextProps, doobUiContextDefaultProps } from '@do-ob/ui/context';
import {
DoobUiContext,
DoobUiContextProps,
doobUiContextDefaultProps,
DialogContext,
DialogDispatchContext,
} from '@do-ob/ui/context';
import { useMode, usePathname } from '@do-ob/ui/hooks';
import { reducer, initialState } from '@do-ob/ui/reducer';
import { dialogReducer } from '@do-ob/ui/reducer';

export interface DoobUiProviderProps {
/**
Expand Down Expand Up @@ -43,7 +49,7 @@ export function DoobUiProvider({
...props
}: React.PropsWithChildren<DoobUiProviderProps>) {

const [ state, dispatch ] = React.useReducer(reducer, initialState);
const [ dialogState, dialogDispatch ] = React.useReducer(dialogReducer, dialogReducer());

const pathname = usePathname(pathnameProp);
const { mode, modeToggle } = useMode(props.mode);
Expand All @@ -53,13 +59,15 @@ export function DoobUiProvider({
<DoobUiContext.Provider value={{
...doobUiContextDefaultProps,
...props,
state,
dispatch,
pathname,
mode,
modeToggle
}}>
{children}
<DialogContext.Provider value={dialogState}>
<DialogDispatchContext.Provider value={dialogDispatch}>
{children}
</DialogDispatchContext.Provider>
</DialogContext.Provider>
</DoobUiContext.Provider>
</RouterProvider>
);
Expand Down
25 changes: 2 additions & 23 deletions packages/ui/src/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,3 @@
import { reducer as dialogReducer } from './reducers/dialog.reducer';
export { reducer as dialogReducer } from './reducers/dialog.reducer';
export * as dialogActions from './reducers/dialog.actions';
import type { DialogState } from './reducers/dialog.reducer';
import type { DialogAction } from './reducers/dialog.actions';

export interface State {
dialog: DialogState;
}

export type Action = DialogAction;

export const initialState: State = {
dialog: dialogReducer()
};

export function reducer(state: State = initialState, action: unknown = {}) {

console.log({ action });

return {
...state,
dialog: dialogReducer(state.dialog, action as DialogAction),
};
}
export type * from './reducers/dialog.reducer';
17 changes: 17 additions & 0 deletions packages/ui/src/reducers/dialog.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export type DialogAction = {
payload: {
id: string;
}
} | {
type: 'dialog/toggle',
payload: {
id: string;
}
} | {
type: 'dialog/open',
payload: {
Expand Down Expand Up @@ -44,6 +49,18 @@ export function unregister(id: string): DialogAction {
};
}

/**
* Toggles a dialog between open and closed.
*/
export function toggle(id: string): DialogAction {
return {
type: 'dialog/toggle',
payload: {
id,
}
};
}

/**
* Opens a dialog.
*/
Expand Down
23 changes: 23 additions & 0 deletions packages/ui/src/reducers/dialog.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export function reducer(
}
};
case 'dialog/unregister':
if(!state.items[payload.id]) {
return state;
}
return {
...state,
items: Object.values(state.items).reduce((acc, dialog) => {
Expand All @@ -44,7 +47,24 @@ export function reducer(
return acc;
}, {} as DialogState['items'])
};
case 'dialog/toggle':
if(!state.items[payload.id]) {
return state;
}
return {
...state,
items: {
...state.items,
[payload.id]: {
...state.items[payload.id],
open: !state.items[payload.id].open,
}
}
};
case 'dialog/open':
if(!state.items[payload.id]) {
return state;
}
return {
...state,
items: {
Expand All @@ -56,6 +76,9 @@ export function reducer(
}
};
case 'dialog/close':
if(!state.items[payload.id]) {
return state;
}
return {
...state,
items: {
Expand Down
Loading

0 comments on commit 1677ce5

Please sign in to comment.