From 367958ca17c48c11429a5591718ed2716ee5eb64 Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Mon, 26 Jan 2026 20:07:30 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(LabelledBox)=20add=20classic=20varian?= =?UTF-8?q?t=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add variant prop to LabelledBox component - Ignore labelAsPlaceholder in classic mode - Add CSS styles for .labelled-box--classic - Add unit tests for both variants Co-Authored-By: Claude Opus 4.5 --- .../components/Forms/LabelledBox/_index.scss | 26 ++++ .../Forms/LabelledBox/index.spec.tsx | 124 ++++++++++++++++++ .../components/Forms/LabelledBox/index.tsx | 9 +- 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 packages/react/src/components/Forms/LabelledBox/index.spec.tsx diff --git a/packages/react/src/components/Forms/LabelledBox/_index.scss b/packages/react/src/components/Forms/LabelledBox/_index.scss index 6f07a6b..d3536e5 100644 --- a/packages/react/src/components/Forms/LabelledBox/_index.scss +++ b/packages/react/src/components/Forms/LabelledBox/_index.scss @@ -77,4 +77,30 @@ } } } + + &--classic { + label { + position: static; + margin-bottom: var( + --c--components--forms-labelledbox--classic-label-margin-bottom + ); + font-size: var( + --c--components--forms-labelledbox--classic-label-font-size + ); + color: var(--c--components--forms-labelledbox--label-color--small); + transition: none; + } + + .labelled-box__children { + padding-top: 0; + } + + &.labelled-box--disabled { + label { + color: var( + --c--components--forms-labelledbox--label-color--small--disabled + ); + } + } + } } diff --git a/packages/react/src/components/Forms/LabelledBox/index.spec.tsx b/packages/react/src/components/Forms/LabelledBox/index.spec.tsx new file mode 100644 index 0000000..d590839 --- /dev/null +++ b/packages/react/src/components/Forms/LabelledBox/index.spec.tsx @@ -0,0 +1,124 @@ +import { render, screen } from "@testing-library/react"; +import React from "react"; +import { expect } from "vitest"; +import { LabelledBox } from "./index"; + +describe("", () => { + describe("floating variant (default)", () => { + it("renders with floating variant by default", () => { + render( + + + , + ); + const container = document.querySelector(".labelled-box"); + expect(container).not.toHaveClass("labelled-box--classic"); + }); + + it("applies placeholder class when labelAsPlaceholder is true", () => { + render( + + + , + ); + const label = screen.getByText("Test Label"); + expect(label.closest("label")).toHaveClass("placeholder"); + }); + + it("does not apply placeholder class when labelAsPlaceholder is false", () => { + render( + + + , + ); + const label = screen.getByText("Test Label"); + expect(label.closest("label")).not.toHaveClass("placeholder"); + }); + }); + + describe("classic variant", () => { + it("renders with classic variant class", () => { + render( + + + , + ); + const container = document.querySelector(".labelled-box"); + expect(container).toHaveClass("labelled-box--classic"); + }); + + it("ignores labelAsPlaceholder in classic variant", () => { + render( + + + , + ); + const label = screen.getByText("Test Label"); + // In classic variant, placeholder class should NOT be applied even if labelAsPlaceholder is true + expect(label.closest("label")).not.toHaveClass("placeholder"); + }); + + it("label is always static in classic variant regardless of labelAsPlaceholder", () => { + const { rerender } = render( + + + , + ); + let label = screen.getByText("Test Label"); + expect(label.closest("label")).not.toHaveClass("placeholder"); + + rerender( + + + , + ); + label = screen.getByText("Test Label"); + expect(label.closest("label")).not.toHaveClass("placeholder"); + }); + }); + + describe("other props work with both variants", () => { + it("applies disabled class in floating variant", () => { + render( + + + , + ); + const container = document.querySelector(".labelled-box"); + expect(container).toHaveClass("labelled-box--disabled"); + }); + + it("applies disabled class in classic variant", () => { + render( + + + , + ); + const container = document.querySelector(".labelled-box"); + expect(container).toHaveClass("labelled-box--classic"); + expect(container).toHaveClass("labelled-box--disabled"); + }); + + it("applies hideLabel in classic variant", () => { + render( + + + , + ); + const label = screen.getByText("Test Label"); + expect(label.closest("label")).toHaveClass("c__offscreen"); + }); + }); +}); diff --git a/packages/react/src/components/Forms/LabelledBox/index.tsx b/packages/react/src/components/Forms/LabelledBox/index.tsx index db1a22d..fd173c7 100644 --- a/packages/react/src/components/Forms/LabelledBox/index.tsx +++ b/packages/react/src/components/Forms/LabelledBox/index.tsx @@ -1,8 +1,10 @@ import React, { PropsWithChildren } from "react"; import classNames from "classnames"; +import type { FieldVariant } from ":/components/Forms/types"; export interface Props extends PropsWithChildren { label?: string; + variant?: FieldVariant; labelAsPlaceholder?: boolean; htmlFor?: string; labelId?: string; @@ -14,6 +16,7 @@ export interface Props extends PropsWithChildren { export const LabelledBox = ({ children, label, + variant = "floating", labelAsPlaceholder, htmlFor, labelId, @@ -21,9 +24,12 @@ export const LabelledBox = ({ horizontal, disabled, }: Props) => { + const isClassic = variant === "classic"; + return (