Skip to content

Commit

Permalink
feat: remove bootstrap from Form component
Browse files Browse the repository at this point in the history
  • Loading branch information
PKulkoRaccoonGang committed Dec 9, 2024
1 parent e96baef commit b255421
Show file tree
Hide file tree
Showing 7 changed files with 584 additions and 1 deletion.
45 changes: 45 additions & 0 deletions src/Form/BSFeedback.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
// import { BsPrefixProps, BsPrefixRefForwardingComponent } from './helpers';

const propTypes = {
/**
* Specify whether the feedback is for valid or invalid fields
*
* @type {('valid'|'invalid')}
*/
type: PropTypes.string,

Check failure on line 12 in src/Form/BSFeedback.jsx

View workflow job for this annotation

GitHub Actions / tests

propType "type" is not required, but has no corresponding defaultProps declaration

/** Display feedback as a tooltip. */
tooltip: PropTypes.bool,

Check failure on line 15 in src/Form/BSFeedback.jsx

View workflow job for this annotation

GitHub Actions / tests

propType "tooltip" is not required, but has no corresponding defaultProps declaration

as: PropTypes.elementType,

Check failure on line 17 in src/Form/BSFeedback.jsx

View workflow job for this annotation

GitHub Actions / tests

propType "as" is not required, but has no corresponding defaultProps declaration
};

const Feedback = React.forwardRef(
(
{
as: Component = 'div',
className,

Check failure on line 24 in src/Form/BSFeedback.jsx

View workflow job for this annotation

GitHub Actions / tests

'className' is missing in props validation
type = 'valid',
tooltip = false,
...props
},
ref,
) => (
<Component
{...props}
ref={ref}
className={classNames(
className,
`${type}-${tooltip ? 'tooltip' : 'feedback'}`,
)}
/>
),
);

Feedback.displayName = 'Feedback';
Feedback.propTypes = propTypes;

export default Feedback;
92 changes: 92 additions & 0 deletions src/Form/BSForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import FormCheck from './FormCheck';

Check failure on line 4 in src/Form/BSForm.jsx

View workflow job for this annotation

GitHub Actions / tests

Missing file extension for "./FormCheck"

Check failure on line 4 in src/Form/BSForm.jsx

View workflow job for this annotation

GitHub Actions / tests

Unable to resolve path to module './FormCheck'
import FormFile from './FormFile';

Check failure on line 5 in src/Form/BSForm.jsx

View workflow job for this annotation

GitHub Actions / tests

Missing file extension for "./FormFile"

Check failure on line 5 in src/Form/BSForm.jsx

View workflow job for this annotation

GitHub Actions / tests

Unable to resolve path to module './FormFile'
import FormControl from './FormControl';
import FormGroup from './FormGroup';
import FormLabel from './FormLabel';
import FormText from './FormText';
import Switch from './Switch';

Check failure on line 10 in src/Form/BSForm.jsx

View workflow job for this annotation

GitHub Actions / tests

Missing file extension for "./Switch"

Check failure on line 10 in src/Form/BSForm.jsx

View workflow job for this annotation

GitHub Actions / tests

Unable to resolve path to module './Switch'
// import { useBootstrapPrefix } from './ThemeProvider';
import createWithBsPrefix from './createWithBsPrefix';
// import { BsPrefixProps, BsPrefixRefForwardingComponent } from './helpers';

const FormRow = createWithBsPrefix('form-row');

const propTypes = {
/**
* @default {'form'}
*/
bsPrefix: PropTypes.string,

/**
* The Form `ref` will be forwarded to the underlying element,
* which means, unless it's rendered `as` a composite component,
* it will be a DOM node, when resolved.
*
* @type {ReactRef}
* @alias ref
*/
_ref: PropTypes.any,

/**
* Display the series of labels, form controls,
* and buttons on a single horizontal row
*/
inline: PropTypes.bool,

/**
* Mark a form as having been validated. Setting it to `true` will
* toggle any validation styles on the forms elements.
*/
validated: PropTypes.bool,
as: PropTypes.elementType,
};

const defaultProps = {
inline: false,
};

const FormImpl = (React.forwardRef(
(
{
bsPrefix,
inline,
className,
validated,
as: Component = 'form',
...props
},
ref,
) => {
// bsPrefix = useBootstrapPrefix(bsPrefix, 'form');
bsPrefix = 'form';
return (
<Component
{...props}
ref={ref}
className={classNames(
className,
validated && 'was-validated',
inline && `${bsPrefix}-inline`,
)}
/>
);
},
));

FormImpl.displayName = 'Form';
FormImpl.propTypes = propTypes;
FormImpl.defaultProps = defaultProps;

FormImpl.Row = FormRow;
FormImpl.Group = FormGroup;
FormImpl.Control = FormControl;
FormImpl.Check = FormCheck;
FormImpl.File = FormFile;
FormImpl.Switch = Switch;
FormImpl.Label = FormLabel;
FormImpl.Text = FormText;

