diff --git a/apps/scandic-web/components/Blocks/Accordion/index.tsx b/apps/scandic-web/components/Blocks/Accordion/index.tsx index 5b9634dfc..689664307 100644 --- a/apps/scandic-web/components/Blocks/Accordion/index.tsx +++ b/apps/scandic-web/components/Blocks/Accordion/index.tsx @@ -4,8 +4,8 @@ import { useState } from "react" import Accordion from "@scandic-hotels/design-system/Accordion" import AccordionItem from "@scandic-hotels/design-system/Accordion/AccordionItem" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" -import JsonToHtml from "@/components/JsonToHtml" import SectionContainer from "@/components/Section/Container" import SectionHeader from "@/components/Section/Header" import ShowMoreButton from "@/components/TempDesignSystem/ShowMoreButton" diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx index 0b6c60432..1dadd659f 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx @@ -3,10 +3,10 @@ import { useIntl } from "react-intl" import Body from "@scandic-hotels/design-system/Body" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton" import Title from "@scandic-hotels/design-system/Title" -import JsonToHtml from "@/components/JsonToHtml" import { isRestaurantOnSiteTierReward } from "@/utils/rewards" import { RewardIcon } from "../../RewardIcon" diff --git a/apps/scandic-web/components/Blocks/TextCols/index.tsx b/apps/scandic-web/components/Blocks/TextCols/index.tsx index 22ca66fd7..910daaa59 100644 --- a/apps/scandic-web/components/Blocks/TextCols/index.tsx +++ b/apps/scandic-web/components/Blocks/TextCols/index.tsx @@ -1,9 +1,6 @@ +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import Subtitle from "@scandic-hotels/design-system/Subtitle" -import JsonToHtml from "@/components/JsonToHtml" - -import { renderOptions } from "./renderOptions" - import styles from "./textcols.module.css" import type { TextColProps } from "@/types/components/blocks/textCols" @@ -18,7 +15,6 @@ export default function TextCols({ text_cols }: TextColProps) { ) diff --git a/apps/scandic-web/components/Blocks/TextCols/renderOptions.tsx b/apps/scandic-web/components/Blocks/TextCols/renderOptions.tsx deleted file mode 100644 index 91bacb03d..000000000 --- a/apps/scandic-web/components/Blocks/TextCols/renderOptions.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import Link from "@scandic-hotels/design-system/Link" - -import styles from "./textcols.module.css" - -import type { EmbedByUid } from "@/types/transitionTypes/jsontohtml" -import { RTEItemTypeEnum, RTETypeEnum } from "@/types/transitionTypes/rte/enums" -import type { - RTENext, - RTENode, - RTERegularNode, -} from "@/types/transitionTypes/rte/node" -import type { RenderOptions } from "@/types/transitionTypes/rte/option" - -export const renderOptions: RenderOptions = { - [RTETypeEnum.a]: ( - node: RTERegularNode, - embeds: EmbedByUid, - next: RTENext, - fullRenderOptions: RenderOptions - ) => { - if (node.attrs.url) { - return ( - - {next(node.children, embeds, fullRenderOptions)} - - ) - } - return null - }, - [RTETypeEnum.reference]: ( - node: RTENode, - embeds: EmbedByUid, - next: RTENext, - fullRenderOptions: RenderOptions - ) => { - if ("attrs" in node) { - const type = node.attrs.type - if (type !== RTEItemTypeEnum.asset) { - const href = node.attrs?.locale - ? `/${node.attrs.locale}${node.attrs.href}` - : node.attrs.href - return ( - - {next(node.children, embeds, fullRenderOptions)} - - ) - } - - return null - } - }, -} diff --git a/apps/scandic-web/components/Blocks/UspGrid/index.tsx b/apps/scandic-web/components/Blocks/UspGrid/index.tsx index dc2d15832..54c7b674b 100644 --- a/apps/scandic-web/components/Blocks/UspGrid/index.tsx +++ b/apps/scandic-web/components/Blocks/UspGrid/index.tsx @@ -1,8 +1,6 @@ import { IconByIconName } from "@scandic-hotels/design-system/Icons/IconByIconName" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" -import JsonToHtml from "@/components/JsonToHtml" - -import { renderOptions } from "./renderOptions" import { getUspIconName } from "./utils" import styles from "./uspgrid.module.css" @@ -27,7 +25,6 @@ export default function UspGrid({ usp_grid }: UspGridProps) { ) diff --git a/apps/scandic-web/components/Blocks/UspGrid/renderOptions.tsx b/apps/scandic-web/components/Blocks/UspGrid/renderOptions.tsx deleted file mode 100644 index 117bda8d1..000000000 --- a/apps/scandic-web/components/Blocks/UspGrid/renderOptions.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import Link from "@scandic-hotels/design-system/Link" - -import type { EmbedByUid } from "@/types/transitionTypes/jsontohtml" -import { RTEItemTypeEnum, RTETypeEnum } from "@/types/transitionTypes/rte/enums" -import type { RTENext, RTENode } from "@/types/transitionTypes/rte/node" -import type { RenderOptions } from "@/types/transitionTypes/rte/option" - -export const renderOptions: RenderOptions = { - [RTETypeEnum.reference]: ( - node: RTENode, - embeds: EmbedByUid, - next: RTENext, - fullRenderOptions: RenderOptions - ) => { - if ("attrs" in node) { - const type = node.attrs.type - if (type !== RTEItemTypeEnum.asset) { - const href = node.attrs?.locale - ? `/${node.attrs.locale}${node.attrs.href}` - : node.attrs.href - - return ( - - {next(node.children, embeds, fullRenderOptions)} - - ) - } - - return null - } - }, -} diff --git a/apps/scandic-web/components/Blocks/index.tsx b/apps/scandic-web/components/Blocks/index.tsx index e2429ddac..24adb047b 100644 --- a/apps/scandic-web/components/Blocks/index.tsx +++ b/apps/scandic-web/components/Blocks/index.tsx @@ -1,5 +1,6 @@ import { Suspense } from "react" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { BlocksEnums } from "@scandic-hotels/trpc/types/blocksEnum" import CardsGrid from "@/components/Blocks/CardsGrid" @@ -8,7 +9,6 @@ import DynamicContent from "@/components/Blocks/DynamicContent" import ShortcutsList from "@/components/Blocks/ShortcutsList" import TextCols from "@/components/Blocks/TextCols" import UspGrid from "@/components/Blocks/UspGrid" -import JsonToHtml from "@/components/JsonToHtml" import AccordionSection from "./Accordion" import CardGallery from "./CardGallery" diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Blocks/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/Blocks/index.tsx index 877fdfacd..38f6a7bc4 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Blocks/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/Blocks/index.tsx @@ -1,11 +1,11 @@ "use client" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { BlocksEnums } from "@scandic-hotels/trpc/types/blocksEnum" import { useDestinationDataStore } from "@/stores/destination-data" import AccordionSection from "@/components/Blocks/Accordion" -import JsonToHtml from "@/components/JsonToHtml" import type { BlocksProps } from "@/types/components/blocks" diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Sidepeek/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/Sidepeek/index.tsx index f0cf6d182..6eda9bc0d 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Sidepeek/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/Sidepeek/index.tsx @@ -4,10 +4,10 @@ import { useState } from "react" import { useIntl } from "react-intl" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton" import SidePeek from "@scandic-hotels/design-system/SidePeek" -import JsonToHtml from "@/components/JsonToHtml" import { trackOpenSidePeekOnDestinationPagesEvent } from "@/utils/tracking/destinationPage" import type { DestinationCityPageData } from "@scandic-hotels/trpc/types/destinationCityPage" diff --git a/apps/scandic-web/components/JsonToHtml/index.tsx b/apps/scandic-web/components/JsonToHtml/index.tsx deleted file mode 100644 index 90c21d751..000000000 --- a/apps/scandic-web/components/JsonToHtml/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { cx } from "class-variance-authority" - -import { nodesToHtml } from "./utils" - -import styles from "./jsontohtml.module.css" - -import type { JsonToHtmlProps } from "@/types/transitionTypes/jsontohtml" - -export default function JsonToHtml({ - embeds, - nodes, - renderOptions = {}, - className, -}: JsonToHtmlProps) { - if (!Array.isArray(nodes) || !nodes.length) { - return null - } - - return ( -
- {nodesToHtml(nodes, embeds, renderOptions).filter(Boolean)} -
- ) -} diff --git a/apps/scandic-web/components/SasTierComparison/index.tsx b/apps/scandic-web/components/SasTierComparison/index.tsx index 4e7127f09..cb6a5abe5 100644 --- a/apps/scandic-web/components/SasTierComparison/index.tsx +++ b/apps/scandic-web/components/SasTierComparison/index.tsx @@ -4,13 +4,12 @@ import Image from "next/image" import Body from "@scandic-hotels/design-system/Body" import Caption from "@scandic-hotels/design-system/Caption" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import Link from "@scandic-hotels/design-system/Link" import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton" import Subtitle from "@scandic-hotels/design-system/Subtitle" import Title from "@scandic-hotels/design-system/Title" -import JsonToHtml from "@/components/JsonToHtml" - import SectionContainer from "../Section/Container" import styles from "./sasTierComparison.module.css" diff --git a/apps/scandic-web/components/Sidebar/index.tsx b/apps/scandic-web/components/Sidebar/index.tsx index de83ec5d6..437825415 100644 --- a/apps/scandic-web/components/Sidebar/index.tsx +++ b/apps/scandic-web/components/Sidebar/index.tsx @@ -1,8 +1,8 @@ +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { DynamicContentEnum } from "@scandic-hotels/trpc/types/dynamicContent" import { SidebarEnums } from "@scandic-hotels/trpc/types/sidebar" import EmployeeBenefitsAuthCard from "@/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard" -import JsonToHtml from "@/components/JsonToHtml" import ShortcutsList from "../Blocks/ShortcutsList" import Card from "../TempDesignSystem/Card" @@ -39,8 +39,8 @@ export default function Sidebar({ blocks }: SidebarProps) { case SidebarEnums.blocks.JoinLoyaltyContact: return ( ) case SidebarEnums.blocks.ScriptedCard: @@ -67,10 +67,10 @@ export default function Sidebar({ blocks }: SidebarProps) { return ( ) case SidebarEnums.blocks.QuickLinks: - return + return ( + + ) default: return null diff --git a/apps/scandic-web/components/TempDesignSystem/Alert/Sidepeek/index.tsx b/apps/scandic-web/components/TempDesignSystem/Alert/Sidepeek/index.tsx index 6ca836e82..9e517d806 100644 --- a/apps/scandic-web/components/TempDesignSystem/Alert/Sidepeek/index.tsx +++ b/apps/scandic-web/components/TempDesignSystem/Alert/Sidepeek/index.tsx @@ -4,11 +4,10 @@ import { useState } from "react" import { useIntl } from "react-intl" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton" import SidePeek from "@scandic-hotels/design-system/SidePeek" -import JsonToHtml from "@/components/JsonToHtml" - import styles from "./sidepeek.module.css" import type { AlertSidepeekProps } from "./sidepeek" diff --git a/apps/scandic-web/components/TempDesignSystem/TeaserCard/Sidepeek/index.tsx b/apps/scandic-web/components/TempDesignSystem/TeaserCard/Sidepeek/index.tsx index 83b63d9ea..3355fd083 100644 --- a/apps/scandic-web/components/TempDesignSystem/TeaserCard/Sidepeek/index.tsx +++ b/apps/scandic-web/components/TempDesignSystem/TeaserCard/Sidepeek/index.tsx @@ -6,10 +6,9 @@ import { useIntl } from "react-intl" import { Button } from "@scandic-hotels/design-system/Button" import ButtonLink from "@scandic-hotels/design-system/ButtonLink" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import SidePeek from "@scandic-hotels/design-system/SidePeek" -import JsonToHtml from "@/components/JsonToHtml" - import styles from "./sidepeek.module.css" import type { TeaserCardSidepeekProps } from "@/types/components/teaserCard" diff --git a/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx b/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx index 45fbbe032..32be19367 100644 --- a/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx +++ b/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx @@ -1,3 +1,4 @@ +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { BlocksEnums } from "@scandic-hotels/trpc/types/blocksEnum" import { DynamicContentEnum } from "@scandic-hotels/trpc/types/dynamicContent" @@ -7,7 +8,6 @@ import PointsOverview from "@/components/Blocks/DynamicContent/Points/Overview" import CurrentRewardsBlock from "@/components/Blocks/DynamicContent/Rewards/CurrentRewards" import NextLevelRewardsBlock from "@/components/Blocks/DynamicContent/Rewards/NextLevel" import ShortcutsList from "@/components/Blocks/ShortcutsList" -import JsonToHtml from "@/components/JsonToHtml" import { getLang } from "@/i18n/serverContext" import { modWebviewLink } from "@/utils/webviews" diff --git a/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx b/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx index 7e38aa838..224bc3558 100644 --- a/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx +++ b/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx @@ -1,9 +1,9 @@ +import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml" import { BlocksEnums } from "@scandic-hotels/trpc/types/blocksEnum" import CardsGrid from "@/components/Blocks/CardsGrid" import DynamicContent from "@/components/Blocks/DynamicContent" import ShortcutsList from "@/components/Blocks/ShortcutsList" -import JsonToHtml from "@/components/JsonToHtml" import { getLang } from "@/i18n/serverContext" import { modWebviewLink } from "@/utils/webviews" diff --git a/packages/design-system/.storybook/main.ts b/packages/design-system/.storybook/main.ts index 4427a5769..42b3c3b83 100644 --- a/packages/design-system/.storybook/main.ts +++ b/packages/design-system/.storybook/main.ts @@ -1,5 +1,5 @@ import { dirname, join } from 'path' -import type { StorybookConfig } from '@storybook/react-vite' +import type { StorybookConfig } from '@storybook/nextjs-vite' const config: StorybookConfig = { stories: ['../lib/**/*.mdx', '../lib/**/*.stories.@(js|jsx|mjs|ts|tsx)'], @@ -11,7 +11,7 @@ const config: StorybookConfig = { getAbsolutePath('@storybook/addon-a11y'), ], framework: { - name: getAbsolutePath('@storybook/react-vite'), + name: getAbsolutePath('@storybook/nextjs-vite'), options: {}, }, } diff --git a/packages/design-system/.storybook/preview.tsx b/packages/design-system/.storybook/preview.tsx index f1e36ecf4..67c92795b 100644 --- a/packages/design-system/.storybook/preview.tsx +++ b/packages/design-system/.storybook/preview.tsx @@ -1,6 +1,6 @@ import { withThemeByClassName } from '@storybook/addon-themes' -import type { Preview, ReactRenderer } from '@storybook/react-vite' +import type { Preview, ReactRenderer } from '@storybook/nextjs-vite' import '../lib/fonts.css' import '../lib/style.css' diff --git a/packages/design-system/.storybook/vitest.setup.ts b/packages/design-system/.storybook/vitest.setup.ts index 77ccf4796..9d2adaa08 100644 --- a/packages/design-system/.storybook/vitest.setup.ts +++ b/packages/design-system/.storybook/vitest.setup.ts @@ -1,4 +1,4 @@ -import { setProjectAnnotations } from '@storybook/react-vite' +import { setProjectAnnotations } from '@storybook/nextjs-vite' import * as previewAnnotations from './preview' setProjectAnnotations([previewAnnotations]) diff --git a/packages/design-system/lib/components/Button/Button.stories.tsx b/packages/design-system/lib/components/Button/Button.stories.tsx index cea5f5a1c..33cfeebd0 100644 --- a/packages/design-system/lib/components/Button/Button.stories.tsx +++ b/packages/design-system/lib/components/Button/Button.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { expect, fn } from 'storybook/test' diff --git a/packages/design-system/lib/components/Card/Card.stories.tsx b/packages/design-system/lib/components/Card/Card.stories.tsx index 6e20ec077..e450af9e7 100644 --- a/packages/design-system/lib/components/Card/Card.stories.tsx +++ b/packages/design-system/lib/components/Card/Card.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { Card } from './Card.tsx' diff --git a/packages/design-system/lib/components/Card/Compositions/ContentCard.stories.tsx b/packages/design-system/lib/components/Card/Compositions/ContentCard.stories.tsx index 659897dea..9cfe21069 100644 --- a/packages/design-system/lib/components/Card/Compositions/ContentCard.stories.tsx +++ b/packages/design-system/lib/components/Card/Compositions/ContentCard.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { fn } from 'storybook/test' import { themes } from '../../../../.storybook/preview' @@ -26,9 +26,9 @@ const meta: Meta = { return ( <>

