Skip to content

Commit

Permalink
Merge branch 'main' into site-settings-editing
Browse files Browse the repository at this point in the history
  • Loading branch information
hanpuliu-charles committed Jul 26, 2024
2 parents a0459ec + 8f9e4d3 commit 7651aaf
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 10 deletions.
1 change: 1 addition & 0 deletions apps/studio/src/constants/formBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const JSON_FORMS_RANKING = {
AnyOfControl: 3,
ProseControl: 2,
RadioControl: 3,
LinkControl: 3,
GroupLayoutRenderer: 1,
VerticalLayoutRenderer: 1,
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Heading, HStack, Icon } from "@chakra-ui/react"
import { Box, Flex, Heading, HStack, Icon } from "@chakra-ui/react"
import { Button, IconButton } from "@opengovsg/design-system-react"
import { getComponentSchema } from "@opengovsg/isomer-components"
import { BiDollar, BiX } from "react-icons/bi"
Expand Down Expand Up @@ -29,7 +29,13 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
const { title } = getComponentSchema(component.type)

return (
<Box position="relative" h="100%" w="100%" overflow="auto">
<Flex
flexDir="column"
position="relative"
h="100%"
w="100%"
overflow="auto"
>
<Box
bgColor="base.canvas.default"
borderBottomColor="base.divider.medium"
Expand Down Expand Up @@ -68,7 +74,14 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
<Box px="2rem" py="1rem">
<FormBuilder />
</Box>
<Box px="2rem" pb="1.5rem">
<Box
pos="sticky"
bottom={0}
bgColor="base.canvas.default"
boxShadow="md"
py="1.5rem"
px="2rem"
>
<Button
w="100%"
onClick={() => {
Expand All @@ -79,6 +92,6 @@ export default function ComplexEditorStateDrawer(): JSX.Element {
Save
</Button>
</Box>
</Box>
</Flex>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
Divider,
HStack,
Icon,
Spacer,
Text,
VStack,
} from "@chakra-ui/react"
Expand Down Expand Up @@ -148,13 +147,14 @@ export default function RootStateDrawer() {
</Droppable>
</DragDropContext>
</VStack>
<Spacer />
{/* TODO: Add New Block Section */}
<Box
w="100%"
bgColor="white"
p="1.5rem 2rem 1.5rem 2rem"
boxShadow="0px 0px 10px 0px #BFBFBF80"
bgColor="base.canvas.default"
boxShadow="md"
pos="sticky"
py="1.5rem"
px="2rem"
bottom={0}
>
<Button
w="100%"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
jsonFormsGroupLayoutTester,
JsonFormsIntegerControl,
jsonFormsIntegerControlTester,
JsonFormsLinkControl,
jsonFormsLinkControlTester,
JsonFormsObjectControl,
jsonFormsObjectControlTester,
JsonFormsProseControl,
Expand All @@ -41,6 +43,7 @@ const renderers: JsonFormsRendererRegistryEntry[] = [
renderer: JsonFormsDropdownControl,
},
{ tester: jsonFormsIntegerControlTester, renderer: JsonFormsIntegerControl },
{ tester: jsonFormsLinkControlTester, renderer: JsonFormsLinkControl },
{ tester: jsonFormsTextControlTester, renderer: JsonFormsTextControl },
{ tester: jsonFormsAllOfControlTester, renderer: JsonFormsAllOfControl },
{ tester: jsonFormsAnyOfControlTester, renderer: JsonFormsAnyOfControl },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import type { UseRadioProps } from "@chakra-ui/react"
import type { ControlProps, RankedTester } from "@jsonforms/core"
import type { PropsWithChildren } from "react"
import { useState } from "react"
import {
Box,
FormControl,
HStack,
Icon,
Text,
useRadio,
useRadioGroup,
} from "@chakra-ui/react"
import { and, isStringControl, rankWith, schemaMatches } from "@jsonforms/core"
import { withJsonFormsControlProps } from "@jsonforms/react"
import { FormLabel, Input } from "@opengovsg/design-system-react"
import { BiEnvelopeOpen, BiFile, BiFileBlank, BiLink } from "react-icons/bi"

import { JSON_FORMS_RANKING } from "~/constants/formBuilder"

const LINK_TYPES = {
page: {
icon: BiFileBlank,
label: "Page",
},
external: {
icon: BiLink,
label: "External link",
},
file: {
icon: BiFile,
label: "File",
},
email: {
icon: BiEnvelopeOpen,
label: "Email",
},
} as const

export const jsonFormsLinkControlTester: RankedTester = rankWith(
JSON_FORMS_RANKING.LinkControl,
and(
isStringControl,
schemaMatches((schema) => schema.format === "link"),
),
)

const RadioCard = ({ children, ...rest }: PropsWithChildren<UseRadioProps>) => {
const { getInputProps, getRadioProps } = useRadio(rest)

return (
<Box
as="label"
_first={{
"> div": {
borderLeftRadius: "base",
},
}}
_last={{
"> div": {
borderRightRadius: "base",
},
}}
>
<input {...getInputProps()} />
<Box
{...getRadioProps()}
cursor="pointer"
border="1px solid"
borderColor="base.divider.strong"
bgColor="utility.ui"
px="1rem"
py="0.5rem"
mx={0}
_checked={{
bgColor: "interaction.muted.main.active",
color: "interaction.main.default",
borderColor: "interaction.main.default",
}}
textTransform="none"
fontWeight={500}
lineHeight="1.25rem"
>
{children}
</Box>
</Box>
)
}

interface RadioContentProps {
selectedLinkType: string
data: string
handleChange: (value: string) => void
}

const RadioContent = ({
selectedLinkType,
data,
handleChange,
}: RadioContentProps): JSX.Element => {
switch (selectedLinkType) {
case "page":
return (
<Input
type="text"
value={data}
onChange={(e) => handleChange(e.target.value)}
placeholder="Page permalink"
/>
)
case "external":
return (
<Input
type="text"
value={data}
onChange={(e) => handleChange(e.target.value)}
placeholder="https://www.isomer.gov.sg"
/>
)
case "file":
return (
<Input
type="text"
value={data}
onChange={(e) => handleChange(e.target.value)}
placeholder="File link"
/>
)
case "email":
return (
<Input
type="text"
value={data.startsWith("mailto:") ? data.slice("mailto:".length) : ""}
onChange={(e) => handleChange(`mailto:${e.target.value}`)}
placeholder="[email protected]"
/>
)
default:
return <></>
}
}

export function JsonFormsLinkControl({
data,
label,
handleChange,
path,
description,
required,
}: ControlProps) {
const [selectedLinkType, setSelectedLinkType] = useState("page")

const handleLinkTypeChange = (value: string) => {
setSelectedLinkType(value)
handleChange(path, "")
}

const { getRootProps, getRadioProps } = useRadioGroup({
name: "link-type",
defaultValue: "page",
onChange: handleLinkTypeChange,
})

const dataString = data && typeof data === "string" ? data : ""

return (
<Box py="0.5rem">
<FormControl isRequired={required}>
<FormLabel description={description}>{label}</FormLabel>

<HStack {...getRootProps()} spacing={0}>
{Object.entries(LINK_TYPES).map(([key, { icon, label }]) => {
const radio = getRadioProps({ value: key })

return (
<RadioCard key={key} {...radio}>
<HStack spacing={2}>
<Icon as={icon} fontSize="1.25rem" />
<Text textStyle="subhead-2">{label}</Text>
</HStack>
</RadioCard>
)
})}
</HStack>

<Box my="0.5rem">
<RadioContent
selectedLinkType={selectedLinkType}
data={dataString}
handleChange={(value) => handleChange(path, value)}
/>
</Box>
</FormControl>
</Box>
)
}

export default withJsonFormsControlProps(JsonFormsLinkControl)
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export {
default as JsonFormsRadioControl,
jsonFormsRadioControlTester,
} from "./JsonFormsRadioControl"
export {
default as JsonFormsLinkControl,
jsonFormsLinkControlTester,
} from "./JsonFormsLinkControl"
export {
default as JsonFormsTextControl,
jsonFormsTextControlTester,
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/interfaces/complex/Button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const ButtonSchema = Type.Object(
href: Type.String({
title: "Button URL",
description: "The URL to navigate to when the button is clicked",
format: "link",
}),
colorScheme: Type.Optional(
Type.Union(
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/interfaces/complex/Infobar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const InfobarSchema = Type.Object(
Type.String({
title: "Button destination",
description: "When this is clicked, open:",
format: "link",
}),
),
secondaryButtonLabel: Type.Optional(
Expand All @@ -36,6 +37,7 @@ export const InfobarSchema = Type.Object(
Type.String({
title: "Secondary button destination",
description: "When this is clicked, open:",
format: "link",
}),
),
},
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/interfaces/complex/Infopic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const InfopicSchema = Type.Object(
Type.String({
title: "Button destination",
description: "When this is clicked, open:",
format: "link",
}),
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ContentPageHeaderSchema = Type.Object(
Type.String({
title: "Button URL",
description: "The URL the button should link to",
format: "link",
}),
),
},
Expand Down

0 comments on commit 7651aaf

Please sign in to comment.