diff --git a/.all-contributorsrc b/.all-contributorsrc index 03c818670..a5dd02a27 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -123,10 +123,10 @@ ] }, { - "login": "probablyup", + "login": "quantizor", "name": "Evan Jacobs", "avatar_url": "https://avatars.githubusercontent.com/u/570070?v=4", - "profile": "https://probablyup.com", + "profile": "https://quantizor.dev", "contributions": [ "question", "code", diff --git a/.changeset/config.json b/.changeset/config.json index bc9a7d413..4f393048f 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -4,7 +4,7 @@ "commit": false, "linked": [], "access": "public", - "baseBranch": "master", + "baseBranch": "main", "updateInternalDependencies": "patch", "ignore": [] } diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b948465e4..605db9d96 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,6 @@ # Learn how to add code owners here: # https://help.github.com/en/articles/about-code-owners -* @jaredpalmer @probablyup -/docs/ @jaredpalmer @probablyup -/examples/ @jaredpalmer @probablyup \ No newline at end of file +* @jaredpalmer @quantizor +/docs/ @jaredpalmer @quantizor +/examples/ @jaredpalmer @quantizor \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b58951398..1193bd4d0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -69,8 +69,8 @@ git remote add upstream https://github.com/formik/formik.git 3. Synchronize your local `next` branch with the upstream one: ```sh -git checkout master -git pull upstream master +git checkout main +git pull upstream main ``` 4. Install the dependencies with [yarn](https://yarnpkg.com) (npm isn't supported): @@ -122,7 +122,7 @@ the results. If any of them fail, refer to [Checks and how to fix them](#checks- Make sure the following is true: -- The branch is targeted at `master` for ongoing development. We do our best to keep `master` in good shape, with all tests passing. Code that lands in `master` must be compatible with the latest stable release. It may contain additional features, but no breaking changes. We should be able to release a new minor version from the tip of `master` at any time. +- The branch is targeted at `main` for ongoing development. We do our best to keep `main` in good shape, with all tests passing. Code that lands in `main` must be compatible with the latest stable release. It may contain additional features, but no breaking changes. We should be able to release a new minor version from the tip of `main` at any time. - If a feature is being added: - If the result was already achievable with the library, explain why this feature needs to be added. - If this is a common use case, consider adding an example to the documentation. diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml deleted file mode 100644 index 0d3976027..000000000 --- a/.github/workflows/benchmark.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Performance - -on: - pull_request: - push: - branches: [main] - -jobs: - benchmark: - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - node: ['18.x'] - - name: Test on node ${{ matrix.node }} - - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v3 - with: - cache: yarn - node-version: ${{ matrix.node }} - - - name: Install & build - run: | - node --version - npm --version - yarn --version - yarn install --frozen-lockfile - yarn build:benchmark - - - name: Download previous benchmark data - uses: actions/cache@v3 - with: - path: ./benchmark-cache - key: ${{ runner.os }}-benchmark - - - name: Run benchmark - run: yarn benchmark - - - name: Store benchmark result - uses: benchmark-action/github-action-benchmark@v1 - with: - tool: benchmarkjs - external-data-json-path: ./benchmark-cache/benchmark-data.json - output-file-path: output.txt - # comment for PRs that's updated with current perf relative to baseline (main) - summary-always: true - # warn if slowness is detected; might be transient on rerun - alert-threshold: 110% - comment-on-alert: true - fail-on-alert: true - # if things get considerably slower, deny the PR - fail-threshold: 120% - # needed for commenting on PRs - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..a983f4fa9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,147 @@ +name: ci + +on: + pull_request: + push: + branches: [main] + +jobs: + detectChangedSourceFiles: + name: 'determine changes' + runs-on: ubuntu-latest + outputs: + changes: ${{ steps.changed-files-yaml.outputs.any_changed }} + steps: + - uses: actions/checkout@v4 + - name: Detect changed files + id: changed-files-yaml + uses: tj-actions/changed-files@v45 + with: + files: | + .github/workflows/ci.yml + packages/formik/src/** + packages/formik/package.json + packages/formik-native/src/** + packages/formik-native/package.json + + benchmark: + if: always() && needs.detectChangedSourceFiles.outputs.changes == 'true' + needs: detectChangedSourceFiles + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: yarn + node-version-file: .nvmrc + + - name: Install & build + run: | + node --version + npm --version + yarn --version + yarn install --frozen-lockfile + yarn build:benchmark + + - name: Download previous benchmark data + uses: actions/cache@v4 + with: + path: ./benchmark-cache + key: ${{ runner.os }}-benchmark + + - name: Run benchmark + run: yarn benchmark + + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: benchmarkjs + external-data-json-path: ./benchmark-cache/benchmark-data.json + output-file-path: output.txt + # comment for PRs that's updated with current perf relative to baseline (main) + summary-always: true + # warn if slowness is detected; might be transient on rerun + alert-threshold: 110% + comment-on-alert: true + fail-on-alert: true + # if things get considerably slower, deny the PR + fail-threshold: 120% + # needed for commenting on PRs + github-token: ${{ secrets.GITHUB_TOKEN }} + + interaction: + needs: detectChangedSourceFiles + if: always() && needs.detectChangedSourceFiles.outputs.changes == 'true' + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + cache: yarn + node-version-file: .nvmrc + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Get installed Playwright version + id: playwright-version + run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV + + - name: Cache playwright binaries + uses: actions/cache@v4 + id: playwright-cache + with: + path: | + ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} + + - name: Install Playwright Browsers + run: yarn playwright install --with-deps + if: steps.playwright-cache.outputs.cache-hit != 'true' + - run: yarn playwright install-deps + if: steps.playwright-cache.outputs.cache-hit != 'true' + + - name: Run Playwright tests + run: yarn playwright test + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 5 + + size: + needs: detectChangedSourceFiles + if: always() && needs.detectChangedSourceFiles.outputs.changes == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - uses: preactjs/compressed-size-action@v2 + with: + repo-token: '${{ secrets.GITHUB_TOKEN }}' + build-script: 'turbo run build --filter {./packages/*}...' + + unit: + needs: detectChangedSourceFiles + if: always() && needs.detectChangedSourceFiles.outputs.changes == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + cache: yarn + node-version-file: .nvmrc + - name: Install deps, build, and test + run: | + node --version + npm --version + yarn --version + yarn install --frozen-lockfile + yarn test --coverage + env: + CI: true + NODE_OPTIONS: --max-old-space-size=4096 \ No newline at end of file diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml deleted file mode 100644 index a720fa902..000000000 --- a/.github/workflows/playwright.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Playwright Tests -on: - push: - branches: [main] - pull_request: -jobs: - test: - timeout-minutes: 10 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - cache: yarn - node-version: 18 - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Get installed Playwright version - id: playwright-version - run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV - - - name: Cache playwright binaries - uses: actions/cache@v3 - id: playwright-cache - with: - path: | - ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} - - - name: Install Playwright Browsers - run: yarn playwright install --with-deps - if: steps.playwright-cache.outputs.cache-hit != 'true' - - run: yarn playwright install-deps - if: steps.playwright-cache.outputs.cache-hit != 'true' - - - name: Run Playwright tests - run: yarn playwright test - - uses: actions/upload-artifact@v3 - if: always() - with: - name: playwright-report - path: playwright-report/ - retention-days: 5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3770d5738..fcf9c2676 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,20 +9,20 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'jaredpalmer/formik' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: cache: yarn - node-version: 18 + node-version-file: .nvmrc - name: Install Dependencies run: yarn install - name: Create Release Pull Request or Publish to npm - uses: changesets/action@master + uses: changesets/action@1.4.8 with: publish: yarn release env: diff --git a/.github/workflows/size.yml b/.github/workflows/size.yml deleted file mode 100644 index 7c515450a..000000000 --- a/.github/workflows/size.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Compressed Size - -on: [pull_request] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - uses: preactjs/compressed-size-action@v2 - with: - repo-token: '${{ secrets.GITHUB_TOKEN }}' - build-script: 'turbo run build --filter {./packages/*}...' diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 4c149332b..f466b2798 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 30 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 7d06aaaa0..000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Unit Test - -on: - pull_request: - push: - branches: [main] - -jobs: - test: - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - node: ['18.x'] - - name: Test on node ${{ matrix.node }} - - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v3 - with: - cache: yarn - node-version: ${{ matrix.node }} - - - name: Install deps, build, and test - run: | - node --version - npm --version - yarn --version - yarn install --frozen-lockfile - yarn test --coverage - env: - CI: true - NODE_OPTIONS: --max-old-space-size=4096 diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..3f430af82 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v18 diff --git a/.vscode/settings.json b/.vscode/settings.json index 25fa6215f..11a40855a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ { - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": false, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, } diff --git a/docs/api/fastfield.md b/docs/api/fastfield.md index cd9d7b1bf..32fa48ee3 100644 --- a/docs/api/fastfield.md +++ b/docs/api/fastfield.md @@ -57,7 +57,8 @@ const Basic = () => ( alert(JSON.stringify(values, null, 2)); }, 500); }} - render={formikProps => ( + > + {formikProps => (
{/** This only updates for changes made to values.firstName, touched.firstName, errors.firstName */} @@ -66,8 +67,8 @@ const Basic = () => ( {/** Updates for all changes because it's from the top-level formikProps which get all updates */} - {form.touched.firstName && form.errors.firstName && ( -
{form.errors.firstName}
+ {formikProps.touched.firstName && formikProps.errors.firstName && ( +
{formikProps.errors.firstName}
)} @@ -105,7 +106,7 @@ const Basic = () => ( and all changes by all s and s */} - {() => ( + {({ field, form, meta }) => (
{/** Works because this is inside @@ -125,7 +126,7 @@ const Basic = () => ( )} - /> +
); ``` diff --git a/docs/api/field.md b/docs/api/field.md index 422493ec6..a2c1002c6 100644 --- a/docs/api/field.md +++ b/docs/api/field.md @@ -102,7 +102,7 @@ Either a React component or the name of an HTML element to render. That is, one - A valid HTML element name - A custom React component -Custom React components will be passed `onChange`, `onBlur`, `name`, and `value` plus any other props passed to directly to ``. +Custom React components will be passed `onChange`, `onBlur`, `name`, and `value` plus any other props passed directly to ``. Default is `'input'` (so an `` is rendered by default) diff --git a/docs/api/formik.md b/docs/api/formik.md index 307e58b17..a7e683e67 100644 --- a/docs/api/formik.md +++ b/docs/api/formik.md @@ -177,11 +177,13 @@ Set `errors` imperatively. Set the error message of a field imperatively. `field` should match the key of `errors` you wish to update. Useful for creating custom input error handlers. -#### `setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => void` +#### `setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => Promise` Set the touched state of a field imperatively. `field` should match the key of `touched` you wish to update. Useful for creating custom input blur handlers. Calling this method will trigger validation to run if `validateOnBlur` is set to `true` (which it is by default). `isTouched` defaults to `true` if not specified. You can also explicitly prevent/skip validation by passing a third argument as `false`. +If `validateOnBlur` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + #### `submitForm: () => Promise` Trigger a form submission. The promise will be rejected if form is invalid. @@ -191,7 +193,7 @@ Trigger a form submission. The promise will be rejected if form is invalid. Number of times user tried to submit the form. Increases when [`handleSubmit`](#handlesubmit-e-reactformeventhtmlformelement--void) is called, resets after calling [`handleReset`](#handlereset---void). `submitCount` is readonly computed property and should not be mutated directly. -#### `setFieldValue: (field: string, value: any, shouldValidate?: boolean) => Promise` +#### `setFieldValue: (field: string, value: React.SetStateAction, shouldValidate?: boolean) => Promise` Set the value of a field imperatively. `field` should match the key of `values` you wish to update. Useful for creating custom input change handlers. Calling this will trigger validation to run if `validateOnChange` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a third argument as `false`. @@ -208,14 +210,18 @@ use it to pass API responses back into your component in `handleSubmit`. Set `isSubmitting` imperatively. You would call it with `setSubmitting(false)` in your `onSubmit` handler to finish the cycle. To learn more about the submission process, see [Form Submission](../guides/form-submission.md). -#### `setTouched: (fields: { [field: string]: boolean }, shouldValidate?: boolean) => void` +#### `setTouched: (fields: { [field: string]: boolean }, shouldValidate?: boolean) => Promise` Set `touched` imperatively. Calling this will trigger validation to run if `validateOnBlur` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as `false`. -#### `setValues: (fields: React.SetStateAction<{ [field: string]: any }>, shouldValidate?: boolean) => void` +If `validateOnBlur` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + +#### `setValues: (fields: React.SetStateAction<{ [field: string]: any }>, shouldValidate?: boolean) => Promise>` Set `values` imperatively. Calling this will trigger validation to run if `validateOnChange` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as `false`. +If `validateOnChange` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + #### `status?: any` A top-level status object that you can use to represent form state that can't diff --git a/docs/api/useField.md b/docs/api/useField.md index b9065b432..e22245ffe 100644 --- a/docs/api/useField.md +++ b/docs/api/useField.md @@ -3,7 +3,7 @@ id: useField title: useField() --- -`useField` is a custom React hook that will automagically help you hook up inputs to Formik. You can and should use it to build your own custom input primitives. There are 2 ways to use it. +`useField` is a React hook used to thread Formik behaviors into arbitrary field components. It provides the greatest amount of flexibility for scenarios where `Field` is inappropriate. There are two ways to use it. ## Example @@ -18,7 +18,7 @@ interface Values { } const MyTextField = ({ label, ...props }) => { - const [field, meta, helpers] = useField(props); + const [field, meta] = useField(props); return ( <>