# Changelog

All notable changes to this project will be documented in this file.

---


## [6.0.2] — 2026-07-23

> Masking layer migrated from the abandoned `react-text-mask` + `text-mask-addons` (both last published Oct 2022, no React 19 support) to the actively-maintained `react-imask` (v7). Behavior and appearance are preserved, including the guide placeholder template for the fixed-pattern masks.

### Changed

- **`MaskedTextInput` now renders `react-imask`'s `<IMaskInput>`** instead of `react-text-mask`'s `<MaskedInput>`. The public API is unchanged: same props (except the two react-text-mask-only props removed below) and the same `onChange` contract — the emitted event's `target.value` is the masked string and `target.rawValue` is the unmasked string. Change events now flow through IMask's `onAccept` (fired per *accepted* change) rather than a per-keystroke DOM `change`; the manual currency dot-removal caret shift was removed because IMask manages caret positioning itself. The render-side value normalization (`formatCurrency` + the dotless-value decimal insertion for currency, and the leading-`0` fix for percent) is unchanged.
- **`MaskedTextInput/masks.js` mask definitions rewritten as IMask configs.** `createMaskAndUnmask(type, options)` now returns `{maskOptions, unmask}` (was `{mask, unmask}`), where `maskOptions` is spread onto `<IMaskInput>`. All `unmask` functions are unchanged. Currency/percent/number use IMask `Number` masks; phone/ssn/taxId use pattern masks (`(000) 000-0000`, `000-00-0000`, `00-0000000`). The `$` prefix and `%` suffix are composed via pattern blocks; the max integer-digit limits (currency 8, percent 3) are enforced via a numeric `max` bound; a negative currency value keeps the sign before the prefix (`-$1,000.00`) via a dynamic mask.
- **`util/number.js` `formatPhone` / `formatPhoneNoAreaCode`** now use `IMask.createPipe` instead of `react-text-mask`'s `conformToMask`. Output is byte-for-byte identical to before (verified by the existing tests), including the trailing-literal cases (`'555' → '(555) '`, `'123' → '123-'`).

### Removed

- **`react-text-mask`** and **`text-mask-addons`** dropped from `dependencies`. (`inputmask`, used by `CurrencyInput`, is a different library and is untouched.)
- **`keepCharPositions`, `pipe` props** removed from `MaskedTextInput` — react-text-mask-specific with no react-imask equivalent (neither was in use). `placeholderChar` (default `'_'`) is retained.

### Added

- **`react-imask` `^7.6.1`** to `dependencies` (bundles `imask`; peer-compatible with React 19).
- **`NegativeCurrency` Storybook story** for `MaskedTextInput`, showcasing the sign-before-prefix negative currency display (`-$1,234.56`).

### Notes

