diff --git a/apps/docs/src/content/04-components/overlays/light-box/examples/gallery.tsx b/apps/docs/src/content/04-components/overlays/light-box/examples/gallery.tsx new file mode 100644 index 0000000000..fa025712fd --- /dev/null +++ b/apps/docs/src/content/04-components/overlays/light-box/examples/gallery.tsx @@ -0,0 +1,49 @@ +import { + Button, + Flex, + Image, + LightBox, + LightBoxTrigger, + ActionGroup, + LightBoxGallery, + LightBoxGalleryItem, + IconDownload, +} from "@mittwald/flow-react-components"; + +export default () => { + const images = [ + "https://mittwald.github.io/flow/assets/mittwald_logo_rgb.jpg", + "https://cdn.shopify.com/s/files/1/2022/6883/products/IMG_2002_250x250@2x.JPG?v=1538235544", + ]; + + return ( + + {images.map((src, index) => ( + + + + + + + {images.map((src) => ( + + + + + + + + + ))} + + + + ))} + + ); +}; diff --git a/apps/docs/src/content/04-components/overlays/light-box/overview.mdx b/apps/docs/src/content/04-components/overlays/light-box/overview.mdx index c1b83dde24..e4862fe4e7 100644 --- a/apps/docs/src/content/04-components/overlays/light-box/overview.mdx +++ b/apps/docs/src/content/04-components/overlays/light-box/overview.mdx @@ -37,3 +37,14 @@ Darstellung von Inhalten mit großer vertikaler Ausdehnung, wie z. B. mehrseitigen PDFs. + +--- + +# Mit Galerie + +Innerhalb der LightBox kann eine `LightBoxGallery` verwendet werden. Diese kann +mit `LightBoxGalleryItems` gefüllt werden, welche die Platzierung von +[Images](/04-components/content/image/overview) und +[ActionGroups](/04-components/actions/action-group/overview) unterstützen. + + diff --git a/packages/components/src/components/LightBox/LightBox.module.scss b/packages/components/src/components/LightBox/LightBox.module.scss index c559db285e..837a37b517 100644 --- a/packages/components/src/components/LightBox/LightBox.module.scss +++ b/packages/components/src/components/LightBox/LightBox.module.scss @@ -54,4 +54,14 @@ .actions { padding-left: var(--light-box--spacing); } + + .gallery { + width: var(--light-box--max-width); + } + + &:has(.gallery) { + .actions { + display: none; + } + } } diff --git a/packages/components/src/components/LightBox/LightBox.tsx b/packages/components/src/components/LightBox/LightBox.tsx index 78bc1a6053..7c2fa4f45d 100644 --- a/packages/components/src/components/LightBox/LightBox.tsx +++ b/packages/components/src/components/LightBox/LightBox.tsx @@ -15,6 +15,8 @@ import styles from "./LightBox.module.scss"; import DivView from "@/views/DivView"; import ButtonView from "@/views/ButtonView"; import { UiComponentTunnelExit } from "../UiComponentTunnel/UiComponentTunnelExit"; +import { useLocalizedStringFormatter } from "react-aria"; +import locales from "./locales/*.locale.json"; export interface LightBoxProps extends PropsWithChildren, FlowComponentProps, PropsWithClassName { @@ -52,6 +54,9 @@ export const LightBox = flowComponent("LightBox", (props) => { component: "LightBox", }, }, + LightBoxGallery: { + className: styles.gallery, + }, }; const controllerFromContext = useOverlayController("LightBox", { @@ -60,6 +65,8 @@ export const LightBox = flowComponent("LightBox", (props) => { const controller = controllerFromProps ?? controllerFromContext; + const stringFormatter = useLocalizedStringFormatter(locales, "LightBox"); + return ( { color="light-static" variant="solid" onPress={() => controller.close()} + aria-label={stringFormatter.format("close")} > diff --git a/packages/components/src/components/LightBox/components/LightBoxGallery/LightBoxGallery.module.scss b/packages/components/src/components/LightBox/components/LightBoxGallery/LightBoxGallery.module.scss new file mode 100644 index 0000000000..e1274eeec1 --- /dev/null +++ b/packages/components/src/components/LightBox/components/LightBoxGallery/LightBoxGallery.module.scss @@ -0,0 +1,135 @@ +.gallery { + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + + --button-size: calc( + var(--icon--size--m) + 2 * var(--button--padding-icon-only) + ); + --button-size-plus-spacing: calc( + var(--button-size) + var(--light-box--spacing) + ); + --indicator-height: calc(var(--light-box--spacing) + var(--icon--size--m)); + + .content { + display: flex; + flex-direction: column; + height: var(--light-box--max-height); + width: 100%; + justify-content: center; + } + + .galleryItem { + position: relative; + margin: 0 auto; + user-select: none; + } + + .actions { + position: absolute; + top: 0; + right: calc(var(--button-size-plus-spacing) * -1); + display: flex; + flex-direction: column; + row-gap: var(--light-box--spacing); + } + + .actionGroup { + flex-grow: 0; + flex-direction: column; + row-gap: var(--light-box--spacing); + } + + .image { + animation: fade-in var(--transition--duration--default) ease-in forwards; + height: 100%; + width: 100%; + pointer-events: none; + } + + @keyframes fade-in { + from { + opacity: 0; + } + + to { + opacity: 1; + } + } + + .indicators { + display: flex; + justify-content: center; + column-gap: var(--light-box--indicator-spacing); + color: var(--light-box--content-color); + } + + .indicator { + display: block; + width: var(--light-box--indicator-size); + height: var(--light-box--indicator-size); + border: var(--light-box--indicator-border-width) + var(--light-box--indicator-border-style) var(--light-box--content-color); + border-radius: var(--light-box--indicator-corner-radius); + + &.current { + background-color: var(--light-box--content-color); + } + } +} + +@media (min-width: 768px) { + .content { + padding-inline: calc( + var(--button-size-plus-spacing) + var(--light-box--spacing) + ); + padding-bottom: var(--indicator-height); + } + + .galleryItem { + max-height: calc(var(--light-box--max-height) - var(--indicator-height)); + } + + .indicators { + position: absolute; + bottom: calc(var(--light-box--spacing) / 2); + inset-inline: 0; + } + + .previousButton, + .nextButton { + position: absolute; + top: calc(50% - var(--button-size) / 2); + } + + .previousButton { + left: 0; + } + + .nextButton { + right: 0; + } +} + +@media (max-width: 768px) { + .content { + padding-inline: var(--button-size-plus-spacing); + padding-bottom: var(--button-size-plus-spacing); + } + + .galleryItem { + max-height: calc( + var(--light-box--max-height) - var(--button-size-plus-spacing) + ); + } + + .controls { + display: flex; + position: absolute; + bottom: 0; + inset-inline: 0; + justify-content: space-between; + align-items: center; + } +} diff --git a/packages/components/src/components/LightBox/components/LightBoxGallery/LightBoxGallery.tsx b/packages/components/src/components/LightBox/components/LightBoxGallery/LightBoxGallery.tsx new file mode 100644 index 0000000000..bf22c537f1 --- /dev/null +++ b/packages/components/src/components/LightBox/components/LightBoxGallery/LightBoxGallery.tsx @@ -0,0 +1,113 @@ +import { flowComponent } from "@/lib/componentFactory/flowComponent"; +import React, { type ReactNode, useRef, useState } from "react"; +import { + IconChevronLeft, + IconChevronRight, +} from "@/components/Icon/components/icons"; +import styles from "./LightBoxGallery.module.scss"; +import type { PropsWithClassName } from "@/lib/types/props"; +import clsx from "clsx"; +import { useLocalizedStringFormatter } from "react-aria"; +import locales from "../../locales/*.locale.json"; +import Button from "@/components/Button"; + +export interface LightBoxGalleryProps extends PropsWithClassName { + children: ReactNode[]; + defaultIndex?: number; +} + +/** @flr-generate all */ +export const LightBoxGallery = flowComponent("LightBoxGallery", (props) => { + const { children, className, defaultIndex = 0 } = props; + + const [currentIndex, setIndex] = useState(defaultIndex); + + const count = React.Children.count(children); + + const paginate = (direction: number) => { + setIndex((prev: number) => (prev + direction + count) % count); + }; + + const pointerStartX = useRef(null); + const SWIPE_THRESHOLD = 50; + + const handlePointerDown = (e: React.PointerEvent) => { + if (!e.isPrimary) return; + pointerStartX.current = e.clientX; + }; + + const handlePointerUp = (e: React.PointerEvent) => { + if (pointerStartX.current === null) return; + + const distance = pointerStartX.current - e.clientX; + + if (Math.abs(distance) > SWIPE_THRESHOLD) { + paginate(distance > 0 ? 1 : -1); + } + + pointerStartX.current = null; + }; + + const handlePointerCancel = () => { + pointerStartX.current = null; + }; + + const stringFormatter = useLocalizedStringFormatter(locales, "LightBox"); + + const indicators = Array(count) + .fill("") + .map((_, index) => ( + + )); + + return ( + + + + {children[currentIndex]} + + + + paginate(-1)} + color="light-static" + className={styles.previousButton} + > + + + + {indicators} + + paginate(1)} + color="light-static" + className={styles.nextButton} + > + + + + + + ); +}); + +export default LightBoxGallery; diff --git a/packages/components/src/components/LightBox/components/LightBoxGallery/index.ts b/packages/components/src/components/LightBox/components/LightBoxGallery/index.ts new file mode 100644 index 0000000000..73945c4dd5 --- /dev/null +++ b/packages/components/src/components/LightBox/components/LightBoxGallery/index.ts @@ -0,0 +1 @@ +export { type LightBoxGalleryProps, LightBoxGallery } from "./LightBoxGallery"; diff --git a/packages/components/src/components/LightBox/components/LightBoxGallery/view.ts b/packages/components/src/components/LightBox/components/LightBoxGallery/view.ts new file mode 100644 index 0000000000..b1f261b8f9 --- /dev/null +++ b/packages/components/src/components/LightBox/components/LightBoxGallery/view.ts @@ -0,0 +1,10 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +import type { LightBoxGallery } from "./LightBoxGallery"; +import type { ViewComponent } from "@/lib/viewComponentContext"; + +declare global { + interface FlowViewComponents { + LightBoxGallery: ViewComponent; + } +} diff --git a/packages/components/src/components/LightBox/components/LightBoxGalleryItem/LightBoxGalleryItem.tsx b/packages/components/src/components/LightBox/components/LightBoxGalleryItem/LightBoxGalleryItem.tsx new file mode 100644 index 0000000000..5cdd726b59 --- /dev/null +++ b/packages/components/src/components/LightBox/components/LightBoxGalleryItem/LightBoxGalleryItem.tsx @@ -0,0 +1,52 @@ +import { flowComponent } from "@/lib/componentFactory/flowComponent"; +import styles from "@/components/LightBox/components/LightBoxGallery/LightBoxGallery.module.scss"; +import { type PropsContext, PropsContextProvider } from "@/lib/propsContext"; +import { IconClose } from "@/components/Icon/components/icons"; +import { useOverlayController } from "@/lib/hooks"; +import { useLocalizedStringFormatter } from "react-aria"; +import locales from "../../locales/*.locale.json"; +import { Button } from "@/components/Button"; +import type { PropsWithChildren } from "react"; +import { UiComponentTunnelExit } from "@/components/UiComponentTunnel/UiComponentTunnelExit"; + +export type LightBoxGalleryItemProps = PropsWithChildren; + +/** @flr-generate all */ +export const LightBoxGalleryItem = flowComponent( + "LightBoxGalleryItem", + (props) => { + const { children } = props; + + const controller = useOverlayController("Modal"); + + const propsContext: PropsContext = { + ActionGroup: { + className: styles.actionGroup, + Button: { color: "light-static" }, + tunnel: { id: "actionGroup", component: "LightBoxGalleryItem" }, + }, + Image: { className: styles.image }, + }; + + const stringFormatter = useLocalizedStringFormatter(locales); + + return ( + + {children} + + controller.close()} + > + + + + + + ); + }, +); diff --git a/packages/components/src/components/LightBox/components/LightBoxGalleryItem/index.ts b/packages/components/src/components/LightBox/components/LightBoxGalleryItem/index.ts new file mode 100644 index 0000000000..0bba996d42 --- /dev/null +++ b/packages/components/src/components/LightBox/components/LightBoxGalleryItem/index.ts @@ -0,0 +1,4 @@ +export { + type LightBoxGalleryItemProps, + LightBoxGalleryItem, +} from "./LightBoxGalleryItem"; diff --git a/packages/components/src/components/LightBox/components/LightBoxGalleryItem/view.ts b/packages/components/src/components/LightBox/components/LightBoxGalleryItem/view.ts new file mode 100644 index 0000000000..954fb21eb2 --- /dev/null +++ b/packages/components/src/components/LightBox/components/LightBoxGalleryItem/view.ts @@ -0,0 +1,10 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +import type { LightBoxGalleryItem } from "./LightBoxGalleryItem"; +import type { ViewComponent } from "@/lib/viewComponentContext"; + +declare global { + interface FlowViewComponents { + LightBoxGalleryItem: ViewComponent; + } +} diff --git a/packages/components/src/components/LightBox/index.ts b/packages/components/src/components/LightBox/index.ts index fc3da273d0..dc7799e22f 100644 --- a/packages/components/src/components/LightBox/index.ts +++ b/packages/components/src/components/LightBox/index.ts @@ -1,3 +1,5 @@ export * from "./components/LightBoxTrigger"; +export * from "./components/LightBoxGallery"; +export * from "./components/LightBoxGalleryItem"; export { type LightBoxProps, LightBox } from "./LightBox"; export { default } from "./LightBox"; diff --git a/packages/components/src/components/LightBox/locales/de-DE.locale.json b/packages/components/src/components/LightBox/locales/de-DE.locale.json new file mode 100644 index 0000000000..30521fc301 --- /dev/null +++ b/packages/components/src/components/LightBox/locales/de-DE.locale.json @@ -0,0 +1,6 @@ +{ + "close": "Schließen", + "indicator": "{current} von {count}", + "next": "Nächstes", + "previous": "Vorheriges" +} diff --git a/packages/components/src/components/LightBox/locales/en-US.locale.json b/packages/components/src/components/LightBox/locales/en-US.locale.json new file mode 100644 index 0000000000..011fa1b3c8 --- /dev/null +++ b/packages/components/src/components/LightBox/locales/en-US.locale.json @@ -0,0 +1,6 @@ +{ + "close": "Close", + "indicator": "{current} of {count}", + "next": "Next", + "previous": "Previous" +} diff --git a/packages/components/src/components/LightBox/stories/Default.stories.tsx b/packages/components/src/components/LightBox/stories/Default.stories.tsx index c4725b623a..b35f6dfac1 100644 --- a/packages/components/src/components/LightBox/stories/Default.stories.tsx +++ b/packages/components/src/components/LightBox/stories/Default.stories.tsx @@ -2,13 +2,24 @@ import type { Meta, StoryObj } from "@storybook/react"; import React from "react"; import Button from "@/components/Button"; import { ActionGroup } from "@/components/ActionGroup"; -import { LightBox } from "@/components/LightBox"; +import { + LightBoxGallery, + LightBoxGalleryItem, + LightBox, +} from "@/components/LightBox"; import LightBoxTrigger from "@/components/LightBox/components/LightBoxTrigger"; import { Image } from "@/components/Image"; import { dummyText } from "@/lib/dev/dummyText"; import { IconDelete, IconDownload } from "@/components/Icon/components/icons"; import { useOverlayController } from "@/lib/controller"; import svg from "./test.svg"; +import { Flex } from "@/components/Flex"; + +const images = [ + dummyText.imageSrc, + "https://mittwald.github.io/flow/assets/mittwald_logo_rgb.jpg", + svg, +]; const meta: Meta = { title: "Overlays/LightBox", @@ -91,3 +102,31 @@ export const WithSvg: Story = { ), }; + +export const WithGallery: Story = { + render: () => ( + + {images.map((src, index) => ( + + + + + + + {images.map((src) => ( + + + + + + + + + ))} + + + + ))} + + ), +}; diff --git a/packages/components/src/components/LightBox/view.ts b/packages/components/src/components/LightBox/view.ts new file mode 100644 index 0000000000..e39634ccb1 --- /dev/null +++ b/packages/components/src/components/LightBox/view.ts @@ -0,0 +1,10 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +import type { LightBox } from "./LightBox"; +import type { ViewComponent } from "@/lib/viewComponentContext"; + +declare global { + interface FlowViewComponents { + LightBox: ViewComponent; + } +} diff --git a/packages/components/src/components/Notification/Notification.module.scss b/packages/components/src/components/Notification/Notification.module.scss index 8d61397fed..f81f0ec09e 100644 --- a/packages/components/src/components/Notification/Notification.module.scss +++ b/packages/components/src/components/Notification/Notification.module.scss @@ -27,12 +27,12 @@ } .heading { - --button-width: calc( + --button-size: calc( var(--button--line-height-s) + 2 * var(--button--padding-s-x) ); padding-inline-end: calc( - var(--button-width) + var(--heading--icon-to-text-spacing) + var(--button-size) + var(--heading--icon-to-text-spacing) ); .icon { diff --git a/packages/components/src/components/propTypes/index.ts b/packages/components/src/components/propTypes/index.ts index 1bed1820be..1843e44761 100644 --- a/packages/components/src/components/propTypes/index.ts +++ b/packages/components/src/components/propTypes/index.ts @@ -87,6 +87,10 @@ import type { KbdProps } from "@/components/Kbd/Kbd"; import type { AccordionProps } from "@/components/Accordion"; import type { ChatProps } from "../Chat"; import type { SectionHeaderProps } from "../Section/components/SectionHeader/SectionHeader"; +import type { + LightBoxGalleryItemProps, + LightBoxGalleryProps, +} from "@/components/LightBox"; export * from "./types"; @@ -137,6 +141,8 @@ export interface FlowComponentPropsTypes { Label: LabelProps; LayoutCard: LayoutCardProps; LightBox: LightBoxProps; + LightBoxGallery: LightBoxGalleryProps; + LightBoxGalleryItem: LightBoxGalleryItemProps; Link: LinkProps; List: ListProps; ListItemView: ListItemViewContentProps; @@ -228,6 +234,8 @@ const propsContextSupportingComponentsMap: Record< Label: true, LayoutCard: true, LightBox: true, + LightBoxGallery: true, + LightBoxGalleryItem: true, Link: true, List: true, ListItemView: true, diff --git a/packages/components/src/views/LightBoxGalleryItemView.tsx b/packages/components/src/views/LightBoxGalleryItemView.tsx new file mode 100644 index 0000000000..fde9f4f370 --- /dev/null +++ b/packages/components/src/views/LightBoxGalleryItemView.tsx @@ -0,0 +1,18 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +import React, { memo, type FC, useContext } from "react"; +import { + LightBoxGalleryItem, + type LightBoxGalleryItemProps, +} from "@/components/LightBox/components/LightBoxGalleryItem/LightBoxGalleryItem"; +import { viewComponentContext } from "@/lib/viewComponentContext/viewComponentContext"; + +const LightBoxGalleryItemView: FC = memo((props) => { + const View = + useContext(viewComponentContext)["LightBoxGalleryItem"] ?? + LightBoxGalleryItem; + return ; +}); +LightBoxGalleryItemView.displayName = "LightBoxGalleryItemView"; + +export default LightBoxGalleryItemView; diff --git a/packages/components/src/views/LightBoxGalleryView.tsx b/packages/components/src/views/LightBoxGalleryView.tsx new file mode 100644 index 0000000000..818b4bfe3f --- /dev/null +++ b/packages/components/src/views/LightBoxGalleryView.tsx @@ -0,0 +1,17 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +import React, { memo, type FC, useContext } from "react"; +import { + LightBoxGallery, + type LightBoxGalleryProps, +} from "@/components/LightBox/components/LightBoxGallery/LightBoxGallery"; +import { viewComponentContext } from "@/lib/viewComponentContext/viewComponentContext"; + +const LightBoxGalleryView: FC = memo((props) => { + const View = + useContext(viewComponentContext)["LightBoxGallery"] ?? LightBoxGallery; + return ; +}); +LightBoxGalleryView.displayName = "LightBoxGalleryView"; + +export default LightBoxGalleryView; diff --git a/packages/design-tokens/src/overlays/light-box.yml b/packages/design-tokens/src/overlays/light-box.yml index 8a2cd28787..7668492830 100644 --- a/packages/design-tokens/src/overlays/light-box.yml +++ b/packages/design-tokens/src/overlays/light-box.yml @@ -1,9 +1,21 @@ light-box: overlay-background-color: - value: "{dark.color.600}" + value: "{dark-static.color.600}" max-width: value: "calc(100dvw - {size-px.l})" max-height: value: "calc(100dvh - {size-px.l})" spacing: value: "{size-px.m}" + indicator-spacing: + value: "{size-px.xs}" + indicator-size: + value: "{size-px.m}" + indicator-border-width: + value: "{border-width.200}" + indicator-border-style: + value: "{border-style.default}" + indicator-corner-radius: + value: "{corner-radius.round}" + content-color: + value: "{light-static.color.800}" diff --git a/packages/remote-elements/src/auto-generated/RemoteLightBoxGalleryElement.ts b/packages/remote-elements/src/auto-generated/RemoteLightBoxGalleryElement.ts new file mode 100644 index 0000000000..1810e9a192 --- /dev/null +++ b/packages/remote-elements/src/auto-generated/RemoteLightBoxGalleryElement.ts @@ -0,0 +1,34 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +import { FlowRemoteElement } from "@/lib/FlowRemoteElement"; +import type { LightBoxGalleryProps as RemoteLightBoxGalleryElementProps } from "@mittwald/flow-react-components"; +export type { LightBoxGalleryProps as RemoteLightBoxGalleryElementProps } from "@mittwald/flow-react-components"; + +export class RemoteLightBoxGalleryElement extends FlowRemoteElement { + static override get remoteAttributes() { + return ["style"]; + } + + static override get remoteProperties() { + return { + className: {}, + defaultIndex: {}, + }; + } + + static override get remoteEvents() { + return {}; + } + + static override get remoteSlots() { + return []; + } +} + +declare global { + interface HTMLElementTagNameMap { + "flr-light-box-gallery": InstanceType; + } +} + +customElements.define("flr-light-box-gallery", RemoteLightBoxGalleryElement); diff --git a/packages/remote-elements/src/auto-generated/RemoteLightBoxGalleryItemElement.ts b/packages/remote-elements/src/auto-generated/RemoteLightBoxGalleryItemElement.ts new file mode 100644 index 0000000000..c6d950b42a --- /dev/null +++ b/packages/remote-elements/src/auto-generated/RemoteLightBoxGalleryItemElement.ts @@ -0,0 +1,36 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +import { FlowRemoteElement } from "@/lib/FlowRemoteElement"; +import type { LightBoxGalleryItemProps as RemoteLightBoxGalleryItemElementProps } from "@mittwald/flow-react-components"; +export type { LightBoxGalleryItemProps as RemoteLightBoxGalleryItemElementProps } from "@mittwald/flow-react-components"; + +export class RemoteLightBoxGalleryItemElement extends FlowRemoteElement { + static override get remoteAttributes() { + return ["style"]; + } + + static override get remoteProperties() { + return {}; + } + + static override get remoteEvents() { + return {}; + } + + static override get remoteSlots() { + return []; + } +} + +declare global { + interface HTMLElementTagNameMap { + "flr-light-box-gallery-item": InstanceType< + typeof RemoteLightBoxGalleryItemElement + >; + } +} + +customElements.define( + "flr-light-box-gallery-item", + RemoteLightBoxGalleryItemElement, +); diff --git a/packages/remote-elements/src/auto-generated/index.ts b/packages/remote-elements/src/auto-generated/index.ts index 2b87011467..d35b0395e4 100644 --- a/packages/remote-elements/src/auto-generated/index.ts +++ b/packages/remote-elements/src/auto-generated/index.ts @@ -69,6 +69,8 @@ export * from "./RemoteLabelElement"; export * from "./RemoteLabeledValueElement"; export * from "./RemoteLayoutCardElement"; export * from "./RemoteLegendElement"; +export * from "./RemoteLightBoxGalleryElement"; +export * from "./RemoteLightBoxGalleryItemElement"; export * from "./RemoteLineElement"; export * from "./RemoteLinkElement"; export * from "./RemoteListEmptyViewElement"; diff --git a/packages/remote-react-components/src/auto-generated/LightBoxGallery.ts b/packages/remote-react-components/src/auto-generated/LightBoxGallery.ts new file mode 100644 index 0000000000..234b00e128 --- /dev/null +++ b/packages/remote-react-components/src/auto-generated/LightBoxGallery.ts @@ -0,0 +1,18 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +"use client"; +import createFlowRemoteComponent from "@/components/createFlowRemoteComponent"; +import { RemoteLightBoxGalleryElement } from "@mittwald/flow-remote-elements"; +export { type RemoteLightBoxGalleryElement } from "@mittwald/flow-remote-elements"; + +export const LightBoxGallery = createFlowRemoteComponent( + "flr-light-box-gallery", + "LightBoxGallery", + RemoteLightBoxGalleryElement, + { + slotProps: { + wrapper: "flr-slot-root-wrapper", + }, + eventProps: {}, + }, +); diff --git a/packages/remote-react-components/src/auto-generated/LightBoxGalleryItem.ts b/packages/remote-react-components/src/auto-generated/LightBoxGalleryItem.ts new file mode 100644 index 0000000000..90006231e1 --- /dev/null +++ b/packages/remote-react-components/src/auto-generated/LightBoxGalleryItem.ts @@ -0,0 +1,18 @@ +/* prettier-ignore */ +/* This file is auto-generated with the remote-components-generator */ +"use client"; +import createFlowRemoteComponent from "@/components/createFlowRemoteComponent"; +import { RemoteLightBoxGalleryItemElement } from "@mittwald/flow-remote-elements"; +export { type RemoteLightBoxGalleryItemElement } from "@mittwald/flow-remote-elements"; + +export const LightBoxGalleryItem = createFlowRemoteComponent( + "flr-light-box-gallery-item", + "LightBoxGalleryItem", + RemoteLightBoxGalleryItemElement, + { + slotProps: { + wrapper: "flr-slot-root-wrapper", + }, + eventProps: {}, + }, +); diff --git a/packages/remote-react-components/src/auto-generated/index.ts b/packages/remote-react-components/src/auto-generated/index.ts index c5605d231f..f82347f153 100644 --- a/packages/remote-react-components/src/auto-generated/index.ts +++ b/packages/remote-react-components/src/auto-generated/index.ts @@ -69,6 +69,8 @@ export * from "./Label"; export * from "./LabeledValue"; export * from "./LayoutCard"; export * from "./Legend"; +export * from "./LightBoxGallery"; +export * from "./LightBoxGalleryItem"; export * from "./Line"; export * from "./Link"; export * from "./ListEmptyView"; diff --git a/packages/remote-react-components/src/tests/assets/mittwald_logo_rgb.jpg b/packages/remote-react-components/src/tests/assets/mittwald_logo_rgb.jpg new file mode 100644 index 0000000000..bd91b2383a Binary files /dev/null and b/packages/remote-react-components/src/tests/assets/mittwald_logo_rgb.jpg differ diff --git a/packages/remote-react-components/src/tests/visual/LightBox.browser.test.tsx b/packages/remote-react-components/src/tests/visual/LightBox.browser.test.tsx index c325b6f929..a194a710ea 100644 --- a/packages/remote-react-components/src/tests/visual/LightBox.browser.test.tsx +++ b/packages/remote-react-components/src/tests/visual/LightBox.browser.test.tsx @@ -2,7 +2,9 @@ import { testEnvironments } from "@/tests/lib/environments"; import { test } from "vitest"; import { page } from "vitest/browser"; import gopher from "@/tests/assets/gopher.webp"; +import logo from "@/tests/assets/mittwald_logo_rgb.jpg"; import { userEvent } from "vitest/browser"; +import React from "react"; test.each(testEnvironments)( "LightBox (%s)", @@ -46,3 +48,63 @@ test.each(testEnvironments)( await testScreenshot("LightBox - closed"); }, ); + +test.each(testEnvironments)( + "LightBox with Gallery (%s)", + async ({ + testScreenshot, + render, + components: { + Button, + LightBox, + LightBoxTrigger, + Image, + ActionGroup, + LightBoxGallery, + LightBoxGalleryItem, + IconDownload, + }, + }) => { + await render( + + Trigger + + + + + + + + + + + + + + + + + + + + + , + ); + + const trigger = page.getByTestId("trigger"); + await trigger.click(); + + await testScreenshot("LightBox with Gallery - opened"); + + await userEvent.keyboard("{tab}"); + await userEvent.keyboard("{tab}"); + await userEvent.keyboard("{tab}"); + await userEvent.keyboard("{enter}"); + + await testScreenshot("LightBox with Gallery - previous"); + + await userEvent.keyboard("{escape}"); + + await testScreenshot("LightBox with Gallery - closed"); + }, +); diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-firefox-darwin.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-firefox-darwin.png new file mode 100644 index 0000000000..576db79902 Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-firefox-darwin.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-firefox-linux.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-firefox-linux.png new file mode 100644 index 0000000000..e98ecfe7ed Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-firefox-linux.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-webkit-darwin.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-webkit-darwin.png new file mode 100644 index 0000000000..bfea818a26 Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-webkit-darwin.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-webkit-linux.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-webkit-linux.png new file mode 100644 index 0000000000..6da5c30bdf Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-closed-webkit-linux.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-firefox-darwin.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-firefox-darwin.png new file mode 100644 index 0000000000..b56bd4afd8 Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-firefox-darwin.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-firefox-linux.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-firefox-linux.png new file mode 100644 index 0000000000..248faf8ffa Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-firefox-linux.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-webkit-darwin.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-webkit-darwin.png new file mode 100644 index 0000000000..1cc16f6c33 Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-webkit-darwin.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-webkit-linux.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-webkit-linux.png new file mode 100644 index 0000000000..19f0488b0e Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-opened-webkit-linux.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-firefox-darwin.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-firefox-darwin.png new file mode 100644 index 0000000000..76e8438367 Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-firefox-darwin.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-firefox-linux.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-firefox-linux.png new file mode 100644 index 0000000000..3b348904af Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-firefox-linux.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-webkit-darwin.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-webkit-darwin.png new file mode 100644 index 0000000000..b11e30f239 Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-webkit-darwin.png differ diff --git a/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-webkit-linux.png b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-webkit-linux.png new file mode 100644 index 0000000000..4748620c98 Binary files /dev/null and b/packages/remote-react-components/src/tests/visual/__screenshots__/LightBox.browser.test.tsx/LightBox-with-Gallery-previous-webkit-linux.png differ diff --git a/packages/remote-react-renderer/src/auto-generated/index.ts b/packages/remote-react-renderer/src/auto-generated/index.ts index a59305c4d6..02f21edada 100644 --- a/packages/remote-react-renderer/src/auto-generated/index.ts +++ b/packages/remote-react-renderer/src/auto-generated/index.ts @@ -70,6 +70,8 @@ import { Label as Label } from "@mittwald/flow-react-components"; import { LabeledValue as LabeledValue } from "@mittwald/flow-react-components"; import { LayoutCard as LayoutCard } from "@mittwald/flow-react-components"; import { Legend as Legend } from "@mittwald/flow-react-components"; +import { LightBoxGallery as LightBoxGallery } from "@mittwald/flow-react-components"; +import { LightBoxGalleryItem as LightBoxGalleryItem } from "@mittwald/flow-react-components"; import { Line as Line } from "@mittwald/flow-react-components"; import { Link as Link } from "@mittwald/flow-react-components"; import { EmptyView as ListEmptyView } from "@mittwald/flow-react-components"; @@ -314,6 +316,14 @@ export const flowComponents = { LayoutCard, ), "flr-legend": createFlowRemoteComponentRenderer("Legend", Legend), + "flr-light-box-gallery": createFlowRemoteComponentRenderer( + "LightBoxGallery", + LightBoxGallery, + ), + "flr-light-box-gallery-item": createFlowRemoteComponentRenderer( + "LightBoxGalleryItem", + LightBoxGalleryItem, + ), "flr-line": createFlowRemoteComponentRenderer("Line", Line), "flr-link": createFlowRemoteComponentRenderer("Link", Link), "flr-list-empty-view": createFlowRemoteComponentRenderer(