Skip to content

Commit

Permalink
Add space block factory (#2005)
Browse files Browse the repository at this point in the history
Add `createSpaceBlock` factory to replace `SpaceBlock`.

---------

Co-authored-by: Johannes Obermair <48853629+johnnyomair@users.noreply.github.com>
  • Loading branch information
jomunker and johnnyomair authored Apr 30, 2024
1 parent d6ca50a commit 90c6f19
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 10 deletions.
8 changes: 8 additions & 0 deletions .changeset/tall-pants-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@comet/blocks-admin": minor
"@comet/blocks-api": minor
---

Deprecate `SpaceBlock`

It will be replaced by the `createSpaceBlock` factory since it had no real use case.
32 changes: 32 additions & 0 deletions .changeset/warm-chicken-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
"@comet/blocks-admin": minor
"@comet/blocks-api": minor
---

Add `createSpaceBlock` factory

Allows selecting a spacing value out of a list of provided options.

**Example**

API

```tsx
enum Spacing {
d150 = "d150",
d200 = "d200",
}

export const SpaceBlock = createSpaceBlock({ spacing: Spacing }, "DemoSpace");
```

Admin

```tsx
const options = [
{ value: "d150", label: "Dynamic 150" },
{ value: "d200", label: "Dynamic 200" },
];

export const SpaceBlock = createSpaceBlock<string>({ defaultValue: options[0].value, options });
```
18 changes: 18 additions & 0 deletions demo/admin/src/common/blocks/SpaceBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createSpaceBlock } from "@comet/blocks-admin";
import * as React from "react";
import { FormattedMessage } from "react-intl";

const options: { value: string; label: React.ReactNode }[] = [
{ value: "d150", label: <FormattedMessage id="spacing.d150" defaultMessage="Dynamic 150" /> },
{ value: "d200", label: <FormattedMessage id="spacing.d200" defaultMessage="Dynamic 200" /> },
{ value: "d250", label: <FormattedMessage id="spacing.d250" defaultMessage="Dynamic 250" /> },
{ value: "d300", label: <FormattedMessage id="spacing.d300" defaultMessage="Dynamic 300" /> },
{ value: "d350", label: <FormattedMessage id="spacing.d350" defaultMessage="Dynamic 350" /> },
{ value: "d400", label: <FormattedMessage id="spacing.d400" defaultMessage="Dynamic 400" /> },
{ value: "d450", label: <FormattedMessage id="spacing.d450" defaultMessage="Dynamic 450" /> },
{ value: "d500", label: <FormattedMessage id="spacing.d500" defaultMessage="Dynamic 500" /> },
{ value: "d550", label: <FormattedMessage id="spacing.d550" defaultMessage="Dynamic 550" /> },
{ value: "d600", label: <FormattedMessage id="spacing.d600" defaultMessage="Dynamic 600" /> },
];

