Skip to content

v2.0.0

Choose a tag to compare

@vermorag vermorag released this 26 Oct 17:45
· 65 commits to main since this release
Immutable release. Only release title and notes can be modified.
5e4dff9

The library has been migrated from Vue 2 / webpack 3 to Vue 3.5 and Vite 8. Backward compatibility with 1.x is not preserved; the full migration guide with a step-by-step checklist and ready-made grep commands is in CHANGELOG.md.

Breaking changes

Environment and packaging

  • Peer dependency vue ^3.5; Node ≥ 24 to build. Vue 2 is no longer supported.
  • ESM-only package with an exports map. UMD builds dist/at.js / dist/at.min.js and the global at are removed.
  • Locales moved to @amazingcat/cattr-ui/locale/<lang> (ESM) from dist/locale/<lang>.js (UMD).
  • Internal at-ui/src/... imports are gone; the at-ui bundler alias is no longer needed.
  • The at-ui-style workspace package is renamed to cattr-ui-style (private). Theme customization via $var: …; @import no longer works — use @use '@amazingcat/cattr-ui/src/stylesheet/src/index.scss' with (…).

Installation API

  • Vue.use(CattrUI, opts) → createApp(App).use(CattrUI, opts). Auto-registration through window.Vue is removed.
  • Components are exported under At* names (AtButton, AtSelect, …); the default export is { install, version } only. Services are available as app.config.globalProperties.$Message/$Modal/$Notify/$Loading and as named exports Message, Dialog, Notification, LoadingBar.
  • i18n hook: app.use(CattrUI, { i18n: (key, values) => … }); the implicit Vue.locale / $t prototype detection is removed.

Template API

  • v-model on every component now uses modelValue / update:modelValue (Input, InputNumber, Textarea, Checkbox, CheckboxGroup, Radio, RadioGroup, RadioButton, Select, Switch, Slider, Rate, Modal, Tabs, Collapse, Dropdown, Tooltip, Popover). Manual :value + @input bindings must become :model-value + @update:model-value.
  • The .native modifier is gone: @click.native → @click. Button no longer emits its own click; consumer listeners fall through to the native <button>.
  • Input and InputNumber use inheritAttrs: false: class/style stay on the wrapper, all other attributes and listeners (@keyup.enter, id, aria-*, data-*) go to the native <input>. @input on these components is now the native event, not the component's.
  • Slot syntax slot="name" → <template #name> (#menu on Dropdown, #title on Submenu, #header/#footer on Modal, #title/#content on Popover, #title/#extra/#loading on Card).
  • Table column render signature: render: (h, params) → render: ({ item, column, index }) with h imported from vue and Vue 3 VNode format. index is now the row index (it was the column index due to a shadowed variable).
  • Select no longer inherits the popover mixin: props title, content, header and the toggle event are removed; placement supports top* / bottom* only.
  • Event semantics: on-change on Select, Rate, Tabs, Textarea and radio-group-change on RadioGroup fire only on user interaction, not on programmatic value changes. Menu on-select fires once per click (was once per nesting level). Modal OK emits a single on-confirm (it used to emit on-cancel afterwards too).
  • Services: $Notify(...) returns a close function instead of a component instance. Services must be called after app.use(CattrUI) (or after app.use(<Service>)). $Modal status dialogs default to English titles (Info, Success, Warning, Error).
  • Removed: AtForm, AtFormItem (never exported in 1.x) and their dispatch('AtFormItem', …) plumbing in Input/InputNumber/Textarea.
  • Styles: Vue 3 transition classes (-enter-from / -leave-from instead of -enter / -leave) for custom animations; the grid no longer overrides the global $screen-* variables after import ($screen-sm-max is 767px, not 991px).

Minor changes

  • Prebuilt CSS in the package: @amazingcat/cattr-ui/style.css, style.min.css and fonts under dist/css/fonts; Sass is only needed for custom themes.
  • Styles compile with sass-embedded; SCSS sources migrated to Sass modules (@use / @forward), theme variables are overridable through @use … with (…), no Dart Sass deprecation warnings.
  • Named At* exports enable tree-shaking and per-component app.use(AtButton).
  • Pagination emits update:current and update:pageSize, enabling v-model:current / v-model:page-size.
  • Tabs, Collapse and Dropdown now have a two-way v-model (in 1.x they never emitted input).
  • Notification gains closeAll(); the close functions returned by $Message(...) and $Notify(...) expose .id; close(id) now hides the item and calls its onClose.
  • $Modal: dialogs are queued and shown one after another; callback and the returned promise work together; Escape, the close icon and the mask resolve as 'cancel'; closeOnPressEsc is honoured; new props showCancelButton, showConfirmButton, inputValue, inputPlaceholder, new event after-leave.
  • Services can be installed standalone (app.use(Dialog)): Modal registers its own Button/Input dependencies.
  • Button/ButtonGroup, Radio/RadioGroup, Checkbox/CheckboxGroup, Tabs, Steps, Timeline, Collapse, Menu, Select, Breadcrumb and Dropdown use provide/inject: children work at any depth and react to parent prop changes.
  • Keyboard handling uses event.key (Select, Pagination, Modal); Pagination accepts numpad digits.
  • LoadingBar: config({ width }) applies to the visible bar; destroy() added.
  • Documentation site on Vite + vue-router 5 + vue-i18n 11, deployed to GitHub Pages; CI workflow with lint (--max-warnings 0), Prettier, Vitest with coverage thresholds and a PR coverage comment.
  • Tooling: ESLint 10 flat config, eslint-plugin-vue 10, Prettier 3, Vitest 5 — 42 spec files, 222 tests.

Patches

  • Message: closeAll() closed only every other message; close(id) removed the message from the stack without hiding it; a message opened from onClose was shifted above the viewport.
  • Notification: same close/stacking fixes; custom icon now works without type.
  • Modal/Dialog: the dialog queue never worked (every call opened a new dialog); promises hung when the dialog was closed by Escape, the close icon or the mask; close() in the same tick as alert()/confirm() still showed the dialog; the keydown listener was never removed (beforeDestory typo).
  • Table: row selection checkbox toggled the wrong row after sorting or on later pages; the "select all" checkbox in fixed-height mode toggled twice per click; the resize listener was never removed (beforeDestory typo); render cell received the column index instead of the row index.
  • Tabs: closing an active unnamed pane selected a pane that no longer existed after removal; closing a pane before an active unnamed pane broke the selection; on-change fired on mount and on programmatic changes.
  • Select: keyboard navigation only scrolled the list downwards; scroll-into-view depended on offsetParent; clearing a filterable select left the stale filter applied; the keydown listener was never removed.
  • Collapse: in-place mutations of the bound array (push, splice) did not update the panes.
  • InputNumber: external modelValue changes were ignored; typed values were discarded; change fired twice per click; emits at min/max boundaries preserved.
  • Rate: on-change fired twice per click; Textarea: emitted on external value changes.
  • Popover/Tooltip: not positioned when opened through v-model or mounted with modelValue: true; mixin listeners are now removed on unmount.
  • Pagination: the upper clamp of the page number was dead code (quickjump accepted 999); root HTML comments made the component a fragment and dropped consumer attributes.
  • LoadingBar: start() right after finish()/error() was cancelled by the previous hide timer; height: 4px !important ignored config({ width }).
  • Timeline: the pending class was not removed when pending turned off. Steps/Collapse: first render no longer flashes with index = -1.
  • Breadcrumb: separator is reactive and the first render is no longer empty; clicking without a router no longer throws.
  • Slider: track width is measured on each event (stale cached width on resize); handle moves immediately on drag.