Skip to content

Commit

Permalink
feat: add numeric comma seperator support
Browse files Browse the repository at this point in the history
Also added a few component styling support
  • Loading branch information
ivawzh committed Oct 2, 2023
1 parent 9b45133 commit 67503bb
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 15 deletions.
6 changes: 5 additions & 1 deletion src/components/Frequency.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const DEFAULT_PROPS = {
disabled: false,
selectPlaceholder: InternalSelect.DEFAULT_PROPS.placeholder,
optional: false,
commaSeparated: false,
validate: (value, { isInputEmpty, isFrequencyEmpty }) => {
const errors = [];

Expand Down Expand Up @@ -94,6 +95,7 @@ function Frequency(props) {
typeof amountPrefix === "string" && amountPrefix.length > 0,
disabled: (disabled) => typeof disabled === "boolean",
optional: (optional) => typeof optional === "boolean",
commaSeparated: (commaSeparated) => typeof commaSeparated === "boolean",
}
);
const {
Expand All @@ -113,6 +115,7 @@ function Frequency(props) {
helpText,
disabled,
optional,
commaSeparated,
validate,
validateData,
testId,
Expand Down Expand Up @@ -183,7 +186,7 @@ function Frequency(props) {
<InternalInput
name={`${name}.amount`}
parentName={name}
variant="numeric"
variant= {commaSeparated ? "commaNumeric" : "numeric"}
data={data}
prefix={amountPrefix}
color={props.color}
Expand Down Expand Up @@ -276,6 +279,7 @@ Frequency.propTypes = {
helpText: PropTypes.node,
disabled: PropTypes.bool,
optional: PropTypes.bool,
commaSeparated: PropTypes.bool,
validate: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
validateData: PropTypes.any,
testId: PropTypes.string,
Expand Down
2 changes: 1 addition & 1 deletion src/components/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const DEFAULT_PROPS = {
return "Required";
}

if (variant === "numeric" && NUMERIC_REGEX.test(value) === false) {
if (["numeric", "commaNumeric"].includes(variant) && NUMERIC_REGEX.test(value) === false) {
return "Only 0-9 are allowed";
}

Expand Down
10 changes: 5 additions & 5 deletions src/components/OtpInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import useBackground from "../hooks/useBackground";
import useResponsivePropsCSS from "../hooks/useResponsivePropsCSS";

const DEFAULT_PROPS = {
numInputs: 6,
codeLength: 6,
disabled: false,
optional: false,
color: "grey.t05",
Expand All @@ -34,7 +34,7 @@ export default function OtpInput(props) {
DEFAULT_PROPS,
{},
{
numInputs: (numInputs) => typeof numInputs === "number",
codeLength: (codeLength) => typeof codeLength === "number",
disabled: (disabled) => typeof disabled === "boolean",
optional: (optional) => typeof optional === "boolean",
shouldAutoFocus: (shouldAutoFocus) =>
Expand All @@ -45,7 +45,7 @@ export default function OtpInput(props) {

const {
name,
numInputs,
codeLength,
disabled,
optional,
onChange: onChangeProp,
Expand Down Expand Up @@ -105,7 +105,7 @@ export default function OtpInput(props) {
id={otpInputId}
value={value}
onChange={onChange}
numInputs={numInputs}
numInputs={codeLength}
containerStyle={{ gap: "4px" }}
renderInput={(inputProps, index) => {
return (
Expand All @@ -130,7 +130,7 @@ OtpInput.DEFAULT_PROPS = DEFAULT_PROPS;
OtpInput.propTypes = {
name: PropTypes.string.isRequired,
color: PropTypes.string,
numInputs: PropTypes.number,
codeLength: PropTypes.number,
isDisabled: PropTypes.bool,
shouldAutoFocus: PropTypes.bool,
value: PropTypes.string,
Expand Down
5 changes: 3 additions & 2 deletions src/components/Stepper.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@ function Item(_props) {
const label = useResponsiveProp(props, "label");
const isFirst = index === 0;
const isLast = index === total - 1;
const labelCss = theme.stepper.getCSS({ targetElement: "label" });

return (
<div
css={theme.stepper.getCSS({ targetElement: "item", stepsCount: total })}
>
<div css={theme.stepper.getCSS({ targetElement: "labelContainer" })}>
<div css={theme.stepper.getCSS({ targetElement: "label" })}>
<div css={labelCss}>
{label && (
<Text
textStyle="body2"
color={current ? "primary.blue.t100" : "black"}
color={current ? labelCss.colorCurrent : labelCss.colorNonCurrent}
align="center"
>
<strong>{label}</strong>
Expand Down
29 changes: 25 additions & 4 deletions src/components/internal/InternalInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { mergeProps } from "../../utils/component";
import { getDataAttributes } from "../../utils/getDataAttributes";

const TYPES = ["text", "password", "email", "tel"];
const VARIANTS = ["text", "numeric", "decimal"];
const VARIANTS = ["text", "numeric", "decimal", "commaNumeric"];
const COLORS = ["grey.t05", "white"];

const NUMERIC_REGEX = /^\d*$/;
Expand Down Expand Up @@ -99,7 +99,7 @@ function InternalInput(props) {
const dataAttrs = getDataAttributes(data);

const variantProps =
variant === "numeric"
["numeric", "commaNumeric"].includes(variant)
? {
// See: https://technology.blog.gov.uk/2020/02/24/why-the-gov-uk-design-system-team-changed-the-input-type-for-numbers
inputMode: "numeric",
Expand All @@ -111,6 +111,18 @@ function InternalInput(props) {
}
: {};

const serializedValue = variant === "commaNumeric" ? serializeCommaNumeric(value) : value;

const onChangeDeserialized = useCallback(event => {
const input = event.target.value;

if (variant === "commaNumeric" && input && typeof input === "string") {
const deserializedValue = input.replace(/,/g, '');
event.target.value = deserializedValue;
}
onChange(event);
}, [variant, onChange])

return (
<div
css={theme.input.getCSS({
Expand Down Expand Up @@ -141,8 +153,8 @@ function InternalInput(props) {
aria-describedby={describedBy}
onFocus={onFocus}
onBlur={onBlur}
value={value}
onChange={onChange}
value={serializedValue}
onChange={onChangeDeserialized}
/>
</div>
);
Expand Down Expand Up @@ -174,3 +186,12 @@ InternalInput.propTypes = {
};

export default InternalInput;

function serializeCommaNumeric(value) {
const commaNumeric = new Intl.NumberFormat('en', {
maximumFractionDigits: 0,
minimumFractionDigits: 0,
}).format(value);

return commaNumeric === '0' ? '' : commaNumeric;
}
4 changes: 2 additions & 2 deletions src/themes/default/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export default (theme, { getColor }) => {
color,
__internal__focus,
}) => {
const hasPrefix = ["numeric", "decimal"].includes(variant) && prefix;
const hasSuffix = ["numeric", "decimal"].includes(variant) && suffix;
const hasPrefix = ["commaNumeric", "numeric", "decimal"].includes(variant) && prefix;
const hasSuffix = ["commaNumeric", "numeric", "decimal"].includes(variant) && suffix;

switch (targetElement) {
case "inputContainer": {
Expand Down
2 changes: 2 additions & 0 deletions src/themes/default/stepper.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export default (theme) => {
left: "50%",
transform: "translateX(-50%)",
whiteSpace: "nowrap",
colorCurrent: "primary.blue.t100",
colorNonCurrent: "black",
};
}

Expand Down
16 changes: 16 additions & 0 deletions website/src/pages/components/frequency/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const scope = allDesignSystem;
const colorOptions = getRadioOptions(COLORS);
const modeOptions = getRadioOptions(MODES);
const frequencyOptions = ALL_FREQUENCY_OPTIONS;
const commaSeparatedOptions = getCheckboxOptions();
const isOptionalOptions = getCheckboxOptions();
const hasHelpTextOptions = getCheckboxOptions();
const isDisabledOptions = getCheckboxOptions();
Expand All @@ -30,6 +31,7 @@ function FrequencyPage() {
return acc;
}, {});
});
const [commaSeparated, setCommaSeparated] = useState(DEFAULT_PROPS.commaSeparated);
const [optional, setIsOptional] = useState(DEFAULT_PROPS.optional);
const [hasHelpText, setHasHelpText] = useState(
Boolean(DEFAULT_PROPS.helpText)
Expand Down Expand Up @@ -99,6 +101,12 @@ function FrequencyPage() {
defaultValue: DEFAULT_PROPS.weekly,
type: "boolean",
},
{
prop: "commaSeparated",
value: commaSeparated,
defaultValue: DEFAULT_PROPS.commaSeparated,
type: "boolean",
},
{
prop: "optional",
value: optional,
Expand Down Expand Up @@ -154,6 +162,14 @@ function FrequencyPage() {
selectedValues={frequencies}
setSelectedValues={setFrequencies}
/>
<RadioGroupSetting
css={{ marginLeft: theme.space[13] }}
heading="Comma Separate"
options={commaSeparatedOptions}
selectedValue={commaSeparated}
setSelectedValue={setCommaSeparated}
type="boolean"
/>
<RadioGroupSetting
css={{ marginLeft: theme.space[13] }}
heading="Optional"
Expand Down

0 comments on commit 67503bb

Please sign in to comment.