Skip to content

Commit

Permalink
feat: wip progress on FormDynamicZone
Browse files Browse the repository at this point in the history
  • Loading branch information
QuentinLeCaignec committed Sep 23, 2024
1 parent 674fe70 commit 92f6952
Show file tree
Hide file tree
Showing 15 changed files with 396 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import type {
ActionIconProps,
ButtonProps,
FloatingPosition,
GroupProps,
Expand Down Expand Up @@ -34,7 +35,8 @@ export type IActionListAction<Data extends Record<string, unknown>> =

export interface IActionListProps<Data extends Record<string, unknown>>
extends GroupProps {
actionButtonProps?: ButtonProps;
actionButtonDefaultProps?: ButtonProps;
actionIconDefaultProps?: ActionIconProps;
actionTooltipProps?: TooltipProps;
actions: IActionListAction<Data>[];
isCompactStyle?: boolean;
Expand All @@ -48,7 +50,8 @@ export function ActionList<Data extends Record<string, unknown>>(
props: IActionListProps<Data>,
): ReactNode {
const {
actionButtonProps,
actionButtonDefaultProps,
actionIconDefaultProps,
actionTooltipProps,
actions,
isCompactStyle = false,
Expand Down Expand Up @@ -140,6 +143,7 @@ export function ActionList<Data extends Record<string, unknown>>(
leftSection={getActionIcon(action)}
onClick={() => handleAction(action)}
variant={action.color ? 'filled' : 'default'}
{...actionButtonDefaultProps}
{...getActionComponentProps(action)}
>
{getActionLabel(action)}
Expand All @@ -159,6 +163,7 @@ export function ActionList<Data extends Record<string, unknown>>(
radius={4}
type="button"
variant="subtle"
{...actionIconDefaultProps}
{...getActionComponentProps(action)}
>
{getActionIcon(action)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { IDynamicZoneBlockReference } from './DynamicZoneBlock/DynamicZoneBlock';
import type { IBaseBlockButton, IBaseBlockFull } from '../../types';
import type { IBaseBlockButtonOptions, IBaseBlockFull } from '../../types';
import type { IAction } from '@smile/haring-react-shared';

import {
Expand All @@ -14,21 +14,18 @@ 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',
Expand Down Expand Up @@ -80,7 +77,7 @@ export const dynamicZoneBlocks: IBaseBlockFull[] = [
},
];

export const dynamicZoneButtons: IBaseBlockButton[] = [
export const dynamicZoneButtons: IBaseBlockButtonOptions[] = [
{ blockType: 'default', label: 'Default', leftSection: <Alien /> },
{ blockType: 'other', label: 'Other', leftSection: <Leaf /> },
{ blockType: 'stuff', label: 'Stuff', leftSection: <TreasureChest /> },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,11 @@

margin-bottom: 10px;
}

.button {
&:disabled,
&[data-disabled] {
border-color: var(--mantine-color-gray-4);
background-color: transparent;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,22 @@ export const DynamicZone: IStory = {
blockOptions: dynamicZoneButtons,
blocks: dynamicZoneBlocks,
buttonsText: 'Ajouter un block',
internalBlockCardProps: {
onAppendBlock: action('onAppendBlock, id'),
onRenderBlockContent: (_b, index) => <input key={index} />,
onToggleBlock: action('onToggleBlock'),
},
};

export const CustomInternalProps: IStory = {
args: {
blockOptions: dynamicZoneButtons,
blocks: dynamicZoneBlocks,
internalBlockComponentProps: {
headerActionListProps: {
actionIconDefaultProps: {
color: 'white',
},
},
headerCardSectionProps: {
bg: 'cadetblue',
c: 'white',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IBaseBlockOptions } from '../../types';
import type { IBaseBlockCardOptions } from '../../types';
import type { ReactElement } from 'react';

import { renderWithProviders } from '@smile/haring-react-shared/test-utils';
Expand All @@ -10,9 +10,10 @@ import { dynamicZoneBlocks, dynamicZoneButtons } from './DynamicZone.mock';

describe('DynamicZone', () => {
it('matches snapshot', () => {
const onRender = (_b: IBaseBlockOptions, index: number): ReactElement => (
<input key={index} />
);
const onRender = (
_b: IBaseBlockCardOptions,
index: number,
): ReactElement => <input key={index} />;
const { container } = renderWithProviders(
<DynamicZone
blockOptions={dynamicZoneButtons}
Expand Down
92 changes: 58 additions & 34 deletions packages/haring-react/src/Form/DynamicZone/DynamicZone.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { IDynamicZoneBlockInternalComponentProps } from './DynamicZoneBlock/DynamicZoneBlock';
import type {
IBaseBlockButton,
IBaseBlockButtonOptions,
IBaseBlockFull,
IBaseBlockType,
} from '../../types';
Expand All @@ -13,21 +13,25 @@ import type {
} from '@mantine/core';
import type { ReactElement } from 'react';

import { Button, Container, Group, Stack, Text } from '@mantine/core';
import { Button, Container, Group, Stack, Text, Tooltip } from '@mantine/core';

import classes from './DynamicZone.module.css';
import { DynamicZoneBlock } from './DynamicZoneBlock/DynamicZoneBlock';

export interface IDynamicZoneProps extends ContainerProps {
export interface IDynamicZoneInternalComponentProps {
blockCardProps?: CardProps;
blockOptions: IBaseBlockButton[];
blocks: IBaseBlockFull[];
blocksStackProps?: StackProps;
bottomContainerProps?: ContainerProps;
buttonsGroupProps?: GroupProps;
buttonsText?: string;
buttonsTextProps?: TextProps;
internalBlockCardProps?: IDynamicZoneBlockInternalComponentProps;
}

export interface IDynamicZoneProps extends ContainerProps {
blockOptions: IBaseBlockButtonOptions[];
blocks: IBaseBlockFull[];
buttonsText?: string;
internalBlockComponentProps?: IDynamicZoneBlockInternalComponentProps;
internalComponentProps?: IDynamicZoneInternalComponentProps;
onAppendBlock: (blockType: IBaseBlockType) => void;
onRenderBlockContent: (block: IBaseBlockFull, index: number) => ReactElement;
onToggleBlock: (
Expand All @@ -39,15 +43,11 @@ export interface IDynamicZoneProps extends ContainerProps {

export function DynamicZone(props: IDynamicZoneProps): ReactElement {
const {
blockCardProps,
blockOptions,
blocks,
blocksStackProps,
bottomContainerProps,
buttonsGroupProps,
buttonsText,
buttonsTextProps,
internalBlockCardProps,
internalComponentProps,
internalBlockComponentProps,
onAppendBlock,
onRenderBlockContent,
onToggleBlock,
Expand All @@ -60,15 +60,16 @@ export function DynamicZone(props: IDynamicZoneProps): ReactElement {

return (
<Container fluid p={0} {...rootContainerProps}>
<Stack gap="sm" {...blocksStackProps}>
<Stack gap="sm" {...internalComponentProps?.blocksStackProps}>
{blocks.map((block, index) => (
<DynamicZoneBlock
{...blockCardProps}
{...internalComponentProps?.blockCardProps}
{...block.blockCardProps}
key={block.id}
actions={block.blockActions}
footerChildren={block.blockFooter}
headerChildren={block.blockHeader}
internalComponentProps={internalBlockCardProps}
internalComponentProps={internalBlockComponentProps}
onToggle={(opened) => onToggleBlock(block, index, opened)}
opened={block.opened}
reference={{ arrayLength: blocks.length, id: block.id, index }}
Expand All @@ -82,25 +83,48 @@ export function DynamicZone(props: IDynamicZoneProps): ReactElement {
fluid
mt="lg"
p="sm"
{...bottomContainerProps}
{...internalComponentProps?.bottomContainerProps}
>
<Text className={classes.buttonsLabel} fw="bold" {...buttonsTextProps}>
{buttonsText}
</Text>
<Group {...buttonsGroupProps}>
{blockOptions.map(({ blockType, ...button }) => (
<Button
radius="md"
size="md"
type="button"
variant="default"
{...button}
key={`button-${blockType}`}
onClick={() => onAddBlock(blockType)}
>
{button.label}
</Button>
))}
{Boolean(buttonsText) && (
<Text
className={classes.buttonsLabel}
fw="bold"
{...internalComponentProps?.buttonsTextProps}
>
{buttonsText}
</Text>
)}
<Group {...internalComponentProps?.buttonsGroupProps}>
{blockOptions.map(
({ blockType, label, tooltipLabel, tooltipProps, ...button }) => (
<Tooltip
key={`button-${blockType}`}
disabled={
tooltipLabel === '' ||
tooltipLabel === undefined ||
(typeof tooltipLabel === 'function' &&
tooltipLabel(button) === '')
}
label={
typeof tooltipLabel === 'function' && tooltipLabel(button)
}
{...tooltipProps}
>
<Button
className={classes.button}
radius="md"
size="md"
type="button"
variant="default"
{...button}
onClick={() => onAddBlock(blockType)}
>
{(typeof label === 'function' && label(button)) ||
(typeof label === 'string' && label)}
</Button>
</Tooltip>
),
)}
</Group>
</Container>
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ export interface IDynamicZoneBlockInternalComponentProps {
contentCollapseProps?: CollapseProps;
contentContainerProps?: ContainerProps;
footerCardSectionProps?: CardSectionProps;
headerActionListProps?: IActionListProps<IDynamicZoneBlockReference>;
headerActionListProps?: Omit<
IActionListProps<IDynamicZoneBlockReference>,
'actions' | 'isCompactStyle' | 'selectedElements'
>;
headerCardSectionProps?: CardSectionProps;
headerGroupProps?: GroupProps;
toggleComponentProps?: IDynamicZoneBlockToggleProps;
Expand Down
Loading

0 comments on commit 92f6952

Please sign in to comment.