Skip to content
This repository was archived by the owner on Sep 15, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = {
},
},
},
"@storybook/addon-webpack5-compiler-swc",
],
// staticDirs: ["../public"], TODO: Reinstate after public folder contents established
webpackFinal: async (config) => {
Expand All @@ -40,7 +41,4 @@ module.exports = {
return config;
},
framework: "@storybook/react-webpack5",
docs: {
autodocs: true,
},
};
1 change: 1 addition & 0 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const preview = {
viewports: INITIAL_VIEWPORTS,
},
},
tags: ["autodocs"],
};

export default preview;
22,426 changes: 8,124 additions & 14,302 deletions package-lock.json

Large diffs are not rendered by default.

31 changes: 18 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
"@dnd-kit/core": "^6.0.8",
"@dnd-kit/sortable": "^7.0.2",
"@hookform/resolvers": "^3.3.4",
"@lifesg/react-design-system": "^3.0.0-alpha.20",
"@lifesg/web-frontend-engine": "^2.0.0-alpha.8",
"@lifesg/react-design-system": "^3.4.0-canary.4",
"@lifesg/web-frontend-engine": "^2.2.4",
"react-hook-form": "^7.54.2",
"use-immer": "^0.9.0",
"yup": "^1.4.0"
Expand All @@ -55,15 +55,17 @@
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"@storybook/addon-a11y": "^7.4.6",
"@storybook/addon-actions": "^7.4.6",
"@storybook/addon-essentials": "^7.4.6",
"@storybook/addon-interactions": "^7.4.6",
"@storybook/addon-links": "^7.4.6",
"@storybook/addon-storysource": "^7.6.4",
"@storybook/addon-themes": "^7.5.1",
"@storybook/react": "^7.4.6",
"@storybook/react-webpack5": "^7.4.6",
"@storybook/addon-a11y": "8.6.18",
"@storybook/addon-actions": "8.6.18",
"@storybook/addon-essentials": "8.6.18",
"@storybook/addon-interactions": "8.6.18",
"@storybook/addon-links": "8.6.18",
"@storybook/addon-storysource": "8.6.18",
"@storybook/addon-themes": "8.6.18",
"@storybook/addon-webpack5-compiler-swc": "^3.0.0",
"@storybook/manager-api": "8.6.18",
"@storybook/react": "8.6.18",
"@storybook/react-webpack5": "8.6.18",
"@testing-library/jest-dom": "^6.7.0",
"@testing-library/react": "^12.1.5",
"@types/jest": "^30.0.0",
Expand Down Expand Up @@ -95,7 +97,7 @@
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-typescript2": "^0.36.0",
"storybook": "^7.4.6",
"storybook": "^8.6.18",
"styled-components": "^6.1.19",
"typescript": "^4.8.2",
"typescript-eslint": "^7.1.0"
Expand All @@ -112,5 +114,8 @@
"*.{tsx,ts}": [
"eslint --fix"
]
},
"overrides": {
"nwsapi": "2.2.20"
}
}
}
7 changes: 5 additions & 2 deletions src/components/common/modal/bulk-edit-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { yupResolver } from "@hookform/resolvers/yup";
import { Form } from "@lifesg/react-design-system/form";
import { Typography } from "@lifesg/react-design-system/typography";
import { forwardRef } from "react";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { IBulkEditModalProps } from "src/context-providers";
import { BULK_EDIT_SCHEMA, TBulkEditData } from "src/yup-schemas/bulk-edit";
Expand All @@ -13,7 +14,7 @@ interface IProps {
modal: IBulkEditModalProps;
}

export const BulkEditModal = ({ modal }: IProps) => {
const Modal = ({ modal }: IProps, ref: React.Ref<HTMLDivElement>) => {
// =========================================================================
// CONST, STATE, REFS
// =========================================================================
Expand Down Expand Up @@ -62,7 +63,7 @@ export const BulkEditModal = ({ modal }: IProps) => {
};

return (
<GenericModal type={modal?.type}>
<GenericModal ref={ref} type={modal?.type}>
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(handleFormSubmit)}>
<Wrapper data-testid="bulk-edit-modal">
Expand Down Expand Up @@ -105,3 +106,5 @@ export const BulkEditModal = ({ modal }: IProps) => {
</GenericModal>
);
};

export const BulkEditModal = forwardRef(Modal);
7 changes: 5 additions & 2 deletions src/components/common/modal/discard-changes-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ErrorDisplay } from "@lifesg/react-design-system/error-display";
import { forwardRef } from "react";
import { IDiscardChangesModalProps } from "src/context-providers";
import { useModal } from "../../../context-providers/display/modal-hook";
import { GenericModal } from "./generic-modal";
Expand All @@ -12,7 +13,7 @@ interface IProps {
modal: IDiscardChangesModalProps;
}