- **Guide/placeholder template preserved** — as with react-text-mask's default `guide: true`, a partially-filled phone/ssn/taxId shows the `_` template (e.g. `(555) ___-____`), an empty field shows nothing, and a complete value shows the value. Implemented by driving `<IMaskInput>`'s `lazy` from whether the value is empty, with the `placeholderChar` prop as the template character.
- **Leading zeros in the plain number mask** — a pathological input like `'007'` now conforms to `'007'` (react-text-mask's `createNumberMask` collapsed it to `'0'`). Left as-is: the old output was itself a `createNumberMask` artifact and normal values are unaffected.
- Tests exercising the masked input drive it with `fireEvent.input` (not `fireEvent.change`, which IMask does not observe). Characterization tests cover controlled display, typing, the value/rawValue contract, the digit limits, and the guide template for all six mask types.


## [6.0.1] — 2026-07-20

### Fixed

- **`DatePicker` — `initialMonth` prop works again** — after the migration to the v8+ `DayPicker` API, `initialMonth` had become a no-op: it was written into `state.month`, but the displayed month was driven by `defaultMonth={dateValue}` (the selected date, or today) and `state.month` was never read anywhere. `initialMonth` is now passed through to `defaultMonth`, so the calendar opens on the requested month when the prop is set, falling back to the selected date (or today) otherwise. The orphaned `state.month` / `handleYearMonthChange` carry-over from the old controlled-month API was removed.


---

## 🎉 [6.0.0] — 2026-07-14

> React 18 → 19 upgrade. Major version bump because the React 19-only peer requirement is a breaking change for consumers not yet migrated to React 19. The ui-kit's own code was already React-19-ready (no `ReactDOM.render`/`findDOMNode`/string refs/legacy context; the `defaultProps` in `TableBase`/`DatePicker`/`Button`/`NotificationBar` are all on class components, which React 19 still supports). The only breakage was transitive `ReactDOM.findDOMNode` (removed in React 19) reached through three dependencies, each fixed below.

### Breaking Changes

- **Peer dependency is now React 19 only** — `peerDependencies.react` / `react-dom` moved from `18.x` to `19.x`. Consuming apps must be on React 19 before updating to this version. `prop-types` (15.x) is unchanged; `propTypes` and class-component `defaultProps` still function under React 19.

### Changed

- **react-transition-group `findDOMNode`** — `NotificationBar`'s `<CSSTransition>` relied on the default `findDOMNode` code path (removed in React 19). It now passes a `nodeRef` (`React.createRef()`) that is attached to the animated `<div>`, the officially recommended replacement. No behavior or API change.
- **react-draggable `findDOMNode`** — `SplitWindowWrapper`'s `<DraggableCore>` now receives a `nodeRef` (`useRef`) attached to the separator `<div>`. react-draggable 4.7.0 (already installed) requires `nodeRef` under React 19 and throws without it; the separator drag now works on React 19.
- **`ClickOutsideWrapper` rewritten without `react-onclickoutside`** — the `react-onclickoutside` HOC calls `ReactDOM.findDOMNode` unconditionally and is unmaintained (no React 19 support), so it was replaced with a small functional component. It clones its single child to attach a `ref` and listens on `document` for `mousedown` + `touchstart` (passive, bubble phase), firing `onClickOutside` when the event target is outside the child — matching react-onclickoutside's default `eventTypes` and outside-detection semantics. The DOM structure is unchanged (the child element is still the reference node, exactly as `findDOMNode` returned it), so the consumers (`ActionButton`, `TimePicker`, `DropdownWrapper`, `DatePicker`) and the public `children`/`onClickOutside` API are unchanged.

### Removed

- **`react-onclickoutside`** — dropped from `dependencies`; the only consumer (`ClickOutsideWrapper`) no longer uses it (see above).
- **`react-test-renderer`** — dropped from `devDependencies`. It was deprecated in React 19 and was not imported by any test or config.

### Notes

- **react-virtualized (custom fork) is safe as used** — the fork still ships `findDOMNode` calls in `CellMeasurer`/`WindowScroller`, but `TableBase` only imports `Table`/`Column`/`SortDirection`/`defaultRowRenderer`/`AutoSizer`. Those never call `findDOMNode` at runtime (the `import {findDOMNode}` in `Table.js` is unused and resolves to `undefined` under React 19 without being invoked), so no patch was needed. The remaining runtime dependencies (`react-select`, `react-modal`, `react-day-picker`, `rc-tooltip`, `react-contexify`, `react-dropzone`, `@dnd-kit/*`, `react-text-mask`, `react-spinkit`) already accept React 19 in their peer ranges.

### Tests

- **`DocumentTitle` mock (`FailurePage`, `FailureChunkPage`, `FailureInternalPage`)** — React 19 auto-hoists `<title>`/`<meta>`/`<link>` to `<head>`, so the test mock that rendered `<title>{title}</title>` moved out of the query root and `getByText` could no longer find it. The mock now renders `<span>{title}</span>`; the real `DocumentTitle` (which sets `document.title` via lifecycle methods) is unaffected by React 19.
- **`InputWithX` / `TextInputWithX` prop assertions** — React 19 no longer invokes function components with the legacy second (context) argument that React 18 passed as `{}`, so `toHaveBeenCalledWith(objectContaining({…}), {})` failed on the now-absent `{}`. These assertions now read the first argument directly via `mock.calls[0][0]`, matching the existing `icon`-prop assertion in the same files.
- Full suite: **1442 tests / 118 suites passing**; `rollup -c` and `storybook build` both succeed.

---

## [5.0.10] — 2026-07-20

### Fixed

- **`DatePicker` — `initialMonth` prop works again** — after the migration to the v8+ `DayPicker` API, `initialMonth` had become a no-op: it was written into `state.month`, but the displayed month was driven by `defaultMonth={dateValue}` (the selected date, or today) and `state.month` was never read anywhere. `initialMonth` is now passed through to `defaultMonth`, so the calendar opens on the requested month when the prop is set, falling back to the selected date (or today) otherwise. The orphaned `state.month` / `handleYearMonthChange` carry-over from the old controlled-month API was removed.

---

## [5.0.8] — 2026-07-13

### Changed

- **date-fns 1 → 4** — migrated off the removed v1 snake_case submodule imports (`date-fns/is_valid`, `date-fns/sub_days`, …) to v4 named imports (`import {isValid, subDays} from 'date-fns'`) across `util/date`, `TableBase`, `DatePicker`, and `DateRangePicker`. Because v2+ changed `format` to Unicode tokens and `parse` to a new signature, `format`/`parse` now go through a small compat layer (`src/util/dateFnsCompat.js`) that:
  - translates the legacy format tokens the ui-kit and its consumers rely on (`YYYY→yyyy`, `DD→dd`, `dddd→EEEE`, `Do→do`, `A→a`, `Z→xxx`, literal letters quoted, …) so existing format strings keep working, and returns `'Invalid Date'` for invalid input (matching v1);
  - restores v1's flexible `parse` — accepts `Date`, timestamp, ISO string (`parseISO`), or falls back to native `Date` parsing for `MM/DD/YYYY` strings.

  This keeps the public `formatDate` / `createDateRangeString` APIs backward-compatible: callers may still pass v1-style format strings. The dead `date-fns/*` entries were removed from the jest `moduleNameMapper`. (react-day-picker keeps its own internal date-fns@4; this change is the ui-kit's own date-fns.)

---

## [5.0.7] — 2026-07-13

### Changed

- **react-day-picker 9 → 10** — dependency bump; no component or CSS changes were required. The `DayPicker` props, the custom `Nav`/`MonthCaption` components, the `useDayPicker` context fields, and the generated `rdp-*` DOM class names relied on by `DatePicker`, `DateRangePicker`, and `CustomMonthSelect` are unchanged between v9 and v10. v10 bundles its own `date-fns@4` internally; the ui-kit's own `date-fns` (1.29.0) is unaffected.

---

## [5.0.6] — 2026-07-13

### Changed

- **react-dropzone 15 → 17** — dependency bump; no code changes were required. The `<Dropzone>` component API used across `AvatarUploader`, `SVGUploader`, `FileUploader`, and `FileInput` (render-prop children and the `ref.open()` imperative method) is unchanged. v17 raises its React peer dependency to `>= 18`, which the ui-kit already requires.

---

## [5.0.5] — 2026-07-13

### Changed

- **cropperjs 1 → 2** — `AvatarUploader`'s image cropper was migrated to the cropperjs v2 API (a full rewrite based on web components), matching the implementation used by the PhotoWidget in the sadio app. `AvatarEditModal` builds the cropper from a custom `template` (a square `cropper-selection` over a non-transformable `cropper-image`). On init the image is centered with `$center('contain')`, the selection starts as a centered square at 80% of the image, and a `change` listener keeps the selection within the image bounds. Cropping uses `selection.$toCanvas({width: 500, height: 500})` (async) in place of the removed `getCroppedCanvas`, and the upload-in-progress lock toggles `cropper-canvas.disabled` (v2 removed `enable()`/`disable()`). The `AvatarUploader` public props are unchanged.
- **cropperjs stylesheet no longer needed** — v2 styles its web components via shadow DOM and ships no CSS file, so the `import 'cropperjs/dist/cropper.css'` was removed. The cropper canvas/selection/shade are sized and styled from `avatarUploader.module.css` (square canvas via `aspect-ratio: 1`); consumers no longer need to load any cropper stylesheet.

---

## [5.0.4] — 2026-07-13

### Changed

- **react-contexify 3 → 6** — `Popover` was migrated to the react-contexify v6 API. The v3 `ContextMenu` (and the `react-contexify/lib/components/ContextMenu` deep import that was used to bypass the old `withProxy` HOC) was replaced with `<Menu animation="fade">`. `Popover` children are rendered directly into `<Menu>` so react-contexify's `Item` components still receive their `propsFromTrigger`/`triggerEvent` data.
- **`Popover` props** — added `style` and `onVisibilityChange`, both forwarded to the underlying `<Menu>`. Existing `id`/`className`/`children` are unchanged. `Popover` now matches the component used in the ezadmin app.

### Breaking Changes

- **`PopoverTrigger` removed** — the ui-kit no longer ships a trigger component. Showing/hiding a `Popover` is now the calling component's responsibility, using react-contexify's imperative API: `contextMenu.show({id, event})` (and `contextMenu.hideAll()`), imported from `react-contexify`. To anchor the menu directly below the trigger, pass a `position` derived from the trigger's bounding rect, e.g. `contextMenu.show({id, event, position: {x: rect.left, y: rect.bottom}})`.

### Consumer migration note

- **react-contexify base CSS** — apps that render `Popover` must import the v6 stylesheet **`react-contexify/ReactContexify.css`** (v6 renamed its classes to the `.contexify*` namespace). The ui-kit does not bundle it, matching the prior v3 behavior; Storybook imports it in `.storybook/preview.js` for the Popover stories.
- **Optional look-and-feel override** — `src/Popover/react-contexify-overide.css` is a copy of the override used by the ezadmin app. It sets the `--contexify-*` CSS variables (squared corners, padding, `fit-content` width, …) and item hover/focus styles so the menu matches ezadmin's appearance. It is **not shipped** by the ui-kit — it is imported by the Popover story for parity with ezadmin and provided as a reference consumers can copy into their own app to reproduce that look.

### Tests

- Rewrote the Popover unit tests for the v6 `Menu` mock surface and added an integration test that renders the real react-contexify v6 to assert the caller's `contextMenu.show` opens the menu and that content components receive no leaked DOM props.

---

## [5.0.3] — 2026-07-10

> Dependency cleanup and build-tooling upgrade. No public component API changes — the built bundle exports the same 74 entries and identical CSS.

### Removed

- **Unused dependencies removed** — `highcharts`, `react-tooltip`, `uuid`, `sass-loader`, `babel-plugin-macros`, and `require-context.macro` were not imported anywhere in `src/` and have been dropped from `package.json`. `highcharts` and `react-tooltip` were runtime `dependencies`; the rest were dev-only. `babel-plugin-macros` (the `"macros"` Babel plugin) and `require-context.macro` were vestiges of the pre-Storybook-8 story-loading setup; there are no `.macro` imports in the codebase. The vestigial `"macros"` plugin was also removed from `.babelrc`.

### Changed

- **Rollup 2 → 4** — the bundle build was upgraded from `rollup ^2.80.0` to `^4.62.2`. The deprecated `rollup-plugin-babel` and `rollup-plugin-url` were replaced with the maintained `@rollup/plugin-babel` (`runtimeHelpers: true` → `babelHelpers: 'runtime'`) and `@rollup/plugin-url`. `rollup.config.js` was renamed to `rollup.config.mjs` and loads `package.json` via `fs` (Rollup 4 loads the config as native ESM). The output is functionally identical — same exports, same CSS — and ~14% smaller thanks to Rollup 4's stronger tree-shaking (unused CSS-module class keys, dead branches, and unused object properties are now eliminated).
- **Patch/minor dependency bumps** — `immer` 11.1.8 → 11.1.11, `postcss-preset-env` 11.3.0 → 11.3.2, `webpack` → 5.108.4, `prettier` 3.8.1 → 3.9.5, `spacetime` 7.12.0 → 7.13.0, `react-draggable` 4.5.0 → 4.7.0.

### Fixed

- **Prettier config** — replaced the deprecated `jsxBracketSameLine` option (removed in favor of `bracketSameLine`) in `src/.prettierrc.js`. The codebase was already formatted with the option effectively off, so no files were reformatted.

---

## [5.0.2] — 2026-07-10

### Fixed

- **DropdownWrapper** — `ClickOutsideWrapper` now wraps the whole component instead of just the arrow icon, so the menu closes only on genuine outside clicks; previously clicks on the menu options or the wrapped children counted as "outside" and could close the menu.
- **DropdownWrapper stories — docs source crash** — the rich-label example stories crashed the story render with `RangeError: Maximum call stack size exceeded` in Storybook's docs source serializer (`react-element-to-jsx-string`) because their options carry React elements as `label`s, which the serializer recursed into. Setting `docs.source.type` to `'code'` on those stories makes the "Show code" panel display the static source instead of dynamically serializing the runtime element tree.
- **DropdownWrapper stories — missing required prop** — the shared story template rendered `TextInput` without its required `name` prop (triggering a prop-type warning); it is now a controlled field with `name`/`label`.

### Added

- **DropdownWrapper stories** — the wrapped field now uses the real `TextInput`/`CurrencyInput` components instead of a bare `<input>`, and two examples modeled on ezadmin's PatientInsurancePage "Policy Benefits" form were added: `SuggestedAmounts` (a `CurrencyInput` with suggested eligibility amounts) and `SuggestedPercentages` (a `TextInput` for co-insurance). Both use rich multi-line option labels and write the selected value back into the field.

---

## [5.0.1] — 2026-07-10

### Fixed

- **react-dropzone v5 → v15 crash** — `SVGUploader`, `FileUploader`, and `FileInput` threw `children is not a function` under react-dropzone v15. Migrated to the v15 API: `<Dropzone>` children are now a render function using `getRootProps`/`getInputProps`; `accept` uses the object-of-MIME-types format (`FileInput` still accepts its legacy comma-separated string prop and converts it internally); `disableClick` was replaced with `noClick`/`noKeyboard`; and `className`/`activeClassName` are applied through `getRootProps` using `isDragActive`.
- **Dropzone image preview** — v15 no longer attaches `file.preview` to dropped files, so `SVGUploader` and `FileUploader` now create the object URL themselves via `URL.createObjectURL` (`FileTile` revokes it on unmount). This restores image-preview rendering after a drop.
- **array-move v2 → v4 crash** — drag-to-reorder threw `arrayMove is not a function` because v4 dropped its default export. `MultiSelect` and the `TableSettings` column customizer now use the named `arrayMoveImmutable` export.
- **MultiSelect** — the item being dragged is now highlighted with a white background, and the remove ("×") button background color was corrected.
- **CurrencyInput** — an empty field now displays `$0.00` instead of rendering blank, and its floating label stays raised (as with a populated field) rather than dropping to the placeholder position.
- **Storybook** — fixed and expanded component stories with interactive/editable controls (MaskedTextInput phone/SSN/tax-id masks, TableSettings/TableSettingsModal reorder & revert-on-cancel, AdvancedFilter modal, EditableBodyCell input/select, EditableCellBaseInline formatted-value edit-and-blur, SVGUploader, Avatar scale-on-hover).

---

## 🎉 [5.0.0] — 2026-06-01

> **Breaking release.** Requires React 18. Multiple major third-party dependencies were upgraded or replaced with breaking API changes.

### Breaking Changes

- **React 18 required** — peer dependency changed from `react ^16.x` to `react ^18.x`. React 16 and 17 are no longer supported.
- **react-day-picker v7 → v9** — complete API rewrite. `DatePicker` and `DateRangePicker` were refactored to match the new `mode`/`onSelect`/`useDayPicker` API. The old `navbarElement`, `disabledDays`, and `selectedDays` props are gone.
- **react-select v3 → v5** — `innerRef` pattern replaced by standard React ref forwarding. Some internal emotion class names changed.
- **Enzyme removed** — `enzyme` and `enzyme-adapter-react-16` have been removed. Tests are now written with React Testing Library.

### Added

- Full test suite using `@testing-library/react ^16.3.2` covering Select, DatePicker, DateRangePicker, FileTree, and their subcomponents.
- `@testing-library/jest-dom` for extended DOM matchers.
- Custom SVGR jest mock (`jestSvgrMock.js`) replacing the removed `jest-svg-transformer`.
- Storybook 8 for visual component development. All stories updated to CSF3 format with required `default export`.
- `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/utilities` — drag-and-drop primitives replacing `react-sortable-hoc`.

### Changed

- **DatePicker** — Refactored for react-day-picker v9. Fixed month/year navigation, disabled-day modifiers, and calendar overlay positioning. `openMenuUp` now correctly applies the upward overlay class.
- **DateRangePicker** — Refactored for react-day-picker v9. Range selection state (`from`, `to`, `enteredTo`) now managed correctly with the new `onSelect`/`onDayMouseEnter` API. Fixed dropdown display and `closeDropDown` timing.
- **FileTree** — Replaced `react-treebeard` with a custom recursive `TreeView` component. The decorator mutation pattern is gone; the tree is now rendered via a render prop. The component's external prop API is unchanged.
- **TableBase/ColumnsCustomizer** — Replaced `react-sortable-hoc` HOC pattern with `@dnd-kit/sortable` hooks. The `onSortEnd({oldIndex, newIndex})` callback interface is preserved — no changes required in consuming code.
- **Select** — Fixed `@emotion/core` import (removed in react-select v5) to `@emotion/react`.
- **MaskedTextInput** — Fixed `disabled` prop not correctly suppressing user input.
- **EditableCell** — Fixed error message display when validation fails.
- **AvatarUploader** — Fixed SVG icon import that broke under the new Rollup/SVGR build pipeline.
- **CurrencyInput** — Fixed formatting edge cases surfaced by the jest 30 test run.
- Modernized test patterns to align with current Testing Library/Jest behaviour (`waitFor`, stable query usage, supported matchers).
- Improved resilience of timezone conversion logic and fallback behaviour for invalid timezone inputs.
- Corrected Jest/date-fns v1 module aliasing so tests resolve legacy underscore paths reliably.
- Resolved Immer compatibility break by switching to named `produce` import in array utilities.
- Patched flaky interaction tests across multiple components (submenu hover, blur/unmount timing, async state update timing, matcher API updates).
- Added local Jest mocks for `array-move` in affected suites to avoid ESM parse failures under current Jest transform settings.
- Fixed timezone utility formatting/parsing edge cases and stabilized timezone-dependent test expectations to remove environment-specific failures.
- Fixed Storybook preview — removed reference to missing build artifact `dist/ezderm-ui-kit-light.esm.css`; source CSS files are imported directly instead.

### Removed

- `react-treebeard` — replaced by a custom recursive `TreeView` render-prop component in `src/FileTree/TreeView.js`.
- `react-sortable-hoc` — replaced by `@dnd-kit/sortable`. The `useDragHandle` and `helperClass` props on `ColumnsCustomizer` are no longer accepted.
- `enzyme` and `enzyme-adapter-react-16` — replaced by React Testing Library.
- `jest-svg-transformer` — replaced by a custom SVGR mock.

### Dependency Upgrades

| Package            | From  | To     |
| ------------------ | ----- | ------ |
| `react` (peer)     | ^16.x | ^18.x  |
| `react-dom` (peer) | ^16.x | ^18.x  |
| `react-day-picker` | 7.1.9 | 9.14.0 |
| `react-select`     | 3.1.0 | 5.10.2 |
| `immer`            | ^9.x  | ^11.x  |
| `highcharts`       | ^7.x  | ^12.x  |
| `react-dropzone`   | ^3.x  | ^15.x  |
| `react-tooltip`    | ^3.x  | ^5.x   |
| `rc-tooltip`       | ^3.x  | ^6.x   |
| `react-draggable`  | ^3.x  | ^4.x   |
| `inputmask`        | ^4.x  | ^5.x   |
| `file-saver`       | ^1.x  | ^2.x   |
| `spacetime`        | ^4.x  | ^7.x   |
| `array-move`       | ^2.x  | ^4.x   |
| `uuid`             | ^3.x  | ^13.x  |

### New Dependencies

| Package              | Version | Purpose                                            |
| -------------------- | ------- | -------------------------------------------------- |
| `@dnd-kit/core`      | ^6.x    | Drag-and-drop engine (replaces react-sortable-hoc) |
| `@dnd-kit/sortable`  | ^10.x   | Sortable list primitives                           |
| `@dnd-kit/utilities` | ^3.x    | CSS transform helpers for dnd-kit                  |

### Removed Dependencies

| Package              | Replaced by                 |
| -------------------- | --------------------------- |
| `react-sortable-hoc` | `@dnd-kit/sortable`         |
| `react-treebeard`    | Custom `TreeView` component |

### Dev Tooling Upgrades

| Package                  | From    | To      |
| ------------------------ | ------- | ------- |
| `@storybook/*`           | 6.5.16  | 8.x     |
| `jest`                   | ^24.9.0 | ^30.x   |
| `@testing-library/react` | ^9.3.0  | ^16.3.2 |
| `rollup`                 | ^1.24.0 | ^2.x    |
| `prettier`               | ^1.x    | ^3.x    |
