Skip to content

Releases: cattr-app/ui-kit

v2.1.0

Choose a tag to compare

@vermorag vermorag released this 29 Oct 12:18
Immutable release. Only release title and notes can be modified.
9abe898

New features

  • AtSkeleton — animated loading placeholders with configurable dimensions, count, circular shapes, and theme variables. Automatically displays a placeholder when its default slot is empty.
  • AtAvatar — user pictures with initials as a fallback, configurable colors and sizes, custom initials generation, and accessible names through alt.
  • AtSelect: remote search and pagination.
    • remote and remote-method(query, { signal }) for server-side search with configurable debounce (300 ms by default).
    • AbortSignal support for cancelling superseded requests.
    • on-load-more for pagination triggered by scrolling, keyboard navigation, or a page that does not fill the dropdown.
    • Loading indicators through loading and loading-text, plus on-remote-error for search failures.
    • fallback-label and cached labels for selected values whose options are not currently loaded.
    • empty and footer slots, also available outside remote mode.
    • Search queries and results remain available after a selection in remote multiple mode.
  • Added Select loading translations for all six bundled locales.
  • Added English and Chinese documentation and demos for the new components and remote Select.

Testing

  • Added Playwright browser tests covering documentation pages, component interactions, and visual regressions.
  • Added unit tests for Skeleton, Avatar, and remote Select, including request cancellation, error handling, keyboard navigation, clearing, dropdown positioning, and pagination.

Upgrading from 2.0.1

No breaking API changes or required migration steps.

The new components provide migration paths from vue-loading-skeleton and vue-avatar. Remote Select supports server-side search and pagination scenarios previously handled with vue-select. Replacing these dependencies requires changes in the consuming application.

v2.0.1

Choose a tag to compare

@vermorag vermorag released this 26 Oct 18:23
Immutable release. Only release title and notes can be modified.
eaecf18

Bug-fix release: no public API changes. Every fix ships with a regression test. Details in CHANGELOG.md.

Patches

Table

  • Sorting with pagination only sorted the current page; the whole data set is sorted and then paginated. The active sort is kept across data changes, normal restores the original order, and a column's initial sortType no longer sticks forever.
  • A data change showed page 1 while the pager still highlighted the old page; the current page is kept while it exists, otherwise page 1.
  • columns and pageSize prop changes are followed (header rebuilt, rows re-sliced); the pager uses the same page size as the body.
  • The selection column (optional) gets its own <col>, so column widths no longer shift one column to the left; resize measurement skips the selection cell.
  • Sorting a column clears the arrow of the previously sorted column.

CheckboxGroup — a v-model bound to null crashed the render; a non-array value is treated as an empty selection.

Message, Notification — closing in the same tick as opening (e.g. Message('x')() or an immediate closeAll()) left a hidden element in document.body forever.

CollapseTransition (Collapse, inline Submenu) — re-opening while still closing saved the zeroed padding/overflow as the element's own styles and restored them permanently.

Rate — with allow-half, a null v-model threw on render and on mouseleave; an integer initial value rendered half a star less.

InputNumber — readonly is honoured by the +/- buttons and ArrowUp/ArrowDown; decimal steps no longer produce float artifacts (0.14 + 0.01 → 0.15).

Slider — values were rounded to integers; fractional step/min/max now work (values snap to the min + k·step grid and stay within [min, max]).

Select — a disabled clearable select no longer shows a working clear icon; the filter input is disabled with the select; a numeric label of 0 renders as 0; keys typed into another field while the dropdown is open are no longer captured (the dropdown closes).

Menu — with router, each click navigated twice, replace was ignored and a disabled item with to still navigated; router mode without vue-router threw. The item navigates once, honouring replace/disabled. With inline-collapsed, clicking a nested submenu title no longer closes its ancestor.

Steps, Timeline, Collapse, Submenu — children re-ordered by a keyed v-for kept stale indexes; parents re-sort on update.

useChildren — children deactivated by <keep-alive> are unregistered (and re-added on activate); sort() only orders nodes sharing a root, so it is idempotent.

Progress — a status change without a percent change had no effect.

Modal, $Modal — a throwing user callback left the promise pending forever (settled first, error reported); Dialog() without options threw; an AtModal mounted already open with showInput did not focus the input; Escape closed every open modal at once — now only the topmost one (if it has close-on-press-esc="false", Escape does not reach the modal underneath).

Popover, Tooltip, Dropdown — trigger="focus" did not react to inner inputs (now focusin/focusout); a trigger prop change after mount is applied.

Pagination — current is clamped when total/pageSize shrink (emits update:current and page-change); the page inputs no longer block Tab, Delete, Home/End and Ctrl/Cmd shortcuts.

Docs — select.md: update:modelValue carries the plain value even with valueWithLabel; only on-change carries { value, label }.

Tooling — repository field in the object form; pnpm 12.15.0.

v2.0.0

Choose a tag to compare

@vermorag vermorag released this 26 Oct 17:45
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.

v1.3.14

Choose a tag to compare

@vermorag vermorag released this 03 Oct 03:55
Immutable release. Only release title and notes can be modified.
0a49667
chore: replace yarn with pnpm