Skip to content

Commit

Permalink
feat: added DynamicZone, related types and utilities
Browse files Browse the repository at this point in the history
fix: updated props/types of ActionList for more use-cases
  • Loading branch information
QuentinLeCaignec committed Sep 5, 2024
1 parent 69a0aba commit cd51f30
Show file tree
Hide file tree
Showing 18 changed files with 1,053 additions and 18 deletions.
1 change: 1 addition & 0 deletions packages/haring-react-shared/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type {
IThemeOverride,
IThemes,
IFilter,
IOmitRespectIndexSignature,
} from './types';
// type exports
export { mainTheme, primaryTheme, secondaryTheme, themes } from './theme';
1 change: 1 addition & 0 deletions packages/haring-react-shared/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './options';
export * from './theme';
export * from './filters';
export * from './items';
export * from './utility';
3 changes: 3 additions & 0 deletions packages/haring-react-shared/src/types/utility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type IOmitRespectIndexSignature<T, K extends PropertyKey> = {
[P in keyof T as Exclude<P, K>]: T[P];
};
4 changes: 3 additions & 1 deletion packages/haring-react/src/Components/ActionBar/ActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ export function ActionBar<Data extends Record<string, unknown>>(
`${selectedElements} file(s) selected`,
...actionRowOverflowProps
} = props;
const numberOfSelectedElements = selectedElements.length;
const numberOfSelectedElements = Array.isArray(selectedElements)
? selectedElements.length
: [selectedElements].length;

return (
<div className={`${classes.actionBar} actionBarRef`}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IActionListAction } from './ActionList';
import type { IThumbnail } from '../../types';
import type { Meta, StoryObj } from '@storybook/react';

import { ActionList as Cmp } from './ActionList';
Expand All @@ -16,19 +16,17 @@ const meta = {
type: { name: 'number' },
},
},
component: Cmp,
component: Cmp<IThumbnail>,
tags: ['autodocs'],
title: '3-custom/Components/ActionList',
} satisfies Meta<typeof Cmp>;
} satisfies Meta<typeof Cmp<IThumbnail>>;

export default meta;
type IStory = StoryObj<typeof meta>;

export const ActionList: IStory = {
args: {
actions: actionRowOverflowActionsMock as IActionListAction<
Record<string, unknown>
>[],
actions: actionRowOverflowActionsMock,
maxVisibleActions: 2,
selectedElements: actionRowOverflowSelectedMock,
},
Expand Down
20 changes: 10 additions & 10 deletions packages/haring-react/src/Components/ActionList/ActionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ const defaultTooltipProps = {
withArrow: true,
};

export type IActionListAction<Data extends Record<string, unknown>> = IAction<
Data[]
>;
export type IActionListAction<Data extends Record<string, unknown>> =
| IAction<Data[]>
| IAction<Data>;

export interface IActionListProps<Data extends Record<string, unknown>>
extends GroupProps {
Expand All @@ -41,7 +41,7 @@ export interface IActionListProps<Data extends Record<string, unknown>>
maxVisibleActions?: number;
modalProps?: Omit<ModalProps, 'title'>;
overflowMenuLabel?: string;
selectedElements: Data[];
selectedElements: Data | Data[];
}

export function ActionList<Data extends Record<string, unknown>>(
Expand Down Expand Up @@ -72,7 +72,7 @@ export function ActionList<Data extends Record<string, unknown>>(
children: action.confirmModalProps?.children,
confirmColor: action.confirmModalProps?.confirmColor,
confirmLabel: action.confirmModalProps?.confirmLabel,
onConfirm: () => action.onAction?.(selectedElements),
onConfirm: () => action.onAction?.(selectedElements as Data & Data[]),
title: action.confirmModalProps?.title,
});
}
Expand All @@ -85,7 +85,7 @@ export function ActionList<Data extends Record<string, unknown>>(
clearConfirmAction();
}

function handleModalButton(onAction?: (item: Data[]) => void): void {
function handleModalButton(onAction?: (item: Data | Data[]) => void): void {
onAction?.(selectedElements);
handleClose();
}
Expand All @@ -94,7 +94,7 @@ export function ActionList<Data extends Record<string, unknown>>(
if (action.confirmation) {
setModal(action);
} else {
action.onAction?.(selectedElements);
action.onAction?.(selectedElements as Data & Data[]);
}
}

Expand All @@ -103,7 +103,7 @@ export function ActionList<Data extends Record<string, unknown>>(
return '';
}
return typeof action.label === 'function'
? action.label(selectedElements)
? action.label(selectedElements as Data & Data[])
: action.label;
}

Expand All @@ -112,7 +112,7 @@ export function ActionList<Data extends Record<string, unknown>>(
return null;
}
return typeof action.icon === 'function'
? action.icon(selectedElements)
? action.icon(selectedElements as Data & Data[])
: action.icon;
}