export const DiscardChangesModal = ({ modal }: IProps) => {
const Modal = ({ modal }: IProps, ref: React.Ref<HTMLDivElement>) => {
// =========================================================================
// CONST, STATE, REFS
// =========================================================================
Expand Down Expand Up @@ -45,7 +46,7 @@ export const DiscardChangesModal = ({ modal }: IProps) => {
};

return (
<GenericModal type={modal?.type}>
<GenericModal ref={ref} type={modal?.type}>
<ErrorDisplay
type="confirmation"
title={
Expand All @@ -58,3 +59,5 @@ export const DiscardChangesModal = ({ modal }: IProps) => {
</GenericModal>
);
};

export const DiscardChangesModal = forwardRef(Modal);
19 changes: 12 additions & 7 deletions src/components/common/modal/generic-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ModalBoxProps } from "@lifesg/react-design-system/modal";
import { forwardRef } from "react";
import { EModalType } from "src/context-providers";
import { useModal } from "src/context-providers/display/modal-hook";
import { GrowContainer, ModalBox, ModalInner } from "./generic-modal.styles";
Expand All @@ -8,12 +9,10 @@ interface IProps extends ModalBoxProps {
onClose?: () => void;
}

export const GenericModal = ({
type,
onClose,
children,
...otherProps
}: IProps) => {
const Modal = (
{ type, onClose, children, ...otherProps }: IProps,
ref: React.Ref<HTMLDivElement>
) => {
// =========================================================================
// CONST, STATE, REFS
// =========================================================================
Expand All @@ -28,9 +27,15 @@ export const GenericModal = ({
// =============================================================================
return (
<GrowContainer>
<ModalBox onClose={onClose ?? handleModalClose} {...otherProps}>
<ModalBox
ref={ref}
onClose={onClose ?? handleModalClose}
{...otherProps}
>
<ModalInner data-testid="modal-content">{children}</ModalInner>
</ModalBox>
</GrowContainer>
);
};

export const GenericModal = forwardRef(Modal);
7 changes: 5 additions & 2 deletions src/components/common/modal/reset-fields-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ErrorDisplay } from "@lifesg/react-design-system/error-display";
import { forwardRef } from "react";
import { IResetFieldsModalProps } from "src/context-providers";
import { GenericModal } from "./generic-modal";
import {
Expand All @@ -11,7 +12,7 @@ interface IProps {
modal: IResetFieldsModalProps;
}

export const ResetFieldsModal = ({ modal }: IProps) => {
const Modal = ({ modal }: IProps, ref: React.Ref<HTMLDivElement>) => {
// =========================================================================
// CONST, STATE, REFS
// =========================================================================
Expand All @@ -35,7 +36,7 @@ export const ResetFieldsModal = ({ modal }: IProps) => {
};

return (
<GenericModal type={modal?.type} onClose={onClose}>
<GenericModal ref={ref} type={modal?.type} onClose={onClose}>
<ErrorDisplay
type="confirmation"
description={
Expand All @@ -51,3 +52,5 @@ export const ResetFieldsModal = ({ modal }: IProps) => {
</GenericModal>
);
};

export const ResetFieldsModal = forwardRef(Modal);
7 changes: 5 additions & 2 deletions src/components/common/multi-entry/multi-entry.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ export const MultiEntryAccordionItem = styled(
Accordion.Item
)<MultiEntryAccordionItemProps>`
width: 100%;
border-top: 0;
border-bottom: ${Border["width-010"]} ${Border.solid} ${Colour.border};
padding-bottom: ${({ $hasSubtitle }) => ($hasSubtitle ? `0.5rem` : "0")};

border-top: 0;
&:not(:last-child) {
border-bottom: ${Border["width-010"]} ${Border.solid} ${Colour.border};
}

#content-container {
padding: 0;
}
Expand Down
8 changes: 8 additions & 0 deletions src/components/common/pills/pills.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export const Pills = () => {
// EFFECTS
// =========================================================================

useEffect(() => {
if (element?.pills != null) {
resetField("pills", {
defaultValue: element.pills,
});
}
}, []);

/** This useEffect repopulates the defaultValues of pillPosition when it is remounted. */
useEffect(() => {
if (watchPills) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,9 @@ export const BasicDetails = () => {
};

return (
<AccordionWrapper>
<AccordionWrapper initialDisplay="expand-all">
<AccordionItem
type="default"
expanded
title="Basic"
$hideTopBorder={focusedElement.isDirty || isDisabled}
>
Expand Down
7 changes: 7 additions & 0 deletions src/components/element-editor/element-editor.styles.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Accordion } from "@lifesg/react-design-system/accordion";
import { Alert } from "@lifesg/react-design-system/alert";
import styled from "styled-components";

Expand All @@ -9,3 +10,9 @@ export const Wrapper = styled.div`
}
margin-bottom: 8rem;
`;

export const AccordionWrapper = styled(Accordion)`
& > div:first-child {
display: none;
}
`;
10 changes: 6 additions & 4 deletions src/components/element-editor/element-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
useShouldShowPrefill,
} from "src/context-providers";
import { TFormFieldValues } from "src/yup-schemas";
import { BasicDetails } from "./basic-details";
import { AccordionWrapper, BasicDetails } from "./basic-details";
import { ConditionalRendering } from "./conditional-rendering";
import { EditorAlert, Wrapper } from "./element-editor.styles";
import { Prefill } from "./prefill";
Expand Down Expand Up @@ -70,9 +70,11 @@ export const ElementEditor = () => {
</EditorAlert>
)}
<BasicDetails />
{isTextBasedElement(selectedElementType) && <Validation />}
<ConditionalRendering />
{shouldShowPrefill && <Prefill />}
<AccordionWrapper initialDisplay="collapse-all">
{isTextBasedElement(selectedElementType) && <Validation />}
<ConditionalRendering />
{shouldShowPrefill && <Prefill />}
</AccordionWrapper>
</Wrapper>
);
};
3 changes: 3 additions & 0 deletions src/components/element-editor/prefill/prefill-child.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const PrefillChild = ({ onDelete, index }: IProps) => {
const { ref, ...fieldWithoutRef } = field;
return (
<Form.Select
data-testid="prefill-mode-field"
{...fieldWithoutRef}
placeholder="Select"
selectedOption={fieldWithoutRef.value}
Expand Down Expand Up @@ -63,6 +64,7 @@ export const PrefillChild = ({ onDelete, index }: IProps) => {
const { ref, ...fieldWithoutRef } = field;
return (
<Form.Input
data-testid="prefill-action-id-field"
{...fieldWithoutRef}
placeholder="Enter an action ID"
value={fieldWithoutRef.value}
Expand Down Expand Up @@ -90,6 +92,7 @@ export const PrefillChild = ({ onDelete, index }: IProps) => {
const { ref, ...fieldWithoutRef } = field;
return (
<Form.Input
data-testid="prefill-path-field"
{...fieldWithoutRef}
placeholder="Enter a path"
value={fieldWithoutRef.value}
Expand Down
5 changes: 2 additions & 3 deletions tests/components/common/pills/pills.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ describe("Pills", () => {
const togglePillsNoButton = screen.getByLabelText("No");
expect(togglePillsNoButton).toBeChecked();

expect(screen.queryByText("Pill items")).toBeNull();
expect(screen.queryByText("List position")).toBeNull();
expect(screen.queryByText("Pill items")).not.toBeInTheDocument();
expect(screen.queryByText("List position")).not.toBeInTheDocument();
});

it("should conditionally render the pill items and list position fields if pills is toggled to true", async () => {
Expand All @@ -73,7 +73,6 @@ describe("Pills", () => {
});

const pillItemsField = await screen.findByText("Pill items");

const listPositionField = await screen.findByText("List position");
expect(pillItemsField).toBeInTheDocument();
expect(listPositionField).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe("BasicDetails", () => {
);
expect(textBasicDetails).toBeInTheDocument();

const elementName = screen.getByTestId("label-field");
const elementName = screen.getByTestId("label-field-base");
const errorMessageField = screen.getByTestId(
"required-error-message-field-base"
);
Expand All @@ -98,7 +98,7 @@ describe("BasicDetails", () => {
});

// trigger reset confirmation modal
const typeField = screen.getByTestId("type-field");
const typeField = screen.getByTestId("type-field-base");
fireEvent.click(typeField);

const shortTextOption = await screen.findByText("Short text");
Expand All @@ -115,7 +115,7 @@ describe("BasicDetails", () => {
expect(mockHideModal).toHaveBeenCalled();

// Check if the form fields have been replaced with the new element type's default values
const elementName = screen.getByTestId("label-field");
const elementName = screen.getByTestId("label-field-base");
const errorMessageField = screen.getByTestId(
"required-error-message-field-base"
);
Expand All @@ -140,7 +140,9 @@ describe("BasicDetails", () => {
},
});

const descriptionField = screen.getByTestId("description-field");
const descriptionField = screen.getByTestId(
"description-field-base"
);
const placeholderField = screen.getByTestId(
"placeholder-field-base"
);
Expand All @@ -163,7 +165,7 @@ describe("BasicDetails", () => {
expect(preselectedValueField).toHaveValue("preselectedValue");

// trigger reset confirmation modal
const typeField = screen.getByTestId("type-field");
const typeField = screen.getByTestId("type-field-base");
fireEvent.click(typeField);

const shortTextOption = await screen.findByText("Short text");
Expand All @@ -180,8 +182,9 @@ describe("BasicDetails", () => {
expect(mockHideModal).toHaveBeenCalled();

// Wait for the form to reset
const updatedDescriptionField =
await screen.findByTestId("description-field");
const updatedDescriptionField = await screen.findByTestId(
"description-field-base"
);
const updatedPlaceholderField = await screen.findByTestId(
"placeholder-field-base"
);
Expand Down
Loading
Loading