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

Add min max properties to Input and pkg-pr-new workflow #112

Merged
merged 12 commits into from
Oct 16, 2024
29 changes: 29 additions & 0 deletions .github/workflows/pkg.pr.new.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: PKG PR New
on:
workflow_dispatch:
pull_request:
types: [opened, synchronize, ready_for_review]
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20

- run: yarn --frozen-lockfile

# append the git commit to the package.json version.
# We do this because some cache mechanisms (like nextjs) don't work well with the same version and ignore the changes
# until you manually delete the cache
- run: jq '.version = .version + "-" + env.GITHUB_SHA' package.json > package.json.tmp && mv package.json.tmp package.json

- run: npx pkg-pr-new publish
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added the pkg.pr.new workflow
neotob marked this conversation as resolved.
Show resolved Hide resolved
- The minLength and maxLength input properties

## [2.12.0] - 2024-10-07

### Added
Expand Down
22 changes: 22 additions & 0 deletions cypress/cypress/component/Input/BasicInputField.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,25 @@ describe("Input.cy.tsx", () => {
cy.get(`label[for=${name}]`).parent().find("svg[data-icon=pencil]");
});
});

it("minlenght and maxlenght work", () => {
const name = faker.random.word();
const minLength = 3;
const maxLength = 10;
const validInput = faker.random.alpha({ count: minLength });
const invalidInput = faker.random.alpha({ count: maxLength + 1 });

cy.mount(
<Form
onSubmit={() => {
// Do nothing
}}
>
<Input type="text" name={name} label={name} minLength={minLength} maxLength={maxLength} />
<input type={"submit"} />
</Form>,
);

cy.get(`input[name=${name}]`).type(validInput).should("have.value", validInput);
cy.get(`input[name=${name}]`).clear().type(invalidInput).should("have.value", invalidInput.slice(0, maxLength));
});
31 changes: 30 additions & 1 deletion src/lib/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,23 @@ interface InputProps<T extends FieldValues> extends CommonInputProps<T> {
}

const Input = <T extends FieldValues>(props: InputProps<T>) => {
const { type, options, addonLeft, name, addonRight, rangeMin, rangeMax, textAreaRows, multiple, id, value, disabled, step } = props;
const {
type,
options,
addonLeft,
name,
addonRight,
rangeMin,
rangeMax,
textAreaRows,
multiple,
id,
value,
disabled,
step,
minLength,
maxLength,
} = props;

if (type === "radio" && !options) {
throw new Error("options must be provided for radio inputs");
Expand Down Expand Up @@ -56,6 +72,19 @@ const Input = <T extends FieldValues>(props: InputProps<T>) => {
if (step && type !== "number" && type !== "range") {
throw new Error("step can only be used with number or range inputs");
}
if (minLength !== undefined || maxLength !== undefined) {
// check validity for input types
if (type && !["text", "password", "textarea", "search", "tel", "url", "email"].includes(type)) {
throw new Error("minlength and maxlength can only be used with text, password, textarea, search, tel, url, or email inputs");
}
const isNegativeOrInvalidNumber = (value: number | undefined) => value !== undefined && (isNaN(value) || value < 0);
if (isNegativeOrInvalidNumber(minLength) || isNegativeOrInvalidNumber(maxLength)) {
throw new Error("minlength and maxlength, whether provided, must be 0 or positive valid numbers");
}
if (minLength !== undefined && maxLength !== undefined && minLength > maxLength) {
throw new Error("minlength must be less than or equal to maxlength");
}
}

const formGroupLayout = (() => {
if (type === "switch") {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/InputInternal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const InputInternal = <T extends FieldValues>(props: InputProps<T>) => {
className,
style,
innerRef,
minLength,
maxLength,
} = props;
const { name, id } = useSafeNameId(props.name, props.id);
const focusHandler = useMarkOnFocusHandler(markAllOnFocus);
Expand Down Expand Up @@ -57,6 +59,8 @@ const InputInternal = <T extends FieldValues>(props: InputProps<T>) => {
}}
min={rangeMin}
max={rangeMax}
minLength={minLength}
maxLength={maxLength}
rows={textAreaRows}
multiple={multiple}
disabled={formDisabled || disabled}
Expand Down
14 changes: 14 additions & 0 deletions src/lib/types/CommonInputProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ interface CommonInputProps<T extends FieldValues, TRenderAddon = unknown> {
* hide the validation message for the input
*/
hideValidationMessage?: boolean;

/**
* Component prop that represents the minlength attribute for the input element
* @type {number}
* @example <Input<T> type="text" minlength={0} />
*/

minLength?: number;
/**
* Component prop that represents the maxlength attribute for the input element
* @type {number}
* @example <Input<T> type="text" maxlength={10} />
*/
maxLength?: number;
}

export { CommonInputProps };
Loading