Expand All @@ -123,7 +123,7 @@ export function ActionList<Data extends Record<string, unknown>>(
return undefined;
}
return typeof action.componentProps === 'function'
? action.componentProps(selectedElements)
? action.componentProps(selectedElements as Data & Data[])
: action.componentProps;
}

Expand Down
87 changes: 87 additions & 0 deletions packages/haring-react/src/Form/DynamicZone/DynamicZone.mock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type { IDynamicZoneBlockReference } from './DynamicZoneBlock/DynamicZoneBlock';
import type { IBaseBlock, IBaseBlockButton } from '../../types';
import type { IAction } from '@smile/haring-react-shared';

import {
Alien,
ArrowDown,
ArrowUp,
Leaf,
Trash,
TreasureChest,
} from '@phosphor-icons/react';
import { action } from '@storybook/addon-actions';

const dynamicZoneBlockActionsMock: IAction<IDynamicZoneBlockReference>[] = [
{
color: 'white',
icon: <ArrowUp size={16} />,
id: 'move-up',
label: 'Move Up',
onAction: action('Move block up'),
},
{
color: 'white',
icon: <ArrowDown size={16} />,
id: 'move-down',
label: 'Move Down',
onAction: action('Move block down'),
},
{
color: 'white',
icon: <Trash size={16} />,
id: 'delete',
label: 'Delete',
onAction: action('Delete block'),
},
];

export const dynamicZoneBlocks: IBaseBlock[] = [
{
blockActions: dynamicZoneBlockActionsMock,
blockHeader: (
<>
<Alien />
First
</>
),
blockType: 'default',
id: '1',
opened: false,
value: 'initial',
},
{
blockActions: dynamicZoneBlockActionsMock,
blockFooter: 'footer',
blockHeader: (
<>
<Leaf />
Second
</>
),
blockType: 'default',
id: '2',
opened: true,
value: 'initial',
},
{
blockActions: dynamicZoneBlockActionsMock,
blockFooter: 'footer',
blockHeader: (
<>
<TreasureChest />
Third
</>
),
blockType: 'default',
id: '3',
opened: false,
value: 'initial',
},
];

export const dynamicZoneButtons: IBaseBlockButton[] = [
{ blockType: 'default', label: 'Default', leftSection: <Alien /> },
{ blockType: 'other', label: 'Other', leftSection: <Leaf /> },
{ blockType: 'stuff', label: 'Stuff', leftSection: <TreasureChest /> },
];
12 changes: 12 additions & 0 deletions packages/haring-react/src/Form/DynamicZone/DynamicZone.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.buttonsContainer {
border-radius: 0.5rem;
border: 1px dashed black;
}

.buttonsLabel {
&:empty {
display: none;
}

margin-bottom: 10px;
}
35 changes: 35 additions & 0 deletions packages/haring-react/src/Form/DynamicZone/DynamicZone.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Meta, StoryObj } from '@storybook/react';

import { action } from '@storybook/addon-actions';

import { DynamicZone as Cmp } from './DynamicZone';
import { dynamicZoneBlocks, dynamicZoneButtons } from './DynamicZone.mock';

const meta = {
component: Cmp,
tags: ['autodocs'],
title: '3-custom/Form/DynamicZone',
} satisfies Meta<typeof Cmp>;

export default meta;
type IStory = StoryObj<typeof meta>;

export const DynamicZone: IStory = {
args: {
blockOptions: dynamicZoneButtons,
blocks: dynamicZoneBlocks,
buttonsText: 'Ajouter un block',
internalBlockCardProps: {
headerCardSectionProps: {
bg: 'cadetblue',
c: 'white',
},
toggleComponentProps: {
actionIconProps: { color: 'white', variant: 'subtle' },
},
},
onAppendBlock: action('onAppendBlock, id'),
onRenderBlockContent: (_b, index) => <input key={index} />,
onToggleBlock: action('onToggleBlock'),
},
};
27 changes: 27 additions & 0 deletions packages/haring-react/src/Form/DynamicZone/DynamicZone.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { IBaseBlock } from '../../types';
import type { ReactElement } from 'react';

import { renderWithProviders } from '@smile/haring-react-shared/test-utils';
import { action } from '@storybook/addon-actions';
import { expect } from '@storybook/jest';

import { DynamicZone } from './DynamicZone';
import { dynamicZoneBlocks, dynamicZoneButtons } from './DynamicZone.mock';

describe('DynamicZone', () => {
it('matches snapshot', () => {
const onRender = (_b: IBaseBlock, index: number): ReactElement => (
<input key={index} />
);
const { container } = renderWithProviders(
<DynamicZone
blockOptions={dynamicZoneButtons}
blocks={dynamicZoneBlocks}
onAppendBlock={action('onAppendBlock, id')}
onRenderBlockContent={onRender}
onToggleBlock={action('onToggleBlock')}
/>,
);
expect(container).toMatchSnapshot();
});
});
Loading

0 comments on commit cd51f30

Please sign in to comment.