Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple dynamic fields - Create Dataset Form #395

Merged
Merged
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
14 changes: 14 additions & 0 deletions packages/design-system/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- **SelectMultiple:** NEW multiple selector for occasions when you can choose more than one option.
- **FormSelectMultiple:** The new multiple selector is added to the "FormGroup" components.
- **DropdownButtonItem:** extend Props Interface to accept `as` prop.
- **Accordion:** ability to forward react ref.
- **DynamicFieldsButtons:** Removed from design system.
- **FormGroupWithMultipleFields:** remove withDynamicFields prop and remove logic to handle adding or removing fields.
- **FormGroup:** remove the required and fieldIndex props, remove the cloning of child elements to pass them the withinMultipleFieldsGroup and required props.
- **FormFeedback:** remove withinMultipleFieldsGroup prop.
- **FormInput:** remove withinMultipleFieldsGroup prop.
- **FormLabel:** remove withinMultipleFieldsGroup prop extend interface to accept ColProps.
- **FormSelect:** remove withinMultipleFieldsGroup prop.
- **FormSelectMultiple:** remove withinMultipleFieldsGroup prop.
- **FormText:** remove withinMultipleFieldsGroup prop.
- **FormTextArea:** remove withinMultipleFieldsGroup prop.
- **FormInputGroup:** remove hasVisibleLabel prop.
- **FormInputGroupText:** refactor type.
- **Select Multiple:** add is-invalid classname if isInvalid prop is true.

# [1.1.0](https://github.com/IQSS/dataverse-frontend/compare/@iqss/dataverse-design-system@1.0.1...@iqss/dataverse-design-system@1.1.0) (2024-03-12)

Expand Down
33 changes: 21 additions & 12 deletions packages/design-system/src/lib/components/accordion/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode } from 'react'
import { ForwardedRef, ReactNode, forwardRef } from 'react'
import { Accordion as AccordionBS } from 'react-bootstrap'
import { AccordionItem } from './AccordionItem'
import { AccordionBody } from './AccordionBody'
Expand All @@ -10,16 +10,25 @@ interface AccordionProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onSele
children: ReactNode
}

function Accordion({ defaultActiveKey, alwaysOpen = false, children, ...rest }: AccordionProps) {
return (
<AccordionBS defaultActiveKey={defaultActiveKey} alwaysOpen={alwaysOpen} {...rest}>
{children}
</AccordionBS>
)
}
const Accordion = forwardRef(
({ defaultActiveKey, alwaysOpen = false, children, ...rest }: AccordionProps, ref) => {
return (
<AccordionBS
defaultActiveKey={defaultActiveKey}
alwaysOpen={alwaysOpen}
ref={ref as ForwardedRef<HTMLDivElement>}
{...rest}>
{children}
</AccordionBS>
)
}
)
Accordion.displayName = 'Accordion'

Accordion.Item = AccordionItem
Accordion.Body = AccordionBody
Accordion.Header = AccordionHeader
const AccordionNamespace = Object.assign(Accordion, {
Item: AccordionItem,
Body: AccordionBody,
Header: AccordionHeader
})

export { Accordion }
export { AccordionNamespace as Accordion }
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { PropsWithChildren } from 'react'
import { Row } from '../../grid/Row'
import { Col } from '../../grid/Col'
import { PropsWithChildren } from 'react'
import styles from './FormGroupWithMultipleFields.module.scss'
import { RequiredInputSymbol } from '../required-input-symbol/RequiredInputSymbol'
import { DynamicFieldsButtons } from './dynamic-fields-buttons/DynamicFieldsButtons'
import { useFields } from './useFields'
import { QuestionMarkTooltip } from '../../tooltip/question-mark-tooltip/QuestionMarkTooltip'