export const SpaceBlock = createSpaceBlock<string>({ defaultValue: options[0].value, options });
3 changes: 2 additions & 1 deletion demo/admin/src/pages/PageContentBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { createBlocksBlock, SpaceBlock, YouTubeVideoBlock } from "@comet/blocks-admin";
import { createBlocksBlock, YouTubeVideoBlock } from "@comet/blocks-admin";
import { AnchorBlock, DamImageBlock, DamVideoBlock } from "@comet/cms-admin";
import { HeadlineBlock } from "@src/common/blocks/HeadlineBlock";
import { LinkListBlock } from "@src/common/blocks/LinkListBlock";
import { RichTextBlock } from "@src/common/blocks/RichTextBlock";
import { SpaceBlock } from "@src/common/blocks/SpaceBlock";
import { TextImageBlock } from "@src/common/blocks/TextImageBlock";
import { userGroupAdditionalItemFields } from "@src/userGroups/userGroupAdditionalItemFields";
import { UserGroupChip } from "@src/userGroups/UserGroupChip";
Expand Down
45 changes: 43 additions & 2 deletions demo/api/block-meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,47 @@
}
]
},
{
"name": "DemoSpace",
"fields": [
{
"name": "spacing",
"kind": "Enum",
"enum": [
"d150",
"d200",
"d250",
"d300",
"d350",
"d400",
"d450",
"d500",
"d550",
"d600"
],
"nullable": false
}
],
"inputFields": [
{
"name": "spacing",
"kind": "Enum",
"enum": [
"d150",
"d200",
"d250",
"d300",
"d350",
"d400",
"d450",
"d500",
"d550",
"d600"
],
"nullable": false
}
]
},
{
"name": "DemoTextLink",
"fields": [
Expand Down Expand Up @@ -1070,7 +1111,7 @@
"name": "props",
"kind": "OneOfBlocks",
"blocks": {
"space": "Space",
"space": "DemoSpace",
"richtext": "RichText",
"headline": "Headline",
"image": "DamImage",
Expand Down Expand Up @@ -1128,7 +1169,7 @@
"name": "props",
"kind": "OneOfBlocks",
"blocks": {
"space": "Space",
"space": "DemoSpace",
"richtext": "RichText",
"headline": "Headline",
"image": "DamImage",
Expand Down
16 changes: 16 additions & 0 deletions demo/api/src/common/blocks/space.block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createSpaceBlock } from "@comet/blocks-api";

export enum Spacing {
d150 = "d150",
d200 = "d200",
d250 = "d250",
d300 = "d300",
d350 = "d350",
d400 = "d400",
d450 = "d450",
d500 = "d500",
d550 = "d550",
d600 = "d600",
}

export const SpaceBlock = createSpaceBlock({ spacing: Spacing }, "DemoSpace");
6 changes: 3 additions & 3 deletions demo/api/src/db/fixtures/generators/blocks/space.generator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ExtractBlockInputFactoryProps, SpaceBlock } from "@comet/blocks-api";
import faker from "faker";
import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
import { SpaceBlock, Spacing } from "@src/common/blocks/space.block";

export const generateSpaceBlock = (): ExtractBlockInputFactoryProps<typeof SpaceBlock> => ({ height: faker.datatype.number(200) });
export const generateSpaceBlock = (): ExtractBlockInputFactoryProps<typeof SpaceBlock> => ({ spacing: Spacing.d200 });
3 changes: 2 additions & 1 deletion demo/api/src/pages/blocks/PageContentBlock.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BaseBlocksBlockItemData, BaseBlocksBlockItemInput, BlockField, createBlocksBlock, SpaceBlock, YouTubeVideoBlock } from "@comet/blocks-api";
import { BaseBlocksBlockItemData, BaseBlocksBlockItemInput, BlockField, createBlocksBlock, YouTubeVideoBlock } from "@comet/blocks-api";
import { AnchorBlock, DamImageBlock, DamVideoBlock } from "@comet/cms-api";
import { LinkListBlock } from "@src/common/blocks/link-list.block";
import { RichTextBlock } from "@src/common/blocks/rich-text.block";
import { SpaceBlock } from "@src/common/blocks/space.block";
import { UserGroup } from "@src/user-groups/user-group";
import { IsEnum } from "class-validator";

Expand Down
19 changes: 16 additions & 3 deletions demo/site/src/blocks/SpaceBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import { PropsWithData, withPreview } from "@comet/cms-site";
import { SpaceBlockData } from "@src/blocks.generated";
import { DemoSpaceBlockData } from "@src/blocks.generated";
import * as React from "react";

const SpaceBlock: React.FunctionComponent<PropsWithData<SpaceBlockData>> = ({ data: { height } }) => {
return <div style={{ height: `${height}px` }} />;
const SpaceMapping: Record<string, number> = {
d150: 10,
d200: 20,
d250: 40,
d300: 60,
d350: 80,
d400: 100,
d450: 150,
d500: 200,
d550: 250,
d600: 300,
};

const SpaceBlock: React.FC<PropsWithData<DemoSpaceBlockData>> = ({ data: { spacing } }) => {
return <div style={{ height: `${SpaceMapping[spacing]}px` }} />;
};

export default withPreview(SpaceBlock, { label: "Abstand" });
1 change: 1 addition & 0 deletions packages/admin/blocks-admin/src/blocks/SpaceBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const isHeightValid = (h: number) => h <= 1000;

const DEFAULT_HEIGHT = 100;

/** @deprecated The `SpaceBlock` is deprecated. It will be removed in the next major version. Use createSpaceBlock instead. */
export const SpaceBlock: BlockInterface<SpaceBlockData, State, SpaceBlockInput> = {
...createBlockSkeleton(),

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { SelectField } from "@comet/admin";
import { MenuItem } from "@mui/material";
import * as React from "react";
import { FormattedMessage } from "react-intl";

import { BlocksFinalForm } from "../../../form/BlocksFinalForm";
import { SelectPreviewComponent } from "../../../iframebridge/SelectPreviewComponent";
import { createBlockSkeleton } from "../../helpers/createBlockSkeleton";
import { BlockCategory, BlockInterface } from "../../types";

export interface SpaceBlockFactoryOptions<T> {
name?: string;
defaultValue: T;
options: { value: T; label: React.ReactNode }[];
}

export const createSpaceBlock = <T extends string | number>({
name = "Space",
defaultValue,
options,
}: SpaceBlockFactoryOptions<T>): BlockInterface => {
const SpaceBlock: BlockInterface<{ spacing: T }, { spacing: T }, { spacing: T }> = {
...createBlockSkeleton(),

name,

displayName: <FormattedMessage id="comet.blocks.space" defaultMessage="Space" />,

category: BlockCategory.Layout,

defaultValues: () => ({ spacing: defaultValue }),

AdminComponent: ({ state, updateState }) => {
return (
<SelectPreviewComponent>
<BlocksFinalForm<{ spacing: T }> onSubmit={updateState} initialValues={state}>
<SelectField name="spacing" fullWidth>
{options.map(({ value, label }) => (
<MenuItem key={value} value={value}>
{label}
</MenuItem>
))}
</SelectField>
</BlocksFinalForm>
</SelectPreviewComponent>
);
},

previewContent: ({ spacing }) => {
return [{ type: "text", content: options.find((option) => option.value === spacing)?.label }];
},
};

return SpaceBlock;
};
1 change: 1 addition & 0 deletions packages/admin/blocks-admin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type { CreateOneOfBlockOptions, OneOfBlockFragment, OneOfBlockState } fro
export { createOneOfBlock } from "./blocks/factories/createOneOfBlock";
export type { OptionalBlockDecoratorFragment, OptionalBlockState } from "./blocks/factories/createOptionalBlock";
export { createOptionalBlock } from "./blocks/factories/createOptionalBlock";
export { createSpaceBlock } from "./blocks/factories/spaceBlock/createSpaceBlock";
export { composeBlocks } from "./blocks/helpers/composeBlocks/composeBlocks";
export { createCompositeSetting } from "./blocks/helpers/composeBlocks/createCompositeSetting";
export { createCompositeSettings } from "./blocks/helpers/composeBlocks/createCompositeSettings";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SpaceBlockInput extends BlockInput {
}
}

/** @deprecated The `SpaceBlock` is deprecated. It will be removed in the next major version. Use `createSpaceBlock` instead. */
export const SpaceBlock = createBlock(SpaceBlockData, SpaceBlockInput, {
name: "Space",
// demoMigrations:
Expand Down
39 changes: 39 additions & 0 deletions packages/api/blocks-api/src/blocks/createSpaceBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { IsEnum } from "class-validator";

import { Block, BlockData, BlockDataInterface, BlockInput, createBlock, inputToData, SimpleBlockInputInterface } from "./block";
import { BlockField } from "./decorators/field";
import { BlockFactoryNameOrOptions } from "./factories/types";

interface CreateSpaceBlockOptions<SpacingOptions extends string[] | Record<string, string>> {
spacing: SpacingOptions;
}

type SingleEnumType<SpacingOptions extends string[] | Record<string, string>> = SpacingOptions extends string[]
? SpacingOptions[number]
: keyof SpacingOptions;

interface SpaceBlockInputInterface<SpacingOptions extends string[] | Record<string, string>> extends SimpleBlockInputInterface {
spacing: SingleEnumType<SpacingOptions>;
}

export function createSpaceBlock<SpacingOptions extends string[] | Record<string, string>>(
{ spacing: Spacing }: CreateSpaceBlockOptions<SpacingOptions>,
nameOrOptions: BlockFactoryNameOrOptions = "Space",
): Block<BlockDataInterface, SpaceBlockInputInterface<SpacingOptions>> {
class SpaceBlockData extends BlockData {
@BlockField({ type: "enum", enum: Spacing })
spacing: SingleEnumType<SpacingOptions>;
}

class SpaceBlockInput extends BlockInput {
@IsEnum(Spacing)
@BlockField({ type: "enum", enum: Spacing })
spacing: SingleEnumType<SpacingOptions>;

transformToBlockData(): SpaceBlockData {
return inputToData(SpaceBlockData, this);
}
}

return createBlock(SpaceBlockData, SpaceBlockInput, nameOrOptions);
}
1 change: 1 addition & 0 deletions packages/api/blocks-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export {
TraversableTransformResponseArray,
} from "./blocks/block";
export { createRichTextBlock } from "./blocks/createRichTextBlock";
export { createSpaceBlock } from "./blocks/createSpaceBlock";
export { createTextLinkBlock } from "./blocks/createTextLinkBlock";
export { ChildBlock } from "./blocks/decorators/child-block";
export { ChildBlockInput } from "./blocks/decorators/child-block-input";
Expand Down

0 comments on commit 90c6f19

Please sign in to comment.