import PropTypes from 'prop-types';
import { useBrand, overrideReconciler } from '@westpac/core';
import React, { useId, useMemo, ReactNode, CSSProperties, forwardRef } from 'react';
import { defaultInputGroup } from './overrides/inputGroup';
import { TextInputField } from './TextInputField';
import pkg from '../package.json';
import { sizeMap } from '@westpac/text-input';
// ==============================
// Context and Consumer Hook
// ==============================
type Sizes = 'small' | 'medium' | 'large' | 'xlarge';
// ==============================
// Component
// ==============================
interface TextWrapperProps {
children?: ReactNode;
css?: CSSProperties;
size?: Sizes;
readOnly?: boolean;
disabled?: boolean;
}
const TextWrapper = ({
children,
disabled,
readOnly,
size = 'medium',
...props
}: TextWrapperProps) => {
const { COLORS } = useBrand();
return (
{children}
);
};
interface WrapperProps {
children?: ReactNode;
css?: CSSProperties;
before?: boolean;
after?: boolean;
invalid?: boolean;
ariaInvalid?: boolean;
disabled?: boolean;
readOnly?: boolean;
size?: Sizes;
}
const Wrapper = ({
children,
before,
after,
disabled,
readOnly,
size = 'medium',
invalid,
ariaInvalid,
...props
}: WrapperProps) => {
const { COLORS } = useBrand();
var s = sizeMap[size];
return (
button, > select, > input': {
width: 'auto !important',
margin: '-1px !important',
},
'> *': {
height: 'auto !important',
...(before
? {
borderTopRightRadius: '0 !important',
borderBottomRightRadius: '0 !important',
}
: {}),
...(after
? {
borderTopLeftRadius: '0 !important',
borderBottomLeftRadius: '0 !important',
}
: {}),
},
...(before
? { borderTopRightRadius: 0, borderBottomRightRadius: 0, borderRight: 'none' }
: {}),
...(after ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0, borderLeft: 'none' } : {}),
}}
>
{children}
);
};
export interface InputGroupProps {
/**
* Define an id for internal elements
*/
instanceId?: string;
/**
* The name of the input field
*/
name?: string;
/**
* The placeholder of the input field
*/
placeholder?: string;
/**
* The label text for the input field
*/
label?: string;
/**
* InputGroup size
*/
size?: Sizes;
/**
* The look of the component
*/
look?: 'primary' | 'hero' | 'faint';
/**
* Data driven
*/
data?: {
before?: {
inputType: 'text' | 'button' | 'select';
data?: unknown[] | string;
onClick?: (...args: unknown[]) => unknown;
};
after?: {
inputType: 'text' | 'button' | 'select';
data?: unknown[] | string;
onClick?: (...args: unknown[]) => unknown;
};
};
/**
* Invalid input mode
*/
invalid?: boolean;
/**
* Aria Invalid input mode
*/
ariaInvalid?: boolean;
/**
* Disabled input mode
*/
disabled?: boolean;
/**
* Read only mode
*/
readOnly?: boolean;
/**
* Element before input
*/
before?: ReactNode;
/**
* Element after the input
*/
after?: ReactNode;
/**
* InputGroup children
*/
children?: React.ReactNode;
/**
* The override API
*/
overrides?: {
InputGroup?: {
styles?: (...args: unknown[]) => unknown;
component?: React.ElementType;
attributes?: (...args: unknown[]) => unknown;
};
Text?: {
styles?: (...args: unknown[]) => unknown;
component?: React.ElementType;
attributes?: (...args: unknown[]) => unknown;
};
TextInput?: {
styles?: (...args: unknown[]) => unknown;
component?: React.ElementType;
attributes?: (...args: unknown[]) => unknown;
};
Select?: {
styles?: (...args: unknown[]) => unknown;
component?: React.ElementType;
attributes?: (...args: unknown[]) => unknown;
};
Button?: {
styles?: (...args: unknown[]) => unknown;
component?: React.ElementType;
attributes?: (...args: unknown[]) => unknown;
};
};
}
export const InputGroup = forwardRef(
(
{
instanceId,
name,
label,
look,
readOnly,
size = 'medium',
invalid = false,
disabled = false,
children,
overrides: componentOverrides,
placeholder,
before,
after,
ariaInvalid,
data,
...rest
},
ref
) => {
const {
OVERRIDES: { [pkg.name]: tokenOverrides },
[pkg.name]: brandOverrides,
} = useBrand();
const defaultOverrides = {
InputGroup: defaultInputGroup,
};
const _id = useId();
const id = useMemo(() => instanceId || `gel-input-group-${_id}`, [_id, instanceId]);
const state = {
id,
name,
label,
size,
look,
invalid,
disabled,
readOnly,
overrides: componentOverrides,
placeholder,
ariaInvalid,
...rest,
};
const {
InputGroup: {
component: InputGroup,
styles: inputGroupStyles,
attributes: inputGroupAttributes,
},
} = overrideReconciler(defaultOverrides, tokenOverrides, brandOverrides, componentOverrides);
return (
{before && (
{typeof before === 'string' ? (
{before}
) : (
before
)}
)}
{after && (
{typeof after === 'string' ? (
{after}
) : (
after
)}
)}
);
}
);
InputGroup.displayName = 'InputGroup';
TextWrapper.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit TypeScript types and run "yarn prop-types" |
// ----------------------------------------------------------------------
children: PropTypes.node,
disabled: PropTypes.bool,
readOnly: PropTypes.bool,
size: PropTypes.oneOf(['large', 'medium', 'small', 'xlarge']),
};
Wrapper.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit TypeScript types and run "yarn prop-types" |
// ----------------------------------------------------------------------
after: PropTypes.bool,
ariaInvalid: PropTypes.bool,
before: PropTypes.bool,
children: PropTypes.node,
disabled: PropTypes.bool,
invalid: PropTypes.bool,
readOnly: PropTypes.bool,
size: PropTypes.oneOf(['large', 'medium', 'small', 'xlarge']),
};
InputGroup.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit TypeScript types and run "yarn prop-types" |
// ----------------------------------------------------------------------
/**
* Element after the input
*/
after: PropTypes.node,
/**
* Aria Invalid input mode
*/
ariaInvalid: PropTypes.bool,
/**
* Element before input
*/
before: PropTypes.node,
/**
* InputGroup children
*/
children: PropTypes.node,
/**
* Data driven
*/
data: PropTypes.shape({
after: PropTypes.shape({
data: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
inputType: PropTypes.oneOf(['button', 'select', 'text']).isRequired,
onClick: PropTypes.func,
}),
before: PropTypes.shape({
data: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
inputType: PropTypes.oneOf(['button', 'select', 'text']).isRequired,
onClick: PropTypes.func,
}),
}),
/**
* Disabled input mode
*/
disabled: PropTypes.bool,
/**
* Define an id for internal elements
*/
instanceId: PropTypes.string,
/**
* Invalid input mode
*/
invalid: PropTypes.bool,
/**
* The label text for the input field
*/
label: PropTypes.string,
/**
* The look of the component
*/
look: PropTypes.oneOf(['faint', 'hero', 'primary']),
/**
* The name of the input field
*/
name: PropTypes.string,
/**
* The override API
*/
overrides: PropTypes.shape({
Button: PropTypes.shape({
attributes: PropTypes.func,
component: PropTypes.elementType,
styles: PropTypes.func,
}),
InputGroup: PropTypes.shape({
attributes: PropTypes.func,
component: PropTypes.elementType,
styles: PropTypes.func,
}),
Select: PropTypes.shape({
attributes: PropTypes.func,
component: PropTypes.elementType,
styles: PropTypes.func,
}),
Text: PropTypes.shape({
attributes: PropTypes.func,
component: PropTypes.elementType,
styles: PropTypes.func,
}),
TextInput: PropTypes.shape({
attributes: PropTypes.func,
component: PropTypes.elementType,
styles: PropTypes.func,
}),
}),
/**
* The placeholder of the input field
*/
placeholder: PropTypes.string,
/**
* Read only mode
*/
readOnly: PropTypes.bool,
/**
* InputGroup size
*/
size: PropTypes.oneOf(['large', 'medium', 'small', 'xlarge']),
};