interface FormGroupWithMultipleFieldsProps {
title: string
withDynamicFields?: boolean
required?: boolean
message?: string
}
Expand All @@ -23,37 +20,18 @@ const Title = ({ title, required, message }: Partial<FormGroupWithMultipleFields

export function FormGroupWithMultipleFields({
title,
withDynamicFields,
required,
message,
children
}: PropsWithChildren<FormGroupWithMultipleFieldsProps>) {
const { fields, addField, removeField } = useFields(children, withDynamicFields)

return (
<>
{fields.map((field, index) => {
const isFirstField = index == 0

return (
<Row key={index} className="mb-3">
<Col sm={3}>
{isFirstField && <Title title={title} required={required} message={message} />}
</Col>
<Col sm={withDynamicFields ? 6 : 9}>{field}</Col>

{withDynamicFields && (
<Col sm={3}>
<DynamicFieldsButtons
originalField={isFirstField}
onAddButtonClick={() => addField(field)}
onRemoveButtonClick={() => removeField(index)}
/>
</Col>
)}
</Row>
)
})}
</>
<Row className="mb-3">
<Col sm={3}>
<Title title={title} required={required} message={message} />
</Col>
<Col sm={9} className="mb-3">
{children}
</Col>
</Row>
)
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { PropsWithChildren } from 'react'
import { PropsWithChildren } from 'react'
import { Form as FormBS } from 'react-bootstrap'
import { FormInput } from './form-element/FormInput'
import { FormLabel } from './form-element/FormLabel'
Expand All @@ -13,54 +13,16 @@ import { FormSelectMultiple } from './form-element/FormSelectMultiple'

interface FormGroupProps extends ColProps {
as?: typeof Col | typeof Row
required?: boolean
controlId?: string
fieldIndex?: string
}

function FormGroup({
as = Row,
required,
controlId,
fieldIndex,
children,
...props
}: PropsWithChildren<FormGroupProps>) {
const childrenWithRequiredProp = cloneThroughFragments(children, required, as)

function FormGroup({ as = Row, controlId, children, ...props }: PropsWithChildren<FormGroupProps>) {
return (
<FormBS.Group
controlId={controlId ? (fieldIndex ? `${controlId}-${fieldIndex}` : controlId) : undefined}
className="mb-3"
as={as}
{...props}>
{childrenWithRequiredProp}
<FormBS.Group controlId={controlId} className="mb-3" as={as} {...props}>
{children}
</FormBS.Group>
)
}
function cloneThroughFragments(
children: React.ReactNode,
required?: boolean,
as?: typeof Col | typeof Row
): React.ReactNode {
return React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
if (child.type === React.Fragment) {
const hasChildren = (props: unknown): props is { children: React.ReactNode } =>
typeof props === 'object' && Object.hasOwnProperty.call(props, 'children')

if (hasChildren(child.props)) {
return cloneThroughFragments(child.props.children, required, as)
}
}
return React.cloneElement(child as React.ReactElement, {
required: required,
withinMultipleFieldsGroup: as === Col
})
}
return child
})
}

FormGroup.Label = FormLabel
FormGroup.Input = FormInput
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { FormControl } from 'react-bootstrap'
import { PropsWithChildren } from 'react'
import { Col } from '../../../grid/Col'
import { Col, ColProps } from '../../../grid/Col'
import { Row } from '../../../grid/Row'

interface FormFeedbackProps {
interface FormFeedbackProps extends ColProps {
type?: 'valid' | 'invalid'
withinMultipleFieldsGroup?: boolean
as?: typeof Col | typeof Row
}

export function FormFeedback({
type = 'valid',
withinMultipleFieldsGroup,
children
as,
children,
...props
}: PropsWithChildren<FormFeedbackProps>) {
return withinMultipleFieldsGroup ? (
<FormControl.Feedback type={type}>{children}</FormControl.Feedback>
) : (
<FormControl.Feedback as={Col} sm={{ offset: 3 }} type={type}>
return (
<FormControl.Feedback type={type} as={as} {...props}>
{children}
</FormControl.Feedback>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { Form as FormBS } from 'react-bootstrap'
import { FormElementLayout } from './FormElementLayout'
import * as React from 'react'

export type FormInputElement = HTMLInputElement | HTMLTextAreaElement

export interface FormInputProps extends React.HTMLAttributes<FormInputElement> {
type?: 'text' | 'email' | 'password'
readOnly?: boolean
withinMultipleFieldsGroup?: boolean
name?: string
isValid?: boolean
isInvalid?: boolean
Expand All @@ -24,31 +22,25 @@ export const FormInput = React.forwardRef(function FormInput(
isValid,
isInvalid,
disabled,
withinMultipleFieldsGroup,
value,
required,
...props
}: FormInputProps,
ref
) {
return (
<FormElementLayout
withinMultipleFieldsGroup={withinMultipleFieldsGroup}
<FormBS.Control
name={name}
type={type}
readOnly={readOnly}
plaintext={readOnly}
isValid={isValid}
isInvalid={isInvalid}
isValid={isValid}>
<FormBS.Control
name={name}
type={type}
readOnly={readOnly}
plaintext={readOnly}
isValid={isValid}
isInvalid={isInvalid}
disabled={disabled}
value={value}
required={required}
ref={ref as React.ForwardedRef<HTMLInputElement>}
{...props}
/>
</FormElementLayout>
disabled={disabled}
value={value}
required={required}
ref={ref as React.ForwardedRef<HTMLInputElement>}
{...props}
/>
)
})
Loading
Loading