Releases: Mini-Sylar/vael-ui
Release list
vael-ui@0.2.5
Patch Changes
-
#28
0f41be0Thanks @Mini-Sylar! - Fixes an externalclasspassed to a component (e.g.<Message class="my-class">) silently replacing the component's own internal styling classes instead of merging with them, undervael-ui/vapor. 36 components (Accordion, Card, Checkbox, DataTable, Tag, Toolbar, and others) now explicitly merge fallthrough attrs instead of relying on Vapor's implicit fallthrough, which doesn't reliably mergeclasson a component that already binds its own.Components whose root wraps content in
<Transition>(Dialog, Popover, Message, Tooltip, and others) are not covered by this fix — that's a separate, upstream Vue 3.6 Vapor limitation in how<Transition>itself handles fallthrough attrs, tracked separately.Also bumps the
vuedependency to3.6.0-rc.3, which fixesAnimatePresence/<Transition>deferring exit removal through a<Teleport>nested inside a component (e.g. a force-mountedDialog) — the imperativebeforeClosefallback is no longer required for that case, though it remains supported.
vael-ui@0.2.4
Patch Changes
- #26
32a8b7bThanks @Mini-Sylar! - Fixes inconsistent internal spacing in Dialog, Card, Tour, and confirmAction's popover surface, where the gap on one side of a header/body/footer-style transition was silently double-counted against the other, making the two sides unequal (e.g. Dialog's body→footer gap was exactly double its header→body gap). Also fixes Tour rendering with doubled outer padding — its own header/actions padding was stacking on top of Popover's shared body padding.
vael-ui@0.2.3
Patch Changes
-
#24
0a7d018Thanks @Mini-Sylar! - Fixesvael-ui/vaporshipping with no CSS at all — the vapor build's generator was stripping every component's CSS import under the (incorrect) assumption a consumer would already have styles loaded some other way. It now copies each component's CSS alongside its generated source and keeps the import, the same way the main build already does.packages/vapor-ui's build also moved from Vite library mode totsdown, matching the main package's build exactly, so vapor gets the same real per-component CSS code-splitting — importing a single component only downloads that component's CSS, whether viavael-ui/vaporor thevaporexport condition added in 0.2.1.
vael-ui@0.2.2
Patch Changes
-
c33d874Thanks @Mini-Sylar! - Fixes a build failure (CIRCULAR_REEXPORT,MISSING_EXPORT) invael-ui/vaporfor any consumer using thevaporexport condition added in 0.2.1 — several composable/utility re-exports were pure passthroughs that resolved back to themselves oncevael-ui's root pointed at the same file. They now import from their real source files directly instead of through the package specifier.Also fixes
confirmAction, which was excluded from the Vapor build in 0.2.1 (it rendered the real VDOMButtoncomponent internally) — it now composes real Vapor-compiled components, so it's available fromvael-ui/vaporlike every other composable.
vael-ui@0.2.1
Patch Changes
- #21
a78a3a9Thanks @Mini-Sylar! -vael-ui/vapornow also re-exports composables and utilities, not just components. This also enables avaporexport condition on the package root — set it in your bundler andtsconfig.jsonto usevael-uieverywhere with no/vaporsubpath needed. See the Auto Import guide for setup; see the 0.2.0 release notes for the original Vapor/resolver docs.
vael-ui@0.2.0
Minor Changes
-
#17
35d6fe3Thanks @Mini-Sylar! - Per-component CSS code-splitting, six new components (includingTour), large-data support forDataTable, avael-ui/resolverfor auto-importing components plus avael-ui/nuxtmodule, container-scoped overlays, real link rows forMenuList/Menu, and broader generics across the item-based components.Per-component CSS code-splitting
Every component now ships and imports its own CSS file instead of one bundled
style.css.- Importing a component only pulls in the styles it actually uses — bundlers that tree-shake unused component imports drop their CSS along with them.
import 'vael-ui/style.css'still works unchanged (now resolving to a multi-entry build's combined output), for anyone who wants everything loaded up front or is on a pre-0.2.0 workflow. No import changes required either way.- Shared design tokens live in their own
components/shared/tokens.css, pulled in once regardless of which components you use.
New components
ScrollArea— custom scrollbar styling and edge fade over real native scrolling (orientation: 'vertical' | 'horizontal' | 'both')AvatarGroup— overlapping avatar stack with a "+N" overflow indicator and optional hover-liftBreadcrumb/BreadcrumbItem/BreadcrumbSeparator— data-drivenitems, or compose the parts yourself. Each item'sas/attrsrenders it as a plain link, aRouterLink, or anything else your router providesStepper— linear or free-jump numbered step flow, horizontal or verticalCommandPalette— ⌘K-style fuzzy-filtered command list, built onDialogTour+useTour()— step-by-step spotlight walkthrough with grouped steps, a headless composable for a fully custom UI, and the samecontainer-scoping and animation-agnostic contract as the rest of the overlay components
DataTable: built for large dataServer-driven sort/pagination, virtualization, and infinite-scroll wiring — designed to compose with
useInfiniteQuery-style patterns rather than replicate them.manualSort—datais already sorted server-side;DataTablestops sorting it locally and just reflectsv-model:sort, so a header click tells you what to refetch instead of re-sorting what you gave it.lazy+total—datais already just the current page;DataTablestops slicing it locally and usestotal(the real across-all-pages count) for#footer/pagination math.virtualize— windows rendering to only the visible rows + overscan, for tables with tens of thousands of rows. Row height is measured per-row by default (rows can wrap, or vary understackedBreakpoint), not assumed uniform.reach-end/reach-startevents fire as the virtualized window nears either edge — wire them straight touseInfiniteQuery'sfetchNextPage/fetchPreviousPage.v-model:sort— sort state ({ field, dir }) is now a real two-way binding instead of purely internal.scrollHeighttables now split the header into its own non-scrolling row above a separately scrollable body, so the browser's scrollbar starts at the body instead of overlapping the header.selectionMode="row"now shows a pointer cursor on every row, matching the click-to-select affordance.
vael-ui/resolver: auto-import componentsA resolver for
unplugin-vue-components— register it once and every vael-ui component becomes usable in a template with no manual import at all:// vite.config.ts import Components from "unplugin-vue-components/vite"; import { VaelUiResolver } from "vael-ui/resolver"; export default { plugins: [Components({ resolvers: [VaelUiResolver()] })], };
Pass
{ variant: 'vapor' }to resolve fromvael-ui/vaporinstead of the default VDOM build. No CSS side-effect wiring needed — every component already imports its own CSS internally, so resolving the component pulls its styles in for free. Zero dependency onunplugin-vue-componentsitself; the resolver is a plain, hand-typed function that structurally matches its contract.vael-ui/nuxt: a Nuxt moduleSame idea as the resolver, for Nuxt apps — register the module once and every component is usable with no manual import, using Nuxt's own built-in component registration instead of
unplugin-vue-components:// nuxt.config.ts export default defineNuxtConfig({ modules: ["vael-ui/nuxt"], });
exclude: ['Button']skips specific component names, e.g. to register your own<Button>under that tag instead. VDOM only, novariantoption — Vue 3.6 supports Vapor SSR hydration, but the stable Nuxt release has no Vapor configuration yet (it's landing behind specific upstream PRs). Verified against a real Nuxt app: SSR markup, client hydration, and CSS all confirmed working in bothnuxt devand a productionnuxt build.Container-scoped overlays
Dialog,Drawer,CommandPalette,Popover, andTourall gained acontainerprop that scopes the overlay to one element instead of the whole viewport — the scrim only dims that element, the panel teleports there instead ofbody, and scroll-lock/inert apply only inside it, leaving the rest of the page interactive. Useful for embedding a live overlay demo (a dashboard preview, a docs example) without it taking over the whole screen.BottomSheetdoesn't supportcontaineryet — its drag mechanics still assume the full viewport.New composables back this:
useScrollLock— ref-counted, per-element locks so nested overlays compose correctlyuseInert— scopes inertness to a container instead of the whole documentuseLayerStackadditions — scope Escape-key/layer ownership to an element
Original contained/scoped
Dialogimplementation from @arkida39 (#16), extended here toDrawer,CommandPalette,Popover, andTour.MenuList/Menurows can now be real linksA row's
as/attrs(default'button', so nothing existing changes) renders it as<a>orRouterLinkinstead — native cmd/ctrl/middle-click and "open in new tab" work, which a<button>-only row never could. A row with nesteditems(a submenu trigger) always stays a button.Broader generics
SelectButton,SpeedDial,Tour(anduseTour),Tree,TreeSelect, andCascadeSelectjoinSelect,Combobox,DataTable,Menu,MenuList,CommandPalette,Breadcrumb, andStepperin being generic over their item type (T extends XItem = XItem) — extend an item with your own fields and get them back fully typed through slots and events instead of casting.Deeply nested items (a
Treenode'schildren, aMenurow's nesteditems) stay base-typed — same documented limitation as before.Fixes
- Page-wide scroll locks now consistently target
document.body(Tourwas still lockingdocumentElementdirectly) BottomSheetcontent is scrollable at any drag/snap position instead of only once mostly open, and a nested sheet's parent now un-recedes in sync with the child's own close animation instead of waiting for it to fully finishDialog'steleportTonow correctly wins overcontainerwhen both are setv-scroll-maskacceptsorientation: 'x' | 'y' | 'both'(previously vertical-only, so binding it on a horizontally-scrolling row was a silent no-op), and its edge fade is more visibleMessage's dismiss button hit target is larger
vael-ui@0.1.6
Patch Changes
-
6f27012Thanks @Mini-Sylar! - Breaking: replaceconfirmDialog()anduseConfirmAction()(added in the previous release) with a singleconfirmAction(). The old pair required either hand-rolling your own overlay wiring (useConfirmAction) or being locked into a centeredDialog(confirmDialog);confirmAction()picks its presentation with a discriminated union onsurface,'dialog'(default, centered) or'popover'(anchored to atriggerEl, required in that branch). Both branches pass every other prop straight through to the underlyingDialog/Popover(position,size,side,align,closeOnOutside,ui, etc.), so per-call customization (a taller dialog, a wider popover) needs no new API surface.onConfirmis awaited before closing: the confirm button stays in its loading state until it settles, closing only on success; a rejection leaves the surface open and firesonErrorinstead of closing out from under a failed action.useConfirmActionandconfirmDialogare removed with no compatibility shim, since the API was flagged unstable in the release that introduced it.Add
usePopoverService(openPopover,usePopoverRef,usePopoverQueue) andPopoverHost, the anchored-surface counterpart to the existinguseDialogService/DialogHost.openPopover(Component, options)mounts any component inside aPopoveranchored tooptions.triggerEl, returning{ result, close, panelEl }the same shapeopenDialogreturns —resultsettles with whatever the opened component'susePopoverRef().close(result)passes.confirmAction({ surface: 'popover' })is built on this primitive; reach foropenPopoverdirectly for anything beyond a plain confirm (a custom form in a popover, for example). Requires mounting<PopoverHost/>once at the app root, alongside<DialogHost/>.Fix confirm-flow popovers being permanently stuck invisible (
visibility: hidden, positioning never computed). The shareduseFloatingPositioncomposable only recomputes on a false-to-true transition of itsactiveflag, not on an initial truthy value; an imperatively-opened popover'sopenstate startstruebefore the surface even mounts, so the transition never happened and positioning silently never ran.
vael-ui@0.1.5
Patch Changes
-
6e9f93bThanks @Mini-Sylar! - AddconfirmDialog()anduseConfirmAction()for building async-aware confirm flows (delete confirmations, destructive-action gates) without a dedicatedAlertDialogcomponent.useConfirmAction()is presentation-agnostic — bind itsopenref to any overlay's ownv-model:open(Popover,Dialog, or a fully custom surface), anchored however that overlay already supports (Popover's existing#triggerslot ortriggerElprop, unchanged).confirmDialog()is a thin convenience wrapper over the existingopenDialog()service for the common "title + description + Cancel/Confirm" shape, still accepting a custombody/footercomponent for full control. Both share the same core behavior:confirm(action)keeps the surface open andpendingtrue untilactionsettles, closing only on success — a rejected action clearspending, setserror, and leaves the surface open instead of closing out from under a failed action.Fix
Dock's pointer-proximity magnification visibly juddering in Safari. The live per-itemtransformwas written everypointermoveframe while a CSStransitionwas still active on that property, so Safari was continuously retargeting an in-flight transition — Chromium mostly masked it, Safari didn't. Replaced with a smallrequestAnimationFramespring loop (exponential decay toward each item's target scale/offset) that owns the live tracking entirely; the CSS transition now only ever governs the discrete press-shrink feedback.Fix
Accordion'smotionCss={false}being unable to close.useCollapse's settle logic was forcing the resting style to{}(visually open) whenever motion was disabled, regardless of the target open/closed state — so disabling the built-in transition also silently disabled closing.motionCss={false}now still snaps instantly to the correct open/closed resting style, just without the animated transition.Fix
Calendar's month-change slide briefly bleeding into the weekday header row — the leaving month's grid wasposition: absoluteagainst the wrong containing block (the whole calendar body, which the weekday row also shares), landing it on top of the header text for one frame instead of at the grid's own top edge.Fix
SelectButton's sliding indicator popping in instantly with no transition on the very first selection (starting from nothing selected). The indicator's first-measurement guard was only tracking whether the component had ever measured at all, not whether it had ever shown a real selection — so the first real pick was mistaken for the initial-mount case and had its transition suppressed.Fix
OtpInput's blinking caret drawing through an already-typed digit instead of only appearing in the next empty cell, and fix a one-frame focus flash on the wrong cell when clicking back into a completed code — the browser's own default caret placement (based on the invisible input's unstyled text metrics) was landing and painting before the click handler's correction ran; both are now resolved before any paint by handling pointerdown withpreventDefault()instead of click.Fix
Toolbar's vertical orientation not being vertically centered when only one of its three internal slot groups (start/center/end) had content — the two empty groups were still full flex participants contributing gap spacing. Toolbar now only renders a slot group when it actually has content.Fix
Toastalignment (action button text centering, close-icon sizing) andRadio's icon being misaligned with its label text.Fix
BottomSheet's swipe-to-dismiss being inconsistent on mobile — dragging down past the lowest snap point wasn't always registering as a dismiss gesture.Fix
Badge's count text rendering visibly offset from center.
vael-ui@0.1.4
Patch Changes
2871350Thanks @Mini-Sylar! - FixCombobox,Select,TreeSelect, andDatePickersilently dropping a plainclass/stylepassed by a consumer. Each setsinheritAttrs: falsebut never forwarded those attrs onto its own visible trigger element (only onto the teleported dropdown panel, where one existed), so<Combobox class="my-class">(and the same on the other three) never reached the rendered DOM — any consumer relying on ordinary class-based styling (width, layout,display: nonein a media query, etc.) had no effect. Audited every other component usinginheritAttrs: false; the remaining ones (Popover, Tooltip, Menu, Dialog, Drawer, BottomSheet, ContextMenu) take a consumer-provided trigger via slot and have no component-owned trigger element, so they were unaffected by design, not by accident.
vael-ui@0.1.3
Patch Changes
d752420Thanks @Mini-Sylar! - FixField's context (disabled,required,invalid, labelforwiring, focus/filled tracking) not reaching wrapped controls under Vapor.fieldKeywas defined as a freshSymbol()insideField.vueitself, so the Vapor build's copy of that file created a second, different Symbol instance than the oneuseFieldControl(shared, not duplicated) always injected with — the two never matched, so every control wrapped in<Field>silently ignored the wrapper's state under Vapor.fieldKeynow lives in its own module that the Vapor build correctly imports instead of redefining.