export default FormImpl;
207 changes: 207 additions & 0 deletions src/Form/BSFormCheck.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
// import all from 'prop-types-extra/lib/all';
import React, { useContext, useMemo } from 'react';
import Feedback from './BSFeedback';
import FormCheckInput from './FormCheckInput';
import FormCheckLabel from './FormCheckLabel';
import FormContext from './BSFormContext';
// import { useBootstrapPrefix } from './ThemeProvider';

const propTypes = {
/**
* @default 'form-check'
*/
bsPrefix: PropTypes.string,

/**
* A seperate bsPrefix used for custom controls
*
* @default 'custom-control'
*/
bsCustomPrefix: PropTypes.string,

/**
* The FormCheck `ref` will be forwarded to the underlying input element,
* which means it will be a DOM node, when resolved.
*
* @type {ReactRef}
* @alias ref
*/
_ref: PropTypes.any,

/**
* The underlying HTML element to use when rendering the FormCheck.
*
* @type {('input'|elementType)}
*/
as: PropTypes.elementType,

/**
* A HTML id attribute, necessary for proper form accessibility.
* An id is recommended for allowing label clicks to toggle the check control.
*
* This is **required** for custom check controls or when `type="switch"` due to
* how they are rendered.
*/
id: PropTypes.string,

/**
* Provide a function child to manually handle the layout of the FormCheck's inner components.
*
* ```jsx
* <FormCheck>
* <FormCheck.Input isInvalid type={radio} />
* <FormCheck.Label>Allow us to contact you?</FormCheck.Label>
* <Feedback type="invalid">Yo this is required</Feedback>
* </FormCheck>
* ```
*/
children: PropTypes.node,

/**
* Groups controls horizontally with other `FormCheck`s.
*/
inline: PropTypes.bool,

/**
* Disables the control.
*/
disabled: PropTypes.bool,

/**
* `title` attribute for the underlying `FormCheckLabel`.
*/
title: PropTypes.string,

/**
* Label for the control.
*/
label: PropTypes.node,

/** Use Bootstrap's custom form elements to replace the browser defaults */
// custom: all(PropTypes.bool, ({ custom, id }) => (custom && !id ? Error('Custom check controls require an id to work') : null)),

/**
* The type of checkable.
* @type {('radio' | 'checkbox' | 'switch')}
*/
type: all(
PropTypes.oneOf(['radio', 'checkbox', 'switch']).isRequired,
({ type, custom }) => (type === 'switch' && custom === false
? Error('`custom` cannot be set to `false` when the type is `switch`')
: null),
({ type, id }) => (type === 'switch' && !id
? Error('`id` must be defined when the type is `switch`')
: null),
),

/** Manually style the input as valid */
isValid: PropTypes.bool,

/** Manually style the input as invalid */
isInvalid: PropTypes.bool,

/** Display feedback as a tooltip. */
feedbackTooltip: PropTypes.bool,

/** A message to display when the input is in a validation state */
feedback: PropTypes.node,
};

const FormCheck = (React.forwardRef(
(
{
id,
bsPrefix,
bsCustomPrefix,
inline = false,
disabled = false,
isValid = false,
isInvalid = false,
feedbackTooltip = false,
feedback,
className,
style,
title = '',
type = 'checkbox',
label,
children,
custom: propCustom,
as = 'input',
...props
},
ref,
) => {
const custom = type === 'switch' ? true : propCustom;
const [prefix, defaultPrefix] = custom
? [bsCustomPrefix, 'custom-control']
: [bsPrefix, 'form-check'];

// bsPrefix = useBootstrapPrefix(prefix, defaultPrefix);
bsPrefix = 'form-check';

const { controlId } = useContext(FormContext);
const innerFormContext = useMemo(
() => ({
controlId: id || controlId,
custom,
}),
[controlId, custom, id],
);

const hasLabel = custom || (label != null && label !== false && !children);

const input = (
<FormCheckInput
{...props}
type={type === 'switch' ? 'checkbox' : type}
ref={ref}
isValid={isValid}
isInvalid={isInvalid}
isStatic={!hasLabel}
disabled={disabled}
as={as}
/>
);

return (
<FormContext.Provider value={innerFormContext}>
<div
style={style}
className={classNames(
className,
bsPrefix,
custom && `custom-${type}`,
inline && `${bsPrefix}-inline`,
)}
>
{children || (
<>
{input}
{hasLabel && (
<FormCheckLabel title={title}>{label}</FormCheckLabel>
)}
{(isValid || isInvalid) && (
<Feedback
type={isValid ? 'valid' : 'invalid'}
tooltip={feedbackTooltip}
>
{feedback}
</Feedback>
)}
</>
)}
</div>
</FormContext.Provider>
);
},
));

FormCheck.displayName = 'FormCheck';
FormCheck.propTypes = propTypes;

FormCheck.Input = FormCheckInput;
FormCheck.Label = FormCheckLabel;

export default FormCheck;
7 changes: 7 additions & 0 deletions src/Form/BSFormContext.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

const FormContext = React.createContext({
controlId: undefined,
});

export default FormContext;
Loading

0 comments on commit b255421

Please sign in to comment.