Skip to content

Commit

Permalink
Merge pull request #395 from IQSS/feature/376-add-dynamic-field-types…
Browse files Browse the repository at this point in the history
…-to-create-dataset-form

Multiple dynamic fields - Create Dataset Form
  • Loading branch information
GPortas authored May 20, 2024
2 parents df24105 + 0046b6a commit 2ace63e
Show file tree
Hide file tree
Showing 61 changed files with 1,658 additions and 1,352 deletions.
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

0 comments on commit 2ace63e

Please sign in to comment.