{context.name}

- {Object.entries(themes.themes).map(([key, value]) => { + {Object.entries(themes.themes).map(([key, value], ix) => { return ( -
+

{key}

diff --git a/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx b/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx index 36f9a90b6..6dc78a3c2 100644 --- a/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx +++ b/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { fn } from 'storybook/test' diff --git a/packages/design-system/lib/components/ChipLink/ChipLink.stories.tsx b/packages/design-system/lib/components/ChipLink/ChipLink.stories.tsx index 11841cc64..9c2a7838f 100644 --- a/packages/design-system/lib/components/ChipLink/ChipLink.stories.tsx +++ b/packages/design-system/lib/components/ChipLink/ChipLink.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { MaterialIcon } from '../Icons/MaterialIcon' import { ChipLink } from './ChipLink.tsx' diff --git a/packages/design-system/lib/components/Chips/Chips.stories.tsx b/packages/design-system/lib/components/Chips/Chips.stories.tsx index 0a9f5d3a3..b1215b295 100644 --- a/packages/design-system/lib/components/Chips/Chips.stories.tsx +++ b/packages/design-system/lib/components/Chips/Chips.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { fn } from 'storybook/test' import { Chips } from './Chips.tsx' diff --git a/packages/design-system/lib/components/Divider/Divider.stories.tsx b/packages/design-system/lib/components/Divider/Divider.stories.tsx index 69b237c72..f83368482 100644 --- a/packages/design-system/lib/components/Divider/Divider.stories.tsx +++ b/packages/design-system/lib/components/Divider/Divider.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { Divider } from './Divider' diff --git a/packages/design-system/lib/components/IconButton/IconButton.stories.tsx b/packages/design-system/lib/components/IconButton/IconButton.stories.tsx index 4ead040c2..a3ef2ca9e 100644 --- a/packages/design-system/lib/components/IconButton/IconButton.stories.tsx +++ b/packages/design-system/lib/components/IconButton/IconButton.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { expect, fn } from 'storybook/test' diff --git a/packages/design-system/lib/components/Input/Input.stories.tsx b/packages/design-system/lib/components/Input/Input.stories.tsx index ffbef6c75..6c65fd836 100644 --- a/packages/design-system/lib/components/Input/Input.stories.tsx +++ b/packages/design-system/lib/components/Input/Input.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { expect } from 'storybook/test' diff --git a/packages/design-system/lib/components/JsonToHtml/JsonToHtml.stories.tsx b/packages/design-system/lib/components/JsonToHtml/JsonToHtml.stories.tsx new file mode 100644 index 000000000..5a110fa21 --- /dev/null +++ b/packages/design-system/lib/components/JsonToHtml/JsonToHtml.stories.tsx @@ -0,0 +1,297 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite' +import { JsonToHtml } from './JsonToHtml' +import { RTEImageVaultNode, RTENode } from './types/rte/node' +import { RTETypeEnum } from './types/rte/enums' +import { expect } from 'storybook/test' + +const meta: Meta = { + title: 'Components/JsonToHtml', + component: JsonToHtml, +} + +export default meta + +type Story = StoryObj + +const headings: RTENode[] = [ + { + uid: 'heading-1', + type: RTETypeEnum.h1, + attrs: { type: 'entry' }, + children: [{ text: 'Heading 1' }], + }, + { + uid: 'heading-2', + type: RTETypeEnum.h2, + attrs: { type: 'entry' }, + children: [{ text: 'Heading 2' }], + }, + { + uid: 'heading-3', + type: RTETypeEnum.h3, + attrs: { type: 'entry' }, + children: [{ text: 'Heading 3' }], + }, + { + uid: 'heading-4', + type: RTETypeEnum.h4, + attrs: { type: 'entry' }, + children: [{ text: 'Heading 4' }], + }, +] + +const paragraph: RTENode = { + uid: 'paragraph', + attrs: { type: 'asset' }, + type: RTETypeEnum.p, + children: [ + { text: 'This paragraph has ' }, + { text: 'bold', bold: true }, + { text: ' and ' }, + { text: 'italic', italic: true }, + { text: ' text, plus an inline ' }, + { + type: RTETypeEnum.a, + attrs: { type: 'asset', url: 'https://example.com' }, + uid: 'link-1', + children: [{ text: 'link' }], + }, + { text: '.' }, + ], +} +const list: RTENode = { + type: RTETypeEnum.ul, + attrs: { type: 'asset' }, + uid: 'list-1', + children: [ + { + type: RTETypeEnum.li, + uid: 'list-item-1', + attrs: { type: 'asset' }, + children: [{ text: 'First item' }], + }, + { + type: RTETypeEnum.li, + uid: 'list-item-2', + attrs: { type: 'asset' }, + children: [{ text: 'Second item' }], + }, + { + type: RTETypeEnum.li, + uid: 'list-item-3', + attrs: { type: 'asset' }, + children: [{ text: 'Third item' }], + }, + ], +} + +const code: RTENode = { + type: RTETypeEnum.code, + uid: 'code', + attrs: { type: 'asset' }, + children: [ + { + text: `function greet(name: string) { + return \`Hello, \${name}!\`; + }`, + }, + ], +} + +const blockquote: RTENode = { + type: RTETypeEnum.blockquote, + uid: 'blockqoute', + attrs: { type: 'asset' }, + children: [{ text: 'Simplicity is the soul of efficiency.' }], +} + +const horizontalRule: RTENode = { + type: RTETypeEnum.hr, + uid: 'horizontal-rule', + attrs: { type: 'entry' }, + children: [], +} + +const table: RTENode = { + type: RTETypeEnum.table, + uid: 'table', + attrs: { type: 'asset' }, + children: [ + { + type: RTETypeEnum.thead, + uid: 'table-header', + attrs: { type: 'asset' }, + children: [ + { + type: RTETypeEnum.tr, + uid: 'table-header-row-1', + attrs: { type: 'asset' }, + children: [ + { + type: RTETypeEnum.th, + uid: 'table-head-1', + attrs: { type: 'asset' }, + children: [{ text: 'Head 1' }], + }, + { + type: RTETypeEnum.th, + uid: 'table-head-2', + attrs: { type: 'asset' }, + children: [{ text: 'Head 2' }], + }, + { + type: RTETypeEnum.th, + uid: 'table-head-3', + attrs: { type: 'asset' }, + children: [{ text: 'Head 3' }], + }, + ], + }, + ], + }, + { + type: RTETypeEnum.tbody, + uid: 'table-body', + attrs: { type: 'asset' }, + children: [ + { + type: RTETypeEnum.tr, + uid: 'table-row-1', + attrs: { type: 'asset' }, + children: [ + { + type: RTETypeEnum.td, + uid: 'table-cell-1', + attrs: { type: 'asset' }, + children: [{ text: 'Cell 1' }], + }, + { + type: RTETypeEnum.td, + uid: 'table-cell-2', + attrs: { type: 'asset' }, + children: [{ text: 'Cell 2' }], + }, + { + type: RTETypeEnum.td, + uid: 'table-cell-3', + attrs: { type: 'asset' }, + children: [{ text: 'Cell 3' }], + }, + ], + }, + ], + }, + ], +} + +const image: RTEImageVaultNode = { + type: RTETypeEnum.ImageVault, + uid: 'image', + attrs: { + type: 'entry', + url: 'https://imagevault.scandichotels.com/publishedmedia/77obkq3g4harjm8wyua9/Scandic_Family_Breakfast_2.jpg', + height: '200px', + width: '200px', + id: 1, + title: 'Image Title', + dimensions: { width: 200, height: 200, aspectRatio: 1.5 }, + meta: { alt: 'Image Alt', caption: 'Image Caption' }, + focalPoint: { x: 50, y: 50 }, + }, + children: [], +} + +export const Example: Story = { + args: { + nodes: [ + { + uid: 'paragraph', + attrs: { type: 'asset' }, + type: RTETypeEnum.p, + children: [ + { text: 'This is a kitchen sink of all Rich Text Editor to HTML' }, + ], + }, + ...headings, + paragraph, + list, + code, + blockquote, + horizontalRule, + image, + ] satisfies RTENode[], + embeds: [], + }, +} + +export const Headings: Story = { + args: { + nodes: headings, + embeds: [], + }, + play: async ({ canvas }) => { + expect( + await canvas.findByRole('heading', { name: 'Heading 1' }) + ).toBeInTheDocument() + + expect( + await canvas.findByRole('heading', { name: 'Heading 2' }) + ).toBeInTheDocument() + + expect( + await canvas.findByRole('heading', { name: 'Heading 3' }) + ).toBeInTheDocument() + + expect( + await canvas.findByRole('heading', { name: 'Heading 4' }) + ).toBeInTheDocument() + }, +} +export const Paragraph: Story = { + args: { + nodes: [paragraph], + embeds: [], + }, +} + +export const Code: Story = { + args: { + nodes: [code], + embeds: [], + }, +} + +export const List: Story = { + args: { + nodes: [list], + embeds: [], + }, +} + +export const BlockQuote: Story = { + args: { + nodes: [blockquote], + embeds: [], + }, +} + +export const HorizontalRule: Story = { + args: { + nodes: [horizontalRule], + embeds: [], + }, +} + +export const Table: Story = { + args: { + nodes: [table], + embeds: [], + }, +} + +export const Image: Story = { + args: { + nodes: [image], + embeds: [], + }, +} diff --git a/packages/design-system/lib/components/JsonToHtml/JsonToHtml.tsx b/packages/design-system/lib/components/JsonToHtml/JsonToHtml.tsx new file mode 100644 index 000000000..83b93d24d --- /dev/null +++ b/packages/design-system/lib/components/JsonToHtml/JsonToHtml.tsx @@ -0,0 +1,68 @@ +import { cx } from 'class-variance-authority' + +import { nodesToHtml } from './utils' + +import styles from './jsontohtml.module.css' + +import type { RTENode } from './types/rte/node' +import type { RenderOptions } from './types/rte/option' +import { ContentBlockType } from './types/rte/enums' + +export type Node = { + node: T +} + +type Image = { + id: number + title: string + url: string + focalPoint: { + x: number + y: number + } + meta: { + alt?: string | null + caption?: string | null + } +} +export type Embeds = + | { + __typename: Exclude + system?: { uid: string } | undefined | null + url?: string | undefined | null + title?: string | undefined | null + } + | { + __typename: 'ImageContainer' + system?: { uid: string } | undefined | null + url?: string | undefined | null + title?: string | undefined | null + image_left?: Image | undefined + image_right?: Image | undefined + } + +export type EmbedByUid = Record> + +export type JsonToHtmlProps = { + embeds: Node[] + nodes: RTENode[] + renderOptions?: RenderOptions + className?: string +} + +export function JsonToHtml({ + embeds, + nodes, + renderOptions = {}, + className, +}: JsonToHtmlProps) { + if (!Array.isArray(nodes) || !nodes.length) { + return null + } + + return ( +
+ {nodesToHtml(nodes, embeds, renderOptions).filter(Boolean)} +
+ ) +} diff --git a/packages/design-system/lib/components/JsonToHtml/insertResponseToImageVaultAsset.ts b/packages/design-system/lib/components/JsonToHtml/insertResponseToImageVaultAsset.ts new file mode 100644 index 000000000..a61d57a8d --- /dev/null +++ b/packages/design-system/lib/components/JsonToHtml/insertResponseToImageVaultAsset.ts @@ -0,0 +1,60 @@ +export type ImageVaultAsset = { + id: number + title: string + url: string + dimensions: { + width: number + height: number + aspectRatio: number + } + meta: { alt: string | undefined | null; caption: string | undefined | null } + focalPoint: { x: number; y: number } +} + +type ImageVaultAssetResponse = { + Id: number + Name: string + FocalPoint: { x: number; y: number } + Metadata: Array<{ Name: string; Value: string }> + MediaConversions: Array<{ + Url: string + Width: number + Height: number + AspectRatio: number + FormatAspectRatio: number + }> +} + +export function insertResponseToImageVaultAsset( + response: ImageVaultAssetResponse +): ImageVaultAsset { + const alt = response.Metadata?.find((meta) => + meta.Name.includes('AltText_') + )?.Value + + const caption = response.Metadata?.find((meta) => + meta.Name.includes('Title_') + )?.Value + + const mediaConversion = response.MediaConversions[0] + const aspectRatio = + mediaConversion.FormatAspectRatio || + mediaConversion.AspectRatio || + mediaConversion.Width / mediaConversion.Height + + return { + url: mediaConversion.Url, + id: response.Id, + meta: { + alt, + caption, + }, + title: response.Name, + dimensions: { + width: mediaConversion.Width, + height: mediaConversion.Height, + aspectRatio, + }, + focalPoint: response.FocalPoint || { x: 50, y: 50 }, + } +} diff --git a/apps/scandic-web/components/JsonToHtml/jsontohtml.module.css b/packages/design-system/lib/components/JsonToHtml/jsontohtml.module.css similarity index 100% rename from apps/scandic-web/components/JsonToHtml/jsontohtml.module.css rename to packages/design-system/lib/components/JsonToHtml/jsontohtml.module.css diff --git a/apps/scandic-web/components/JsonToHtml/renderOptions.tsx b/packages/design-system/lib/components/JsonToHtml/renderOptions.tsx similarity index 66% rename from apps/scandic-web/components/JsonToHtml/renderOptions.tsx rename to packages/design-system/lib/components/JsonToHtml/renderOptions.tsx index 229fa4485..c8e708838 100644 --- a/apps/scandic-web/components/JsonToHtml/renderOptions.tsx +++ b/packages/design-system/lib/components/JsonToHtml/renderOptions.tsx @@ -1,33 +1,28 @@ -import { cx } from "class-variance-authority" +import { cx } from 'class-variance-authority' -import { Divider } from "@scandic-hotels/design-system/Divider" -import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" -import Image from "@scandic-hotels/design-system/Image" -import ImageContainer from "@scandic-hotels/design-system/ImageContainer" -import Link from "@scandic-hotels/design-system/Link" -import Table from "@scandic-hotels/design-system/Table" -import { Typography } from "@scandic-hotels/design-system/Typography" -import { ContentEnum } from "@scandic-hotels/trpc/types/content" -import { insertResponseToImageVaultAsset } from "@scandic-hotels/trpc/utils/imageVault" +import { Divider } from '@scandic-hotels/design-system/Divider' +import { MaterialIcon } from '@scandic-hotels/design-system/Icons/MaterialIcon' +import Image from '@scandic-hotels/design-system/Image' +import ImageContainer from '@scandic-hotels/design-system/ImageContainer' +import Link from '@scandic-hotels/design-system/Link' +import Table from '@scandic-hotels/design-system/Table' +import { Typography } from '@scandic-hotels/design-system/Typography' import { hasAvailableParagraphFormat, hasAvailableULFormat, makeCssModuleCompatibleClassName, -} from "./utils" +} from './utils' -import styles from "./jsontohtml.module.css" +import styles from './jsontohtml.module.css' -import type { EmbedByUid } from "@/types/transitionTypes/jsontohtml" -import type { - Attributes, - RTEImageVaultAttrs, -} from "@/types/transitionTypes/rte/attrs" +import type { EmbedByUid } from './JsonToHtml' +import type { Attributes, RTEImageVaultAttrs } from './types/rte/attrs' import { AvailableParagraphFormatEnum, RTEItemTypeEnum, RTETypeEnum, -} from "@/types/transitionTypes/rte/enums" +} from './types/rte/enums' import { type RTEDefaultNode, type RTEImageNode, @@ -36,11 +31,12 @@ import { type RTENode, type RTERegularNode, type RTETextNode, -} from "@/types/transitionTypes/rte/node" -import type { RenderOptions } from "@/types/transitionTypes/rte/option" +} from './types/rte/node' +import type { RenderOptions } from './types/rte/option' +import { insertResponseToImageVaultAsset } from './insertResponseToImageVaultAsset' function noNestedLinksOrReferences(node: RTENode) { - if ("type" in node) { + if ('type' in node) { if (node.type === RTETypeEnum.reference) { return node.children } else if (node.type === RTETypeEnum.a) { @@ -52,22 +48,25 @@ function noNestedLinksOrReferences(node: RTENode) { function extractPossibleAttributes(attrs: Attributes | undefined) { if (!attrs) return {} - const props: Record = {} + const props: Record & { + className?: string + style?: React.CSSProperties | undefined + } = {} if (attrs.id) { props.id = attrs.id } - if (attrs.class) { + if (attrs.class && typeof attrs.class === 'string') { props.className = attrs.class - } else if (attrs["class-name"]) { - props.className = attrs["class-name"] - } else if (attrs.classname) { + } else if (attrs['class-name']) { + props.className = attrs['class-name'] + } else if (attrs.classname && typeof attrs.classname === 'string') { props.className = attrs.classname } - if (attrs.style?.["text-align"]) { + if (attrs.style?.['text-align']) { props.style = { - textAlign: attrs.style["text-align"], + textAlign: attrs.style['text-align'] as React.CSSProperties['textAlign'], } } @@ -81,28 +80,31 @@ export const renderOptions: RenderOptions = { next: RTENext, fullRenderOptions: RenderOptions ) => { - if (node.attrs.url) { - const { className, ...props } = extractPossibleAttributes(node.attrs) - return ( - - {next( - // Sometimes editors happen to nest a reference inside a link and vice versa. - // In that case use the outermost link, i.e. ignore nested links. - node.children.flatMap(noNestedLinksOrReferences), - embeds, - fullRenderOptions - )} - - ) + if (!node.attrs.url) { + return } - return null + + const { className, ...props } = extractPossibleAttributes(node.attrs) + return ( + + {next( + // Sometimes editors happen to nest a reference inside a link and vice versa. + // In that case use the outermost link, i.e. ignore nested links. + node.children.flatMap(noNestedLinksOrReferences), + embeds, + fullRenderOptions + )} + + ) }, [RTETypeEnum.blockquote]: ( @@ -255,7 +257,7 @@ export const renderOptions: RenderOptions = { const { className, ...props } = extractPossibleAttributes(node.attrs) const compatibleClassName = makeCssModuleCompatibleClassName( className, - "ul" + 'ul' ) return (
  • { const { className, ...props } = extractPossibleAttributes(node.attrs) - let propsClassName = props.className + let propsClassName = className if (className) { if (hasAvailableULFormat(className)) { - // @ts-ignore: We want to set css modules classNames even if it does not correspond - // to an existing class in the module style sheet. Due to our css modules plugin for - // typescript, we cannot do this without the ts-ignore propsClassName = styles[className] } } @@ -383,150 +379,149 @@ export const renderOptions: RenderOptions = { next: RTENext, fullRenderOptions: RenderOptions ) => { - if ("attrs" in node) { - const type = node.attrs.type - if (type === RTEItemTypeEnum.asset) { - const imageTypeRegex = /^image\// - const isImage = imageTypeRegex.test(node.attrs["asset-type"]) - if (isImage) { - const image = embeds?.[node?.attrs?.["asset-uid"]] - if (image?.node.__typename === ContentEnum.blocks.SysAsset) { - if (image.node.url) { - const alt = image?.node?.title ?? node.attrs.alt - const { className, ...props } = extractPossibleAttributes( - node.attrs - ) - return ( -
    - {alt} -
    - ) - } - } - } else if (node.attrs["display-type"] === "link" && node.attrs.href) { - const { className, ...props } = extractPossibleAttributes(node.attrs) - return ( - - {next( - // Sometimes editors happen to nest a reference inside a link and vice versa. - // In that case use the outermost link, i.e. ignore nested links. - node.children.flatMap(noNestedLinksOrReferences), - embeds, - fullRenderOptions - )} - - - ) - } - } else if (type === RTEItemTypeEnum.entry) { - const entry = embeds?.[node?.attrs?.["entry-uid"]] - - if (entry?.node.__typename === ContentEnum.blocks.ImageContainer) { - if (entry.node.image_left && entry.node.image_right) { - return ( - - ) - } - return null - } else if ( - entry?.node.__typename === ContentEnum.blocks.AccountPage || - entry?.node.__typename === ContentEnum.blocks.CampaignOverviewPage || - entry?.node.__typename === ContentEnum.blocks.CampaignPage || - entry?.node.__typename === ContentEnum.blocks.CollectionPage || - entry?.node.__typename === ContentEnum.blocks.ContentPage || - entry?.node.__typename === ContentEnum.blocks.DestinationCityPage || - entry?.node.__typename === - ContentEnum.blocks.DestinationCountryPage || - entry?.node.__typename === - ContentEnum.blocks.DestinationOverviewPage || - entry?.node.__typename === ContentEnum.blocks.HotelPage || - entry?.node.__typename === ContentEnum.blocks.LoyaltyPage || - entry?.node.__typename === ContentEnum.blocks.StartPage - ) { - // If entry is not an ImageContainer, it is a page and we return it as a link - const { className, ...props } = extractPossibleAttributes(node.attrs) - - return ( - - {next( - // Sometimes editors happen to nest a reference inside a link and vice versa. - // In that case use the outermost link, i.e. ignore nested links. - node.children.flatMap(noNestedLinksOrReferences), - embeds, - fullRenderOptions - )} - - ) - } - } + if (!('attrs' in node)) { + return null } - return null - }, - - [RTETypeEnum.ImageVault]: (node: RTEImageNode) => { - if ("attrs" in node) { - const type = node.type - if (type === RTETypeEnum.ImageVault) { - const attrs = node.attrs as RTEImageVaultAttrs - let image = undefined - if ("dimensions" in attrs) { - image = attrs - } else { - image = insertResponseToImageVaultAsset(attrs) + const type = node.attrs.type + if (type === RTEItemTypeEnum.asset) { + const imageTypeRegex = /^image\// + const isImage = imageTypeRegex.test(node.attrs['asset-type'] as string) + if (isImage) { + const image = embeds?.[node?.attrs?.['asset-uid'] as string] + if (image?.node.__typename === 'SysAsset') { + if (image.node.url) { + const alt = image?.node?.title ?? node.attrs.alt + const { className, ...props } = extractPossibleAttributes( + node.attrs + ) + return ( +
    + {alt +
    + ) + } } - const alt = image.meta.alt ?? image.title - const caption = image.meta.caption - const { className, ...props } = extractPossibleAttributes(attrs) + } else if (node.attrs['display-type'] === 'link' && node.attrs.href) { + const { className, ...props } = extractPossibleAttributes(node.attrs) return ( -
    -
    - {alt} -
    - {caption ? ( - -

    {image.meta.caption}

    -
    - ) : null} -
    + + {next( + // Sometimes editors happen to nest a reference inside a link and vice versa. + // In that case use the outermost link, i.e. ignore nested links. + node.children.flatMap(noNestedLinksOrReferences), + embeds, + fullRenderOptions + )} + + ) } } - return null + if (type === RTEItemTypeEnum.entry) { + const entry = embeds?.[node?.attrs?.['entry-uid'] as string] + + if (entry?.node.__typename === 'ImageContainer') { + if (entry.node.image_left && entry.node.image_right) { + return ( + + ) + } + return null + } else if ( + entry?.node.__typename === 'AccountPage' || + entry?.node.__typename === 'CampaignOverviewPage' || + entry?.node.__typename === 'CampaignPage' || + entry?.node.__typename === 'CollectionPage' || + entry?.node.__typename === 'ContentPage' || + entry?.node.__typename === 'DestinationCityPage' || + entry?.node.__typename === 'DestinationCountryPage' || + entry?.node.__typename === 'DestinationOverviewPage' || + entry?.node.__typename === 'HotelPage' || + entry?.node.__typename === 'LoyaltyPage' || + entry?.node.__typename === 'StartPage' + ) { + // If entry is not an ImageContainer, it is a page and we return it as a link + const { className, ...props } = extractPossibleAttributes(node.attrs) + + const href = node.attrs?.locale + ? `/${node.attrs.locale}${node.attrs.href ?? node.attrs.url}` + : ((node.attrs.href ?? node.attrs.url) as string) + + return ( + + {next( + // Sometimes editors happen to nest a reference inside a link and vice versa. + // In that case use the outermost link, i.e. ignore nested links. + node.children.flatMap(noNestedLinksOrReferences), + embeds, + fullRenderOptions + )} + + ) + } + } + }, + + [RTETypeEnum.ImageVault]: (node: RTEImageNode) => { + const type = node.type + if (!('attrs' in node) || type !== RTETypeEnum.ImageVault) { + return null + } + + const attrs = node.attrs as RTEImageVaultAttrs + const image = + 'dimensions' in attrs ? attrs : insertResponseToImageVaultAsset(attrs) + + const alt = image.meta.alt ?? image.title + const caption = image.meta.caption + const { className, ...props } = extractPossibleAttributes(attrs) + return ( +
    +
    + {alt} +
    + {caption ? ( + +

    {image.meta.caption}

    +
    + ) : null} +
    + ) }, [RTETypeEnum.table]: ( @@ -663,7 +658,7 @@ export const renderOptions: RenderOptions = { const { className, ...props } = extractPossibleAttributes(node.attrs) const compatibleClassName = makeCssModuleCompatibleClassName( className, - "ul" + 'ul' ) // Set the number of rows dynamically to create even rows for each column. We want the li:s @@ -753,9 +748,6 @@ export const renderOptions: RenderOptions = { if (className) { if (hasAvailableULFormat(className)) { - // @ts-ignore: We want to set css modules classNames even if it does not correspond - // to an existing class in the module style sheet. Due to our css modules plugin for - // typescript, we cannot do this without the ts-ignore propsClassName = styles[className] } } @@ -780,7 +772,7 @@ export const renderOptions: RenderOptions = { ) } - if (className === AvailableParagraphFormatEnum["script-1"]) { + if (className === AvailableParagraphFormatEnum['script-1']) { return (

    @@ -790,7 +782,7 @@ export const renderOptions: RenderOptions = { ) } - if (className === AvailableParagraphFormatEnum["script-2"]) { + if (className === AvailableParagraphFormatEnum['script-2']) { return (

    @@ -800,7 +792,7 @@ export const renderOptions: RenderOptions = { ) } - if (className === AvailableParagraphFormatEnum["subtitle-1"]) { + if (className === AvailableParagraphFormatEnum['subtitle-1']) { return (

    @@ -809,7 +801,7 @@ export const renderOptions: RenderOptions = { ) } - if (className === AvailableParagraphFormatEnum["subtitle-2"]) { + if (className === AvailableParagraphFormatEnum['subtitle-2']) { return (

    diff --git a/packages/design-system/lib/components/JsonToHtml/types/rte/attrs.ts b/packages/design-system/lib/components/JsonToHtml/types/rte/attrs.ts new file mode 100644 index 000000000..306b5661e --- /dev/null +++ b/packages/design-system/lib/components/JsonToHtml/types/rte/attrs.ts @@ -0,0 +1,55 @@ +import type { Lang } from '@scandic-hotels/common/constants/language' + +import type { EmbedTypesEnum, RTEItemType, RTEItemTypeEnum } from './enums' + +export interface Attributes { + [key: string]: unknown + 'class-name'?: string + type: RTEItemType + style?: { [key: string]: unknown } | undefined +} + +export interface RTEAssetAttrs extends Attributes { + alt: string + 'asset-alt': string + 'asset-link': string + 'asset-name': string + 'asset-type': 'image/png' | 'image/jpg' | 'image/jpeg' + 'asset-uid': string + 'display-type': EmbedTypesEnum.display + 'content-type-uid': 'sys_assets' + inline: false + type: RTEItemTypeEnum.asset +} + +export interface RTEAnchorAttrs extends Attributes { + target: string + url: string +} + +export interface RTELinkAttrs extends Attributes { + 'display-type': EmbedTypesEnum.link + 'class-name': string + 'content-type-uid': string + 'entry-uid': string + locale: Lang + href: string + target: HTMLAnchorElement['target'] + type: RTEItemTypeEnum.entry +} + +export interface RTEImageVaultAttrs extends Attributes { + height: string + // style: string[] + width: string + id: number + title: string + url: string + dimensions: { + width: number + height: number + aspectRatio: number + } + meta: { alt: string | undefined | null; caption: string | undefined | null } + focalPoint: { x: number; y: number } +} diff --git a/packages/design-system/lib/components/JsonToHtml/types/rte/enums.ts b/packages/design-system/lib/components/JsonToHtml/types/rte/enums.ts new file mode 100644 index 000000000..18df410aa --- /dev/null +++ b/packages/design-system/lib/components/JsonToHtml/types/rte/enums.ts @@ -0,0 +1,84 @@ +export enum EmbedTypesEnum { + block = 'block', + display = 'display', + download = 'download', + inline = 'inline', + link = 'link', +} + +export type EmbedTypes = keyof typeof EmbedTypesEnum + +/** Copied from https://github.com/contentstack/contentstack-utils-javascript/blob/master/src/nodes/node-type.ts */ +export enum RTETypeEnum { + a = 'a', + blockquote = 'blockquote', + code = 'code', + doc = 'doc', + embed = 'embed', + h1 = 'h1', + h2 = 'h2', + h3 = 'h3', + h4 = 'h4', + h5 = 'h5', + h6 = 'h6', + hr = 'hr', + img = 'img', + li = 'li', + ol = 'ol', + p = 'p', + reference = 'reference', + span = 'span', + /** + * Included for compatibility when copying RTE from other sources e.g. epi + */ + div = 'div', + table = 'table', + tbody = 'tbody', + td = 'td', + text = 'text', + tfoot = 'tfoot', + th = 'th', + thead = 'thead', + tr = 'tr', + ul = 'ul', + ImageVault = 'ImageVault', + fragment = 'fragment', +} + +export type RTEType = keyof typeof RTETypeEnum + +export enum RTEItemTypeEnum { + asset = 'asset', + entry = 'entry', +} + +export type RTEItemType = keyof typeof RTEItemTypeEnum + +export enum AvailableParagraphFormatEnum { + 'script-1' = 'script-1', + 'script-2' = 'script-2', + 'footnote' = 'footnote', + 'caption' = 'caption', + 'subtitle-1' = 'subtitle-1', + 'subtitle-2' = 'subtitle-2', +} + +export enum AvailableULFormatEnum { + 'heart' = 'heart', + 'check' = 'check', +} + +export type ContentBlockType = + | 'AccountPage' + | 'CampaignOverviewPage' + | 'CampaignPage' + | 'CollectionPage' + | 'ContentPage' + | 'DestinationCityPage' + | 'DestinationCountryPage' + | 'DestinationOverviewPage' + | 'HotelPage' + | 'ImageContainer' + | 'LoyaltyPage' + | 'StartPage' + | 'SysAsset' diff --git a/packages/design-system/lib/components/JsonToHtml/types/rte/node.ts b/packages/design-system/lib/components/JsonToHtml/types/rte/node.ts new file mode 100644 index 000000000..d79df13dd --- /dev/null +++ b/packages/design-system/lib/components/JsonToHtml/types/rte/node.ts @@ -0,0 +1,98 @@ +import type { JSX } from 'react' + +import type { EmbedByUid } from '../../JsonToHtml' +import type { + Attributes, + RTEAnchorAttrs, + RTEAssetAttrs, + RTEImageVaultAttrs, + RTELinkAttrs, +} from './attrs' +import type { RTETypeEnum } from './enums' +import type { RenderOptions } from './option' + +export interface RTEDefaultNode { + attrs: Attributes + children: RTENode[] + type: RTETypeEnum + uid: string +} + +export interface RTELinkNode { + attrs: Attributes + children: RTENode[] + type: RTETypeEnum + uid: string +} + +export interface RTEReferenceAssetNode extends RTEDefaultNode { + attrs: RTEAssetAttrs +} + +export interface RTEAnchorNode extends RTEDefaultNode { + attrs: RTEAnchorAttrs + type: RTETypeEnum.a +} + +export interface RTEReferenceLinkNode extends RTEDefaultNode { + attrs: RTELinkAttrs +} + +export interface RTEImageVaultNode extends RTEDefaultNode { + attrs: RTEImageVaultAttrs + type: RTETypeEnum.ImageVault +} + +export enum RTEMarkType { + bold = 'bold', + break = 'break', + classnameOrId = 'classnameOrId', + inlineCode = 'inlineCode', + italic = 'italic', + strikethrough = 'strikethrough', + subscript = 'subscript', + superscript = 'superscript', + underline = 'underline', +} + +type RTETextNodeOptionalKeys = { + [key in RTEMarkType]?: boolean +} + +export type RTETextNode = RTETextNodeOptionalKeys & { + classname?: string + id?: string + text: string +} + +export type RTERegularNode = RTEDefaultNode | RTEAnchorNode | RTEImageVaultNode + +export type RTEImageNode = RTEDefaultNode | RTEImageVaultNode + +export type RTEReferenceNode = RTEAnchorNode + +export type RTENode = RTERegularNode | RTEReferenceNode | RTETextNode + +export type RTERenderMark = ( + children: React.ReactNode, + classname?: string, + id?: string +) => JSX.Element + +export interface RTEDocument extends RTEDefaultNode { + type: RTETypeEnum.doc + _version: number +} + +export type RTERenderOptionComponent = ( + node: RTERegularNode, + embeds: EmbedByUid, + next: RTENext, + fullRenderOptions: RenderOptions +) => React.ReactNode + +export type RTENext = ( + nodes: RTENode[], + embeds: EmbedByUid, + fullRenderOptions: RenderOptions +) => string diff --git a/packages/design-system/lib/components/JsonToHtml/types/rte/option.ts b/packages/design-system/lib/components/JsonToHtml/types/rte/option.ts new file mode 100644 index 000000000..126a5aeec --- /dev/null +++ b/packages/design-system/lib/components/JsonToHtml/types/rte/option.ts @@ -0,0 +1,5 @@ +import type { RTERenderMark, RTERenderOptionComponent } from "./node" + +export type RenderOptions = { + [type: string]: RTERenderOptionComponent | RTERenderMark +} diff --git a/apps/scandic-web/components/JsonToHtml/utils.tsx b/packages/design-system/lib/components/JsonToHtml/utils.tsx similarity index 81% rename from apps/scandic-web/components/JsonToHtml/utils.tsx rename to packages/design-system/lib/components/JsonToHtml/utils.tsx index a52a9ae3b..f0b56728a 100644 --- a/apps/scandic-web/components/JsonToHtml/utils.tsx +++ b/packages/design-system/lib/components/JsonToHtml/utils.tsx @@ -1,30 +1,29 @@ -import React, { cloneElement } from "react" +import React, { cloneElement } from 'react' -import { renderOptions } from "./renderOptions" +import { renderOptions } from './renderOptions' -import styles from "./jsontohtml.module.css" +import styles from './jsontohtml.module.css' -import type { Node } from "@scandic-hotels/trpc/types/edges" -import type { Embeds } from "@scandic-hotels/trpc/types/embeds" +import type { Node, Embeds } from './JsonToHtml' -import type { EmbedByUid } from "@/types/transitionTypes/jsontohtml" import { AvailableParagraphFormatEnum, AvailableULFormatEnum, RTETypeEnum, -} from "@/types/transitionTypes/rte/enums" +} from './types/rte/enums' import { RTEMarkType, type RTENode, type RTERenderMark, type RTERenderOptionComponent, type RTETextNode, -} from "@/types/transitionTypes/rte/node" -import type { RenderOptions } from "@/types/transitionTypes/rte/option" +} from './types/rte/node' +import type { RenderOptions } from './types/rte/option' +import { EmbedByUid } from './JsonToHtml' export function groupEmbedsByUid(embedsArray: Node[]) { const embedsByUid = embedsArray.reduce((acc, embed) => { - if (embed.node.system?.uid) { + if ('system' in embed.node && embed.node.system?.uid) { acc[embed.node.system.uid] = embed } return acc @@ -37,6 +36,8 @@ export function nodeChildrenToHtml( nodes: RTENode[], embeds: EmbedByUid, fullRenderOptions: RenderOptions + // TODO: Change this to an actual return + // eslint-disable-next-line @typescript-eslint/no-explicit-any ): any { return nodes .map((node, i) => { @@ -120,7 +121,7 @@ export function nodeToHtml( embeds: EmbedByUid, fullRenderOptions: RenderOptions ) { - if ("type" in node === false) { + if ('type' in node === false) { return textNodeToHtml(node, fullRenderOptions) } else { const renderer = fullRenderOptions[node.type] as RTERenderOptionComponent @@ -137,7 +138,7 @@ export function nodeToHtml( } function getUniqueId(node: RTENode) { - if ("uid" in node) { + if ('uid' in node) { return node.uid } return node.id @@ -149,7 +150,10 @@ export function nodesToHtml( overrideRenderOptions: RenderOptions ) { const embeds = groupEmbedsByUid(embedsArray) - const fullRenderOptions = { ...renderOptions, ...overrideRenderOptions } + const fullRenderOptions: RenderOptions = { + ...renderOptions, + ...overrideRenderOptions, + } return nodes.map((node, index) => { const nodeHtml = nodeToHtml(node, embeds, fullRenderOptions) @@ -164,12 +168,13 @@ export function nodesToHtml( export function makeCssModuleCompatibleClassName( className: string | undefined, - formatType: "ul" + formatType: 'ul' ): string { - if (!className) return "" + if (!className) return '' - if (formatType === "ul" && hasAvailableULFormat(className)) { - // @ts-ignore: We want to set css modules classNames even if it does not correspond + if (formatType === 'ul' && hasAvailableULFormat(className)) { + // TODO: REMOVE + // @ats-expect-error: We want to set css modules classNames even if it does not correspond // to an existing class in the module style sheet. Due to our css modules plugin for // typescript, we cannot do this without the ts-ignore return styles[className] || className diff --git a/packages/design-system/lib/components/Label/Label.stories.tsx b/packages/design-system/lib/components/Label/Label.stories.tsx index 22607c64b..ddb800e70 100644 --- a/packages/design-system/lib/components/Label/Label.stories.tsx +++ b/packages/design-system/lib/components/Label/Label.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { Label } from './Label' diff --git a/packages/design-system/lib/components/Loading/Loading.stories.tsx b/packages/design-system/lib/components/Loading/Loading.stories.tsx index 3a196b65a..d911605cf 100644 --- a/packages/design-system/lib/components/Loading/Loading.stories.tsx +++ b/packages/design-system/lib/components/Loading/Loading.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { Loading } from './Loading' import { config } from './variants' diff --git a/packages/design-system/lib/components/RateCard/Campaign/Campaign.stories.tsx b/packages/design-system/lib/components/RateCard/Campaign/Campaign.stories.tsx index c19124bd4..3572e69ec 100644 --- a/packages/design-system/lib/components/RateCard/Campaign/Campaign.stories.tsx +++ b/packages/design-system/lib/components/RateCard/Campaign/Campaign.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import CampaignRateCard from '.' const meta: Meta = { diff --git a/packages/design-system/lib/components/RateCard/Code/Code.stories.tsx b/packages/design-system/lib/components/RateCard/Code/Code.stories.tsx index 5ce0ecac7..d0b9220df 100644 --- a/packages/design-system/lib/components/RateCard/Code/Code.stories.tsx +++ b/packages/design-system/lib/components/RateCard/Code/Code.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import CodeRateCard from '.' const meta: Meta = { diff --git a/packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx b/packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx index f75d9ac1e..6b64728d0 100644 --- a/packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx +++ b/packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import NoRateAvailableCard from '.' const meta: Meta = { diff --git a/packages/design-system/lib/components/RateCard/Points/Points.stories.tsx b/packages/design-system/lib/components/RateCard/Points/Points.stories.tsx index a34818575..8315abdf8 100644 --- a/packages/design-system/lib/components/RateCard/Points/Points.stories.tsx +++ b/packages/design-system/lib/components/RateCard/Points/Points.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import PointsRateCard from '.' diff --git a/packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx b/packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx index 5b5d5cae3..647a07c40 100644 --- a/packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx +++ b/packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import RegularRateCard from '.' const meta: Meta = { diff --git a/packages/design-system/lib/components/Select/Select.stories.tsx b/packages/design-system/lib/components/Select/Select.stories.tsx index 928298c44..dc05e7626 100644 --- a/packages/design-system/lib/components/Select/Select.stories.tsx +++ b/packages/design-system/lib/components/Select/Select.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { Select } from './Select' diff --git a/packages/design-system/lib/components/Typography/Typography.stories.tsx b/packages/design-system/lib/components/Typography/Typography.stories.tsx index 7c3f3d68b..165e3b166 100644 --- a/packages/design-system/lib/components/Typography/Typography.stories.tsx +++ b/packages/design-system/lib/components/Typography/Typography.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' +import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { Typography } from './Typography.tsx' diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 516abe1fe..8b1dd028b 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -10,11 +10,13 @@ "./Body": "./lib/components/Body/index.tsx", "./Button": "./lib/components/Button/index.tsx", "./ButtonLink": "./lib/components/ButtonLink/index.tsx", + "./CampaignRateCard": "./lib/components/RateCard/Campaign/index.tsx", "./Caption": "./lib/components/Caption/index.tsx", "./Card": "./lib/components/Card/index.tsx", "./ChipButton": "./lib/components/ChipButton/index.tsx", "./ChipLink": "./lib/components/ChipLink/index.tsx", "./Chips": "./lib/components/Chips/index.tsx", + "./CodeRateCard": "./lib/components/RateCard/Code/index.tsx", "./DeprecatedSelect": "./lib/components/DeprecatedSelect/index.tsx", "./Divider": "./lib/components/Divider/index.tsx", "./Footnote": "./lib/components/Footnote/index.tsx", @@ -24,48 +26,27 @@ "./Form/ErrorMessage": "./lib/components/Form/ErrorMessage/index.tsx", "./Form/Phone": "./lib/components/Form/Phone/index.tsx", "./Form/RadioCard": "./lib/components/Form/RadioCard/index.tsx", - "./IconChip": "./lib/components/IconChip/index.tsx", - "./Image": "./lib/components/Image.tsx", - "./ImageContainer": "./lib/components/ImageContainer/index.tsx", - "./ImageFallback": "./lib/components/ImageFallback/index.tsx", - "./ImageGallery": "./lib/components/ImageGallery/index.tsx", - "./Input": "./lib/components/Input/index.tsx", - "./Label": "./lib/components/Label/index.tsx", - "./Lightbox": "./lib/components/Lightbox/index.tsx", - "./Link": "./lib/components/Link/index.tsx", - "./Modal": "./lib/components/Modal/index.tsx", - "./Modal/ModalContentWithActions": "./lib/components/Modal/ModalContentWithActions/index.tsx", - "./OldDSButton": "./lib/components/OldDSButton/index.tsx", - "./OpeningHours": "./lib/components/OpeningHours/index.tsx", - "./Select": "./lib/components/Select/index.tsx", - "./SkeletonShimmer": "./lib/components/SkeletonShimmer/index.tsx", - "./SidePeek": "./lib/components/SidePeek/index.tsx", - "./SidePeek/SidePeekProvider": "./lib/components/SidePeek/SidePeekContext/SidePeekProvider.tsx", - "./StaticMap": "./lib/components/StaticMap/index.tsx", - "./Subtitle": "./lib/components/Subtitle/index.tsx", - "./Switch": "./lib/components/Switch/index.tsx", - "./Table": "./lib/components/Table/index.tsx", - "./Title": "./lib/components/Title/index.tsx", - "./Tooltip": "./lib/components/Tooltip/index.tsx", - "./Typography": "./lib/components/Typography/index.tsx", - "./RegularRateCard": "./lib/components/RateCard/Regular/index.tsx", - "./CampaignRateCard": "./lib/components/RateCard/Campaign/index.tsx", - "./CodeRateCard": "./lib/components/RateCard/Code/index.tsx", - "./ParkingInformation": "./lib/components/ParkingInformation/index.tsx", - "./PointsRateCard": "./lib/components/RateCard/Points/index.tsx", - "./Preamble": "./lib/components/Preamble/index.tsx", - "./NoRateAvailableCard": "./lib/components/RateCard/NoRateAvailable/index.tsx", "./IconButton": "./lib/components/IconButton/index.tsx", + "./IconChip": "./lib/components/IconChip/index.tsx", "./Icons": "./lib/components/Icons/index.tsx", - "./Icons/IconByCSSelect": "./lib/components/Icons/IconByCSSelect.tsx", - "./Icons/IconByIconName": "./lib/components/Icons/IconByIconName.tsx", - "./Icons/IllustrationByIconName": "./lib/components/Icons/IllustrationByIconName.ts", - "./Icons/iconName": "./lib/components/Icons/iconName.ts", "./Icons/BathroomCabinetIcon": "./lib/components/Icons/Nucleo/Amenities_Facilities/bathroom-cabinet-2.tsx", + "./Icons/BedBunkExtraIcon": "./lib/components/Icons/Illustrations/BedBunkExtra.tsx", + "./Icons/BedBunkIcon": "./lib/components/Icons/Illustrations/BedBunk.tsx", + "./Icons/BedGenericIcon": "./lib/components/Icons/Illustrations/BedGeneric.tsx", "./Icons/BedHotelIcon": "./lib/components/Icons/Customised/Amenities_Facilities/BedHotel.tsx", "./Icons/BedIcon": "./lib/components/Icons/Illustrations/Bed.tsx", + "./Icons/BedKingIcon": "./lib/components/Icons/Illustrations/BedKing.tsx", + "./Icons/BedPullOutExtraIcon": "./lib/components/Icons/Illustrations/BedPullOutExtra.tsx", + "./Icons/BedPullOutIcon": "./lib/components/Icons/Illustrations/BedPullOut.tsx", + "./Icons/BedQueenIcon": "./lib/components/Icons/Illustrations/BedQueen.tsx", + "./Icons/BedSingleIcon": "./lib/components/Icons/Illustrations/BedSingle.tsx", + "./Icons/BedSofaExtraIcon": "./lib/components/Icons/Illustrations/BedSofaExtra.tsx", + "./Icons/BedSofaIcon": "./lib/components/Icons/Illustrations/BedSofa.tsx", + "./Icons/BedTwinIcon": "./lib/components/Icons/Illustrations/BedTwin.tsx", + "./Icons/BedWallExtraIcon": "./lib/components/Icons/Illustrations/BedWallExtra.tsx", "./Icons/BouquetIcon": "./lib/components/Icons/Nucleo/Benefits/bouquet.tsx", "./Icons/BowlingPinsIcon": "./lib/components/Icons/Nucleo/Experiences/bowling-pins.tsx", + "./Icons/BreakfastBuffetIcon": "./lib/components/Icons/Illustrations/BreakfastBuffet.tsx", "./Icons/BunkBedIcon": "./lib/components/Icons/Customised/Amenities_Facilities/MdiBunkBedOutline.tsx", "./Icons/ChipsIcon": "./lib/components/Icons/Nucleo/Food/chips-3.tsx", "./Icons/CoinIcon": "./lib/components/Icons/Illustrations/Coin.tsx", @@ -77,22 +58,27 @@ "./Icons/CutleryTwoIcon": "./lib/components/Icons/Illustrations/CutleryTwo.tsx", "./Icons/DiamondAddIcon": "./lib/components/Icons/Customised/Benefits/DiamondAdd.tsx", "./Icons/DiscountIcon": "./lib/components/Icons/Nucleo/Benefits/discount-2-2.tsx", - "./Icons/FilledDiscountIcon": "./lib/components/Icons/Nucleo/Benefits/FilledDiscount.tsx", - "./Icons/FacilityIcon": "./lib/components/Icons/FacilityIcon.tsx", "./Icons/DoorIcon": "./lib/components/Icons/Nucleo/Amenities_Facilities/door-2.tsx", "./Icons/DowntownCamperIcon": "./lib/components/Icons/Logos/DowntownCamper.tsx", "./Icons/FacebookIcon": "./lib/components/Icons/Customised/Socials/Facebook.tsx", + "./Icons/FacilityIcon": "./lib/components/Icons/FacilityIcon.tsx", + "./Icons/FilledDiscountIcon": "./lib/components/Icons/Nucleo/Benefits/FilledDiscount.tsx", "./Icons/FootStoolIcon": "./lib/components/Icons/Customised/Amenities_Facilities/FootStool.tsx", "./Icons/GiftOpenIcon": "./lib/components/Icons/Illustrations/GiftOpen.tsx", "./Icons/GrandHotelOsloIcon": "./lib/components/Icons/Logos/GrandHotelOslo.tsx", - "./Icons/HairdryerIcon": "./lib/components/Icons/Customised/Amenities_Facilities/Hairdryer.tsx", "./Icons/HairdresserIcon": "./lib/components/Icons/Nucleo/Amenities_Facilities/hairdresser-1.tsx", + "./Icons/HairdryerIcon": "./lib/components/Icons/Customised/Amenities_Facilities/Hairdryer.tsx", "./Icons/HandKeyIcon": "./lib/components/Icons/Illustrations/HandKey.tsx", "./Icons/HandSoapIcon": "./lib/components/Icons/Customised/Amenities_Facilities/HandSoap.tsx", "./Icons/HaymarketIcon": "./lib/components/Icons/Logos/Haymarket.tsx", + "./Icons/HotelLogoIcon": "./lib/components/Icons/Logos/index.tsx", "./Icons/HotelNightIcon": "./lib/components/Icons/Illustrations/HotelNight.tsx", "./Icons/HotelNorgeIcon": "./lib/components/Icons/Logos/HotelNorge.tsx", "./Icons/IceMachineIcon": "./lib/components/Icons/Customised/Amenities_Facilities/IceMachine.tsx", + "./Icons/IconByCSSelect": "./lib/components/Icons/IconByCSSelect.tsx", + "./Icons/IconByIconName": "./lib/components/Icons/IconByIconName.tsx", + "./Icons/iconName": "./lib/components/Icons/iconName.ts", + "./Icons/IllustrationByIconName": "./lib/components/Icons/IllustrationByIconName.ts", "./Icons/InstagramIcon": "./lib/components/Icons/Customised/Socials/Instagram.tsx", "./Icons/KidsIcon": "./lib/components/Icons/Illustrations/Kids.tsx", "./Icons/KidsMocktailIcon": "./lib/components/Icons/Illustrations/KidsMocktail.tsx", @@ -104,22 +90,8 @@ "./Icons/MinimizeIcon": "./lib/components/Icons/Customised/UI/Minimize.tsx", "./Icons/MirrorIcon": "./lib/components/Icons/Customised/Amenities_Facilities/Mirror.tsx", "./Icons/MoneyHandIcon": "./lib/components/Icons/Illustrations/MoneyHand.tsx", - "./Icons/BedBunkExtraIcon": "./lib/components/Icons/Illustrations/BedBunkExtra.tsx", - "./Icons/BedGenericIcon": "./lib/components/Icons/Illustrations/BedGeneric.tsx", - "./Icons/BedBunkIcon": "./lib/components/Icons/Illustrations/BedBunk.tsx", - "./Icons/HotelLogoIcon": "./lib/components/Icons/Logos/index.tsx", - "./Icons/BedKingIcon": "./lib/components/Icons/Illustrations/BedKing.tsx", - "./Icons/BedQueenIcon": "./lib/components/Icons/Illustrations/BedQueen.tsx", - "./Icons/BedSofaIcon": "./lib/components/Icons/Illustrations/BedSofa.tsx", - "./Icons/BedSofaExtraIcon": "./lib/components/Icons/Illustrations/BedSofaExtra.tsx", - "./Icons/BedTwinIcon": "./lib/components/Icons/Illustrations/BedTwin.tsx", - "./Icons/BedWallExtraIcon": "./lib/components/Icons/Illustrations/BedWallExtra.tsx", - "./Icons/BreakfastBuffetIcon": "./lib/components/Icons/Illustrations/BreakfastBuffet.tsx", - "./Icons/NoBreakfastBuffetIcon": "./lib/components/Icons/Illustrations/NoBreakfastBuffet.tsx", - "./Icons/BedSingleIcon": "./lib/components/Icons/Illustrations/BedSingle.tsx", - "./Icons/BedPullOutIcon": "./lib/components/Icons/Illustrations/BedPullOut.tsx", - "./Icons/BedPullOutExtraIcon": "./lib/components/Icons/Illustrations/BedPullOutExtra.tsx", "./Icons/MovingBedsIcon": "./lib/components/Icons/Customised/Amenities_Facilities/MovingBeds.tsx", + "./Icons/NoBreakfastBuffetIcon": "./lib/components/Icons/Illustrations/NoBreakfastBuffet.tsx", "./Icons/PalmTreeIcon": "./lib/components/Icons/Nucleo/Experiences/palm-tree-2.tsx", "./Icons/PopcornIcon": "./lib/components/Icons/Nucleo/Food/popcorn-2.tsx", "./Icons/RecordPlayerIcon": "./lib/components/Icons/Nucleo/Amenities_Facilities/record-player-3.tsx", @@ -139,6 +111,35 @@ "./Icons/WardIcon": "./lib/components/Icons/Customised/Amenities_Facilities/Ward.tsx", "./Icons/WindowNotAvailableIcon": "./lib/components/Icons/Customised/Amenities_Facilities/WindowNotAvailable.tsx", "./Icons/WoodFloorIcon": "./lib/components/Icons/Customised/Amenities_Facilities/WoodFloor.tsx", + "./Image": "./lib/components/Image.tsx", + "./ImageContainer": "./lib/components/ImageContainer/index.tsx", + "./ImageFallback": "./lib/components/ImageFallback/index.tsx", + "./ImageGallery": "./lib/components/ImageGallery/index.tsx", + "./Input": "./lib/components/Input/index.tsx", + "./JsonToHtml": "./lib/components/JsonToHtml/JsonToHtml.tsx", + "./Label": "./lib/components/Label/index.tsx", + "./Lightbox": "./lib/components/Lightbox/index.tsx", + "./Link": "./lib/components/Link/index.tsx", + "./Modal": "./lib/components/Modal/index.tsx", + "./Modal/ModalContentWithActions": "./lib/components/Modal/ModalContentWithActions/index.tsx", + "./NoRateAvailableCard": "./lib/components/RateCard/NoRateAvailable/index.tsx", + "./OldDSButton": "./lib/components/OldDSButton/index.tsx", + "./OpeningHours": "./lib/components/OpeningHours/index.tsx", + "./ParkingInformation": "./lib/components/ParkingInformation/index.tsx", + "./PointsRateCard": "./lib/components/RateCard/Points/index.tsx", + "./Preamble": "./lib/components/Preamble/index.tsx", + "./RegularRateCard": "./lib/components/RateCard/Regular/index.tsx", + "./Select": "./lib/components/Select/index.tsx", + "./SidePeek": "./lib/components/SidePeek/index.tsx", + "./SidePeek/SidePeekProvider": "./lib/components/SidePeek/SidePeekContext/SidePeekProvider.tsx", + "./SkeletonShimmer": "./lib/components/SkeletonShimmer/index.tsx", + "./StaticMap": "./lib/components/StaticMap/index.tsx", + "./Subtitle": "./lib/components/Subtitle/index.tsx", + "./Switch": "./lib/components/Switch/index.tsx", + "./Table": "./lib/components/Table/index.tsx", + "./Title": "./lib/components/Title/index.tsx", + "./Tooltip": "./lib/components/Tooltip/index.tsx", + "./Typography": "./lib/components/Typography/index.tsx", "./style.css": "./lib/style.css", "./base.css": "./lib/base.css", "./globals.css": "./lib/globals.css", @@ -198,7 +199,7 @@ "@storybook/addon-links": "^9.1.2", "@storybook/addon-themes": "^9.1.2", "@storybook/addon-vitest": "^9.1.2", - "@storybook/react-vite": "^9.1.2", + "@storybook/nextjs-vite": "^9.1.2", "@types/css-modules": "^1.0.5", "@types/node": "^20.17.17", "@types/react": "^19", diff --git a/yarn.lock b/yarn.lock index 3425080c3..eb4d25570 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2795,6 +2795,13 @@ __metadata: languageName: node linkType: hard +"@next/env@npm:^15.0.3": + version: 15.4.6 + resolution: "@next/env@npm:15.4.6" + checksum: 10c0/039a757f5e083f44bd71268d804e86064233b023c72930ab45a3a46ba651c5bd474096550ca140b9ec00338c4013afbba7972c09eba23082005d7e9086a4eb67 + languageName: node + linkType: hard + "@next/eslint-plugin-next@npm:15.3.2": version: 15.3.2 resolution: "@next/eslint-plugin-next@npm:15.3.2" @@ -6170,7 +6177,7 @@ __metadata: "@storybook/addon-links": "npm:^9.1.2" "@storybook/addon-themes": "npm:^9.1.2" "@storybook/addon-vitest": "npm:^9.1.2" - "@storybook/react-vite": "npm:^9.1.2" + "@storybook/nextjs-vite": "npm:^9.1.2" "@types/css-modules": "npm:^1.0.5" "@types/node": "npm:^20.17.17" "@types/react": "npm:^19" @@ -7049,6 +7056,28 @@ __metadata: languageName: node linkType: hard +"@storybook/nextjs-vite@npm:^9.1.2": + version: 9.1.2 + resolution: "@storybook/nextjs-vite@npm:9.1.2" + dependencies: + "@storybook/builder-vite": "npm:9.1.2" + "@storybook/react": "npm:9.1.2" + "@storybook/react-vite": "npm:9.1.2" + styled-jsx: "npm:5.1.6" + vite-plugin-storybook-nextjs: "npm:^2.0.5" + peerDependencies: + next: ^14.1.0 || ^15.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + storybook: ^9.1.2 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/e711b8370ccfd14f9a6dbdfa1c5adfbd33fec63357301cc44f1dcd546451bfd94f266875af9a2a7e3268d4342d623f28de4daf1214973bdfac63a7491a639622 + languageName: node + linkType: hard + "@storybook/react-dom-shim@npm:9.1.2": version: 9.1.2 resolution: "@storybook/react-dom-shim@npm:9.1.2" @@ -7060,7 +7089,7 @@ __metadata: languageName: node linkType: hard -"@storybook/react-vite@npm:^9.1.2": +"@storybook/react-vite@npm:9.1.2": version: 9.1.2 resolution: "@storybook/react-vite@npm:9.1.2" dependencies: @@ -13260,6 +13289,15 @@ __metadata: languageName: node linkType: hard +"image-size@npm:^2.0.0": + version: 2.0.2 + resolution: "image-size@npm:2.0.2" + bin: + image-size: bin/image-size.js + checksum: 10c0/f09dd0f7cf8511cd20e4f756bdb5a7cb6d2240de3323f41bde266bed8373392a293892bf12e907e2995f52833fd88dd27cf6b1a52ab93968afc716cb78cd7b79 + languageName: node + linkType: hard + "immer@npm:10.1.1": version: 10.1.1 resolution: "immer@npm:10.1.1" @@ -15066,7 +15104,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.0, magic-string@npm:^0.30.17, magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": +"magic-string@npm:^0.30.0, magic-string@npm:^0.30.11, magic-string@npm:^0.30.17, magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": version: 0.30.17 resolution: "magic-string@npm:0.30.17" dependencies: @@ -15444,6 +15482,13 @@ __metadata: languageName: node linkType: hard +"module-alias@npm:^2.2.3": + version: 2.2.3 + resolution: "module-alias@npm:2.2.3" + checksum: 10c0/47dc5b6d04f6e7df0ff330ca9b2a37c688a682ed661e9432b0b327e1e6c43eedad052151b8d50d6beea8b924828d2a92fa4625c18d651bf2d93d8f03aa0172fa + languageName: node + linkType: hard + "module-details-from-path@npm:^1.0.3": version: 1.0.3 resolution: "module-details-from-path@npm:1.0.3" @@ -20240,6 +20285,24 @@ __metadata: languageName: node linkType: hard +"vite-plugin-storybook-nextjs@npm:^2.0.5": + version: 2.0.5 + resolution: "vite-plugin-storybook-nextjs@npm:2.0.5" + dependencies: + "@next/env": "npm:^15.0.3" + image-size: "npm:^2.0.0" + magic-string: "npm:^0.30.11" + module-alias: "npm:^2.2.3" + ts-dedent: "npm:^2.2.0" + vite-tsconfig-paths: "npm:^5.1.4" + peerDependencies: + next: ^14.1.0 || ^15.0.0 + storybook: ^0.0.0-0 || ^9.0.0 || ^9.1.0-0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + checksum: 10c0/ee308c836c4380f9c9e3f51a7eab532eb648248cb8b78866032ed0e33af2cde3457e536e20c74546c46141d0b5ea9809ec13b76db299b8bd59468285228c3b1b + languageName: node + linkType: hard + "vite-tsconfig-paths@npm:^5.1.4": version: 5.1.4 resolution: "vite-tsconfig-paths@npm:5.1.4"