Журнал изменений
3.0.0
Мажорные изменения
- 8adf390
ButtonandIconButtonno longer default totype="button". Like a native<button>, they submit the surrounding form unlesstype="button"is set, and withasChildthey no longer passtypeto the child element. Internal buttons ofNumberField,PasswordField,Pagination,Calendar, date fields and the dialog and drawer close buttons keeptype="button" - 1af9fda
Calendar, the pickers and the date fields work in any calendar systemNew package
@vega-ui/i18nwith no dependencies and no knowledge of the components; every function that needs a calendar takes it as the first argument:- the
CalendarSystemadapter interface, theGregorianCalendarclass (extendable withsuper, methods bound to the instance) and its shared instancegregorianCalendar;createCalendarSystem(identifier), any other calendar built intoIntl(Persian, Hebrew, Japanese, Buddhist, Islamic, Chinese…) with no dependencies: months numbered from the start of the year (13 in a Hebrew leap year),Intlera names, a year that ends with an era keeps only its own months, a year past the end of an era is clamped to its last year, an unknown era throws aRangeError; custom calendars plug in through the interface - calendar-aware helpers over
YYYY-MM-DDstrings:addCalendarMonths,addCalendarYears,getCalendarMonthStart/End,getCalendarYearStart/End,getCalendarMonthsDistance,getCalendarYearsDistance,getCalendarMonthsOfYear,getSameDayInCalendarMonth,getSameMonthInCalendarYear,isSameCalendarMonth, and the calendar-neutralDAYS_IN_WEEK,addISODays,getISOWeekday,isoDateToUTC,utcToISODate,padDatePart; like<input type="date">they cover the years 0001–9999 and throw aRangeErroroutside them - locale helpers:
getDefaultLocale(), the runtime localeIntluses by default, andgetFirstDayOfWeek,getWeekDayNames,getDateFormat,getDateSeparator, moved from@vega-ui/utils: they take the locales argument ofIntland default to the runtime locale instead ofen-US;getDateFormat/getDateSeparatortake the calendar system first, describe the numeric fields, leave out eras and bidi marks (ar-SAgives/, not\u200F/), and use the Gregorian order of the locale for calendars that name their months (Hebrew, Chinese); newtoLatinDigits Intlformatting:formatCalendarDate,formatCalendarDay(bare day numbers,15rather than15日),createCalendarDateFormatter/createCalendarDayFormatter(oneIntl.DateTimeFormatreused for many days; the day, month and year grids create one per layout instead of one per cell)
@vega-ui/utils(now depends on@vega-ui/i18n):- typed entry of the date fields over a calendar system,
formatTemplateDate,parseTemplateDate,parseTemplateRange,normalizeTemplateDate,stepTimeSegment(time only, no calendar) andgetDateTemplate(the field template of a date format:dd.MM.yyyy→dd.mm.yyyy),getTimeTemplate(HH:mm→HH:MM) andgetDateTimeTemplate(the template ofDateTimeField:dd.mm.yyyy, HH:MM); newfindISODateInRange(dates, start, end), the firstYYYY-MM-DDdate within a range, andgetISODatePart/getISOTimePart, the date and time parts of an ISO date time;snapToStep(value, { min, max, step }), the step grid of<input type="range">
Calendar,DateField,DateTimeField,DateRangeField,DayPicker,MonthPicker,YearPicker:- new
calendarandlocaleprops on the root, applied to every part (labels, weekday names, week start, day, month and year grids); defaults are the Gregorian calendar and the runtime locale, likeIntl. There is no global provider: for app-wide settings, wrap the component (<Calendar locale={appLocale} {...props} />). Values stay ISO strings in every calendar Calendarsetslangon its root whenlocaleis given- PageUp / PageDown move focus to the same day of the previous / next month, Shift+PageUp / Shift+PageDown to the same day of the previous / next year (WAI-ARIA date picker pattern)
Calendarcomposition (breaking), one part per view instead of four nesting levels:- removed
CalendarDayPickerand itsItem/Row/RowGroup/Scroller/ScrollerContent/ScrollerLayout,CalendarMonthPickerand itsItem/Row/RowGroup/Layout,CalendarYearPickerand itsItem/Row/RowGroup/Scroller/ScrollerContent/ScrollerLayout,CalendarMonthPickerButton,CalendarYearPickerButton,CalendarPickerButtonGroup,CalendarPrevYearGroupButton,CalendarNextYearGroupButton,CalendarWeekLabel,CalendarWeekLabels - new
CalendarDays(the day view, holding the newCalendarWeekdays, weekday names in the calendar's locale withformat, andCalendarWeeks, the swipeable day grid withformatandincludeOverflowDays),CalendarMonths(cols,format),CalendarYears(format) - weekdays and cells are customized with template children, no render functions: the children of
CalendarWeekdays/CalendarWeeks/CalendarMonths/CalendarYearsrender once per weekday or cell, read it withuseCalendarWeekdayContext()(column,weekdayas inDate#getDay(), name) /useCalendarDayContext()/useCalendarMonthContext()/useCalendarYearContext()(ISO date, fields in the calendar system, formatted label) and renderCalendarWeekday/CalendarDay/CalendarMonth/CalendarYear; the template is required, there is no implicit default cell CalendarViewButton view='month' | 'year'andCalendarViewButtonGroupreplace the month and year picker buttonsCalendarPrevButton/CalendarNextButtonfollow the view: months in the days, pages of years in the years; they show a chevron unlesschildrenare given- the views (
CalendarDays,CalendarMonths,CalendarYears) take only HTML attributes and display options; the month, selection, disabled dates, locale and calendar come from theCalendarroot CalendarMonthLabel/CalendarYearLabeldroplocale: every part uses the locale of theCalendarpicker/defaultPicker/onChangePicker→view/defaultView/onChangeView; typeCalendarPicker→CalendarView;useCalendarContextexposesview,toggleView,closeView,prev,next,locale
Date fields:
- digits of any numbering system are accepted while typing (
٠٥.٠١.٢٠٢٦,۱۴۰۵/۰۱/۰۱) and written as Latin digits - typing is validated in the calendar system: the day is clamped to the length of the month (
31.02.2026→28.02.2026), a digit that cannot start a segment is zero-padded (4→04), a complete value is clamped tomin/max DateTimeField(breaking):timeFormatuses the notation ofdateFormat(Unicode date patterns,mm= minutes):'HH:mm' | 'HH:mm:ss'instead of'HH:MM' | 'HH:MM:SS'DateRangeFieldswaps a range typed in reverse;DateTimeFieldsteps the time segment under the caret with ArrowUp / ArrowDown: hours by 1, minutes and seconds bytimeStep(likedatetime-local), sotimeStep={15}no longer adds 15 hours- clearing the text or leaving it incomplete clears the calendar selection, and
form.reset()re-syncs the calendar - when
min/maxchange, already typed text is clamped again (firinginput) DateRangeField's defaultrangeSeparator(an en dash between non-breaking spaces) is documented accurately
DayPicker,MonthPicker,YearPicker(breaking):- cells are keyed by ISO strings (
YYYY-MM-DD, the first day of the month / year for the month and year pickers) instead of timestamps and numbers DayPicker:year/monthnumbers →month(any day of the month asYYYY-MM-DD) andcalendar;DayPickerScrollertakesdefaultMonthand reportsonChangePeriod(month);DayPickerLayout/createDayPickerGridoffsetis only the page index that keeps row indexes unique (the month comes frommonth, no longer shifted byoffset);DayPickerLayout/createDayPickerGriddropcols(the week has seven days in every calendar; other values broke the grid);createDayPickerGrid({ month, calendar, offset, … })returns{ col, date, day, inCurrentMonth };getIndexByDate/getDateByIndexremovedMonthPicker:yearis aYYYY-MM-DDstring,calendaradded;createMonthPickerGrid({ year, calendar, cols })derives the rows, so years with 13 months fit;MonthPickerLayoutdropsrows/start; newuseMonthPickerContextYearPicker:yearis aYYYY-MM-DDstring,calendaradded;createYearPickerGridandYearPickerLayouttakestartasYYYY-MM-DD;YearPickerScrollertakesdefaultYearandperiodinstead ofgetIndexByYear;getIndexByYear/getYearByIndexremovedDayPickerLayout,MonthPickerLayout,YearPickerLayout(and the scroller layouts) require the same template children (<DayPickerCell />, …); newDayPickerCell,MonthPickerCell,YearPickerCellanduseDayPickerCellContext,useMonthPickerCellContext,useYearPickerCellContextDataGridignores key presses whose default was already prevented- in range mode the bounds are always reported in order (
[start, end],startnot afterend), also when the range is picked backwards (@vega-ui/hooksuseSelectionorders them); the same holds forCalendar'sonChangeValue - without
defaultActivethe tab stop is always a cell in view: today when it is in the visible month / year, otherwise the first selected cell there, otherwise the first cell (YearPicker: the visibleyear); before, Tab skipped the grid when today was not shown YearPickerScrollerreports the page in view withonChangePeriod(year), likeDayPickerScroller
Right-to-left:
- the calendars and pickers follow the inherited text direction (
diron the page, an ancestor or the component), like native elements: the grids run right to left, ArrowLeft / ArrowRight are mirrored, the default Prev / Next chevrons point the right way, range ends are rounded on the correct side, and swiping and the scrollers page in the right direction (@vega-ui/hooksuseScrollSnapaligns snap points in RTL)
Fixes:
Calendarwithoutselectionis typed as single selection, soonChangeValue={setState}withuseState<string>type-checksgetCalendarMonthsOfYear(@vega-ui/i18n) returns only the months of each era in a year where a Japanese era changes (no duplicated months inMonthPicker)getFirstDayOfWeek(now in@vega-ui/i18n) readsIntl.Localeweek info correctly (getWeekInfo()orweekInfo, Sunday = 7) and falls back to the region of the locale (fa-IR→ Saturday,pt-BR→ Sunday) when the runtime has no week infoNumberField,PhoneField,PinField: afterform.reset()the − / + buttons, the detected country and the PIN slots match the restored value.PhoneFieldwrites the calling code of a picked country only when a controlled parent accepts it. Breaking for custom parts:useNumberFieldContextandusePhoneFieldContextno longer exposeonInputIndexedSnapScroller(and every calendar scroller built on it) no longer moves pages under an ongoing scroll: it appends pages while a scroll reaches the end and re-centers the window once the scroll settles, so swiping to the edge in WebKit and Firefox no longer jumps two pages further (e.g. December → February) and fast swipes keep going;onOffset(-1)now fires when the scroll settles on the first pageIndexedSnapScrollerkeeps a scroll made right after a snap settles instead of jumping back a page (seen with fast swipes on a busy page)IndexedSnapScrollerre-syncs to a controlledindexonly when that prop changes, so the year picker no longer jumps back to the visible year after scrollingCalendarmonth and year arrows no longer stop working after a few clicks: each click moves one page from the page the scroll is already heading to (clicks during a smooth scroll were lost in Firefox), the window grows when the target is outside it, and focus keeps the same day across quick month changes@vega-ui/hooks(breaking):useIndexesreplacespush()/shift()withextend(dir)(grow the window at an edge without moving existing pages) andcenter(index)(re-center the window on a page);useScrollSnap'sscrollToElementByKeyreturns whether the item exists@vega-ui/hooksuseSelectionmatchesdisabledkeys withequals, like selection: object keys with a customequals({ row, col }) are blocked, not only the same referenceSliderbehaves like<input type="range">: handlers passed to the root (onKeyDown,onPointerDown, …) run after the built-in ones instead of replacing them, steps count frommin(min={1} step={2}gives 1, 3, 5…), the arrow keys stop atmin/maxwhen a step overshoots them, End goes to the last step that fits inmax, fractional steps keep their precision (0.3, not0.30000000000000004), and a cancelled pointer (pointercancel) ends the dragRangeSliderfollows the same rules: user handlers no longer replace the built-in ones, steps count frommin, fractional steps keep their precision, End stops at the last step that fits inmax,pointercancelends the drag; the right thumb no longer goes pastmaxwith ArrowRight, the left thumb reachesminwhen a step overshoots it, and a step that would pass the other thumb stops at it instead of being ignored
Removed unused APIs (breaking):
@vega-ui/react:useMonthPickerScrollerContext(an alias ofuseIndexedSnapScrollerContext;MonthPickerhas no scroller)@vega-ui/utils:formatDay,formatMonth,formatYear(Gregorian-only; useformatCalendarDate/formatCalendarDayfrom@vega-ui/i18n),isEqualDates,getClampedDate,capitalize,uncapitalize;getFirstDayOfWeek,getWeekDayNames,getDateFormat,getDateSeparatormoved to@vega-ui/i18n
- the
- af37ac1
BREAKING: the
useCheckboxCardContextfieldonChangedCheckedis renamed toonChangeChecked, matching theCheckboxCardprop and the rest of the library. ReadonChangeCheckedfrom the context instead. - c71df25
BREAKING: checkbox-like inputs follow the native element.
CheckboxHiddenInput,SwitchHiddenInput,CheckboxCardControlHiddenInputandSegmentedControlItemHiddenInputare renamed toCheckboxInput,SwitchInput,CheckboxCardControlInputandSegmentedControlItemInput, together with their prop types. They are the actual interactive inputs, not hidden mirrors.CheckboxandCheckboxCardno longer acceptchecked,defaultChecked,onChangeChecked,indeterminateanddisabledon the root. Set them onCheckboxInput/CheckboxCardControlInputlike on a native checkbox, usingonChangeinstead ofonChangeChecked.indeterminateis a prop of the input.useCheckboxContextanduseCheckboxCardContextexpose onlysizeandvariant.
- 6f10f80
The value of the masked fields moves to the root, like
Slider: the input part only shows it, so a controlled field keeps every keystroke and follows a value changed outside.- Breaking:
NumberFieldtakesvalue,defaultValueandonChangeValueas a number,NaNfor an empty field;NumberFieldInputno longer takesvalueanddefaultValue - Breaking:
PhoneFieldtakesvalue,defaultValueandonChangeValueas the text of the number;PhoneFieldInputno longer takesvalueanddefaultValue. The country ofdefaultValueis selected unlesscodeis set - Breaking:
DateFieldtakesvalue,defaultValueandonChangeValueas aYYYY-MM-DDday,DateTimeFieldas aYYYY-MM-DDTHH:mm[:ss]timestamp,DateRangeFieldas a[start, end]tuple of days;''while the text is empty or incomplete. Their input parts no longer takevalueanddefaultValue - the input parts still fire their own
onChangeandonInputon every edit of the text, andnamestill submits the text - a form reset restores
defaultValueunless the field is controlled - the increment and decrement buttons of
NumberFieldfollow changes ofminandmax - Breaking for custom parts: the contexts of these fields expose the shown
textandchangeTextinstead ofsetText,detectCodeandchangeDate/changeTime
@vega-ui/utils: newformatTemplateRange(calendar, [start, end], template, separator), the counterpart ofparseTemplateRange. - Breaking:
- 39c05d0
BREAKING: new
Listbox, andSelectis built on it instead of the floating-ui interaction hooks. Positioning stays on floating-ui.- New
Listbox,ListboxOption, andListboxGroup: an always visible list like a nativeselectwithsize. Name it witharia-labelledbyoraria-label.labelon an option sets its text for typeahead and does not change whatSelectValueshows. Withmultiple,value,defaultValue, andonChangeValueuse arrays,SpaceandEntertoggle the active option, and adjacent selected options merge into one shape. Optionis adivinstead of abutton: itsrefpoints to anHTMLDivElement, it no longer takesvalueand is not generic,focusableis replaced byactive, anddisabledsetsaria-disabledand uses the--disable-label-text-colorand--disable-background-colortokens likeDataGridPickeritems.SelectListboxhas nodata-status, style it with:popover-open, anduseSelectContextno longer returnsstatus.SelectHiddenSelectrenders only the selectedoption: it submits the value and no longer lists all options.SelectListboxis hidden withvisibilityinstead of theinertandhiddenattributes, and its options no longer shrink to fitmax-height, so a long list scrolls at the full option height.value={null}clears a controlledSelector singleListbox,undefinedstill makes it uncontrolled.Selectstays closed whiledisabledorreadOnly, even withopenordefaultOpen, ignores arrows withMetaorCtrl, and typing that matches nothing no longer opens it. A disabledOptiondoes not callonClick.SelectListboxis a nativepopover="auto"element: the browser closes it onEscapeand an outside click. In aDialog,Escapecloses only the list.- The focus stays on the
SelectCombobox, which points to the active option witharia-activedescendantand setsaria-haspopup,aria-expanded, andaria-controls. A form field insideSelectListbox, such as a search input, can take the focus, and the list closes when the focus leaves it. Selectkeyboard follows the WAI-ARIA select-only combobox: arrows stop at the ends of the list, typing while closed opens the list and moves to the match instead of selecting it, typeahead matches from the start of the label instead of anywhere in it,typeMatchEnabledis renamed totypeahead,Tabselects the option moved to with the keyboard and moves on, and without such a move keeps the value,Alt+ArrowUpcloses the list, andPageUpandPageDownjump by ten options.useSelectContextno longer returns the floating-uicontext,itemProps,listboxProps,elementsRef,labelsRef,activeIndex,selectedIndex,selectRef,update, andonSelect, andvalueRefis replaced byvalueElementandsetValueElement.SelectComboboxPropsno longer hasreadOnlyandvariant, set them onSelect.SelectValuePropsextends the attributes of aspaninstead ofTextProps.SelectListboxignoresid, andListboxOptionandSelectOptiondo not takeid,selected, oractive.
@vega-ui/hooksaddsuseTypeahead.@vega-ui/utilsaddsfindEnabledIndex,isActivationKey,matchTypeahead,resolveListNavigation, andscrollIntoContainer. - New
- 1990f69
Rename
getCommitedtogetCommittedin theuseScrollSnapresult and theSnapScrollerapi ref - ce0b569
BREAKING:
IconSizeno longer includesnull. Omitsizeor passundefinedinstead ofsize={null}. - 399fd0d
BREAKING:
Dialog,Drawer, andSheetare built on the native<dialog>element opened withshowModal(), and the overlays follow native behavior and iOS-like motion.DialogPortal,DialogBackdrop,DrawerPortal,DrawerBackdrop,SheetPortal, andSheetBackdropare removed.DialogContent,DrawerContent, andSheetContentrender the<dialog>intodocument.body, and the backdrop is its::backdrop. Style it with.your-class::backdrop.DialogContent,DrawerContent, andSheetContenttake<dialog>attributes, and theirrefpoints to theHTMLDialogElement.onCancelandonCloserun after the internal handlers.blurred(defaulttrue) blurs the page behind, andoverlay(defaulttrue) dims it; withoverlay={false}the panel stays modal over a transparent backdrop.closedByonDialogContent,DrawerContent, andSheetContentsets which user actions close the panel, like the nativeclosedbyattribute:any(a backdrop click, a swipe, orEscape),closerequest(Escapeonly), ornone. It replacesdismissibleonDrawerandSheetandclosableandclickEnabledonSheet. It defaults tocloserequestonDialogContent, so a backdrop click no longer closes a dialog, and toanyonDrawerContentandSheetContent.useDialogContext,useDrawerContext, anduseSheetContextno longer expose the floating-ui context and props. The unusedrefprop is removed fromDrawerPropsandSheetProps.- The browser makes the page inert, handles focus, and restores it on close, and the page does not scroll behind the panel. On open the panel itself takes focus instead of its first control, and
autoFocuson a child focuses that child.DialogTrigger,DrawerTrigger, andSheetTriggersetaria-haspopupandaria-expanded. DialogTitle,DialogHeader,DialogCloseButton,DrawerTitle,DrawerHeader,DrawerCloseButton,SheetHeader, andSheetMainare removed: compose the panel from your own markup. Name it witharia-labelledbypointing to your heading, or witharia-label; a panel without a name is not accessible. NewDialogClose,DrawerClose, andSheetCloseturn your own button into a close button (asChild) with no styles of its own: they replaceDialogCloseButtonandDrawerCloseButton. Buttons in a<form method="dialog">close the panel too.useDialogContextanduseDrawerContextno longer returncontentIdandtitleId, anduseSheetContextno longer returnscontentId.- Submitting a
<form method="dialog">inside the panel closes it throughonChangeOpen(false), so the close transition plays and a controlled parent can keep it open; the submit button'svaluebecomes the dialog'sreturnValue, as natively. It closes the panel also whenclosedByisnone. BackdropandPopoverBackdropare removed. UseDialogorSheetfor a popover that dims the page.- Panels open with a spring and close faster with an ease-out; with reduced motion they only fade.
Drawer:positionuses logical sides that follow the writing direction:leftandrightare nowstartandend(left-startisstart-start,right-endisend-end, and so on), and the default isend. In right-to-left textendis the left side.- A touch swipe toward its edge drags the drawer and closes it past half its size or on a flick, when
closedByisany. Mouse drags are left for text selection.
Sheet:- Snap points act like native sheet detents. A drag follows the finger, resists past the top and bottom with rubber banding, and settles at the snap point where its momentum would carry it, so a flick can skip a snap point;
steppedSnapPointsmoves one snap point at most. A drag down past the lowest snap point closes the sheet whenclosedByisany. edgeThreshold,siblingThreshold, andswipeTimestampare removed.- The sheet fits its content unless
SheetContenthas a CSS height, and is never taller than the viewport. A number snap point is a fraction of the viewport height instead of the sheet height, and a snap point above the sheet's height rests at its top. - The sheet opens at the lowest snap point unless
defaultSnapPointsays otherwise, and an uncontrolled sheet reopens there.onChangeActiveSnapPointonly fires when the user moves the sheet to another snap point. - On touch devices, dragging by scrollable content moves the sheet below its top snap point; at the top it scrolls the content, and pulls the sheet down once the content is scrolled to the top.
- The backdrop fades as the sheet is dragged down, the sheet rises above the on-screen keyboard, and its padding respects the bottom safe area.
SheetHandleis a button that moves the sheet to the next snap point, and back to the lowest from the top, when the sheet has several snap points; otherwise it is disabled and hidden from assistive technology, and it is always a<button>. It has no built-in name: passaria-label, for exampleResize sheet. Like the iOS grabber, it is a 36×5px bar at the top of the sheet that takes no room, and the sheet keeps its content closer to the top.- Like an iOS sheet, the sheet floats as a card with rounded corners,
--sheet-inset(defaultvar(--spacing-8)) clear of the sides and the bottom, while it rests below the top of the viewport, also at a lower snap point, and widens to the edges as it rises to the top;--sheet-inset: 0keeps it full width.SheetContentexposes--sheet-expansion, from0at its lowest position to1when it reaches the top of the viewport, for styles that change as the sheet rises. SheetContenthas the side and bottom padding thatSheetHeaderandSheetMainhad. A scrollable region inside it is any element withoverflow: auto.react-remove-scrollis no longer a dependency.
Popover:PopoverContentis a nativepopover="auto"element that is always rendered, hidden while closed; its children render only while it is open. The browser opens it fromPopoverTriggerthroughpopovertarget, closes it on an outside click orEscape, stacks nested popovers, and returns focus to the trigger. The trigger must be a button.- Opening no longer moves focus into the content;
Tabfrom the trigger enters it.usePopoverContextno longer exposes the floating-ui context and props. - The content grows out of the side facing its trigger.
PopoverTriggerno longer setsaria-expandedandaria-controls: the browser exposes the expanded state frompopovertarget.
Tooltip:- It shows on hover with a mouse or pen and on keyboard focus, never on a tap, and hides when the trigger is pressed. Right after one tooltip closes, the next shows without a delay.
- It describes its trigger through
aria-describedby, grows out of its arrow, and lets the pointer through to the page.useTooltipContextno longer exposes the floating-ui props.
SelectandTooltiprender their floating content in the top layer withpopover="manual"when the browser supports it, so a modal dialog or anoverflowcontainer no longer clips or covers them.SelectPortalandPhoneFieldSelectPortalare removed: renderSelectListboxdirectly insideSelect.SelectListboxstays at least as wide as the combobox, also when the combobox resizes while the list is open, and only fades with reduced motion.IconButtonno longer keeps the browser's default button padding, so an icon in a small button, such as a 24px close button, is no longer squeezed. - d0069e2
Slideris rebuilt on native<input type="range">and takes one or several thumbs:<Slider value={price} onChangeValue={setPrice} name="price"> <SliderTrack> <SliderRange /> </SliderTrack> <SliderThumb index={0}> <SliderThumbInput aria-label="Minimum price" /> <SliderThumbIndicator /> </SliderThumb> <SliderThumb index={1}> <SliderThumbInput aria-label="Maximum price" /> <SliderThumbIndicator /> </SliderThumb> </Slider>Breaking:
RangeSliderandSliderBasewith all their parts are removed; aSliderwith twoSliderThumbs replacesRangeSlidervalue,defaultValueandonChangeValuetake a number for one thumb or an array with one entry per thumb by itsindex;onChangeValuegets the same shapeSliderProgressandSliderHiddenInputare removed; useSliderTrackwithSliderRangeinside, andnameonSliderorSliderThumbInputuseSliderContextgivesvalues, an array for every thumb, instead ofvalue, and addsgap,nameandchangeThumb(index, value);useRangeSliderContextanduseRangeSliderThumbContextare removed, useuseSliderContextand the newuseSliderThumbContextwithindex,lowandhighSliderThumbholds two parts:SliderThumbInput, the native range input that takes the input props andref, andSliderThumbIndicator, the visual handle with any content
New:
- pointer, keyboard, focus and form submission come from the native input;
PageUp/PageDownmove by a tenth of the whole range, andArrowRight/ArrowLeftincrease and decrease a vertical slider in every browser - a form reset restores
defaultValue, unless the reset is canceled - values off the step grid or outside
min/maxare snapped like the native input does, and values out of order are sorted, so the thumbs, the native inputs and the submitted values always agree - several thumbs on one track: each input gets its neighbours as native
min/max, so thumbs cannot pass each other andaria-valuemin/aria-valuemaxshow the real limits;minStepsBetweenThumbskeeps a gap - the inputs of neighbouring thumbs are cut with
clip-pathat the midpoint between their values, so a click on the track moves the nearest thumb and stacked thumbs split at their centre; the slider looks disabled when none of its thumbs is enabled - a vertical slider sets
touch-action: pan-x pinch-zoom, so a vertical swipe on it moves the thumb instead of scrolling the page variant,nameandminStepsBetweenThumbsonSlider;indexonSliderThumb;SliderThumbInputandSliderThumbIndicator- the thumb position takes
mininto account (before it wasvalue / max) SliderVariantandSliderOrientationtypes
- 90e3572
State callbacks follow one
onChangeXscheme, likeonChangeValueandDrawer'sonChangeOpen.Breaking:
Dialog,Popover,Select,Sheet,Tooltip:onOpenChangeis renamed toonChangeOpenSelect,PhoneFieldSelect:onSelectValueis renamed toonChangeValue
- 6f10f80
PinFieldinput reworked:- Breaking:
PinFieldHiddenInputis renamed toPinFieldInput, likePasswordFieldInputandTextFieldInput - Breaking:
PinFieldInputno longer takesdisabledandmaxLength; set them onPinField, so the input and the slots always agree - Breaking:
PinFieldtakesvalue,defaultValueandonChangeValue;PinFieldInputno longer takesvalueanddefaultValueand still fires its ownonChangeandonInput. The slots follow a controlledvaluechanged outside, and a form reset restoresdefaultValueunless the field is controlled maxLengthofPinFieldis optional and defaults to4- the
placeholderofPinFieldis also set on the input - Home and End move to the start and the end; Shift with an arrow key extends the selection natively
- the
PinFieldcontext is namedPinFieldContextin errors
- Breaking:
- 46cd85f
BREAKING:
SheetactiveSnapPointand theonChangeActiveSnapPointvalue are now indexes intosnapPointsin the order you pass them, likedefaultSnapPoint. They used to point into the snap points sorted by position.onChangeActiveSnapPointno longer fires on mount whendefaultSnapPointis set, and the sheet opens atdefaultSnapPointon the first frame.With
steppedSnapPoints, an edge swipe down no longer closes aSheetwithclosable={false}, and a closing swipe no longer also moves to the next snap point. - f827279
TimeFieldkeeps its value on the root like the other masked fields:- Breaking:
TimeFieldtakesvalue,defaultValueandonChangeValueas aHH:mmtime (HH:mm:sswhen the format has seconds),''while the text is empty or incomplete;TimeFieldInputno longer takesvalueanddefaultValue. A form reset restoresdefaultValueunless the field is controlled - Breaking:
formatuses the notation ofDateTimeField.timeFormat:'HH:mm' | 'HH:mm:ss'instead of'HH:MM' | 'HH:MM:SS' - Breaking:
minandmaxbound the whole time like a native<input type="time">: a complete time outside them is replaced by the nearest bound, instead of bounding each segment separately; invalid bounds are ignored - ArrowUp / ArrowDown step the hours by one and the minutes or seconds under the caret by
step, likeDateTimeField; digits of other numbering systems are accepted
@vega-ui/utils: newparseTemplateTime,formatTemplateTimeandnormalizeTemplateTimefor times typed by aHH:MM[:SS]template, andisISOTime, a check forHH:mm[:ss]strings - Breaking:
Минорные изменения
- 7d971b9
Controlled state for
TooltipandPasswordField:Tooltiptakesopen,defaultOpenandonChangeOpen, likePopoverPasswordFieldtakesshown,defaultShownandonChangeShownfor the password visibilityPasswordFieldToggleIconButtonexposes the visibility witharia-pressedand keeps the focus like a native button instead of moving it to the input, so mobile keyboards do not open on every toggle; give it a fixed label such as "Show password"- a custom
onClickonPasswordFieldToggleIconButtonno longer replaces the toggle - the
PasswordFieldcontext is namedPasswordFieldContextin errors, notPhoneFieldContext
- ecceb29
SegmentedControl: selection is owned by the native radio group; the indicator follows the checked segment through CSS anchor positioningThe component no longer mirrors the value in React state and no longer measures segments in a layout effect or
ResizeObserver. In uncontrolled mode the hidden radios own the selection, and the active segment and the indicator follow:checkedin CSS. In controlled mode React keepscheckedon the radios, so a change the parent does not accept is rolled back.- native form reset restores
defaultValue, and the indicator follows it - programmatic selection (
input.checked = true,form.reset()) moves the indicator without any events - the indicator follows layout changes (resize, font loading, label changes) without JS
- several controls on one page keep independent indicators
- without anchor positioning support the checked segment paints its own background instead of the sliding indicator
- Firefox moves the indicator without the slide animation
Breaking:
- removed
data-activefromSegmentedControlItem; target the checked segment with:has(input[type='radio']:checked) - removed the
--segmented-control-indicator-offsetand--segmented-control-indicator-sizeCSS variables
- native form reset restores
- 79413ab
Export
SlotandButtonBasewith their types from the package root, matching the@vega-ui/react/Slotand@vega-ui/react/ButtonBasesubpaths - ed90a1c
ISO string dates in
Calendarand date fields, like native date inputs;Calendarfollows the WAI-ARIA date picker patternCalendar:value/defaultValueare ISO strings:'YYYY-MM-DD'(single,''is empty),[start, end](range,''is an unset bound),string[](multiple)onChange→onChangeValuefrom/to→min/max('YYYY-MM-DD')disabledis now a boolean that disables the whole calendar; disabled dates moved todisabledDates(string | string[] | (date: string) => boolean)date/defaultDate/onChangeDate→month/defaultMonth/onChangeMonth: the visible month is given as a'YYYY-MM-DD'string of any day in it;onChangeMonthreports its first day and fires only when the month actually changes- the visible month defaults to the month of the selected date
activeDay/defaultActiveDay/onChangeActiveDayremoved: keyboard focus starts on the selected day in the visible month, otherwise today, otherwise the first available day- navigating to another month or year moves focus to the same day there, clamped to the month length and skipping unavailable days
referenceDateremoved from the public API- an empty controlled value (
'') now clears the selection - new type export:
CalendarValue
DateField,DateTimeField,DateRangeField:min/maxare ISO strings instead ofDate('YYYY-MM-DD';'YYYY-MM-DDTHH:mm[:ss]'forDateTimeField)disabledDatestakes ISO strings- like the WAI-ARIA date picker pattern, navigating the calendar only moves focus — the field value changes only when a day is picked, and Escape closes the calendar without changing it
Fixes:
-
Calendar: after picking a month in the month picker, WebKit no longer jumps back to the previous month -
Calendar: fast scrolling no longer skips months inonChangeMonth, the header and keyboard focus -
IndexedSnapScroller: with fractional item widths, scrolling no longer gets stuck on the last item of the window -
DateRangeFieldCalendar: removed a leftoverconsole.log -
@vega-ui/hooks:useSelectionacceptsnullas an empty single selection;useScrollSnapupdates the pending snap on instant programmatic scrolls and no longer swallows snap changes when re-measuring or committing onscrollend -
@vega-ui/utils: newformatISODate,parseISODate,parseISODateTime,sanitizeISODates
Breaking: the
Calendarprops above and themin/max/disabledDatestypes of the date fields change.
Исправления
- 471516f
Accordion no longer adds an already opened value to
openedagain, soonChangeOpenednever receives duplicates. - dc610af
AccordionTriggerpasses its other props, such asonClick,id,aria-*andasChild, to the trigger button instead of dropping them - 03a8337
Alert
fillappearance uses the same translucent tinted background and text color as Badgeghost. - b8ee302
Alertkeeps its content at the start of the row when it has noAlertMaininstead of pushing it to the end - 5feb6c9
fixed merging events & snapping to step
- afa700c
ButtonBase(andButton,IconButtonand other buttons built on it) no longer sets the nativedisabledattribute on the child element withasChild. The child owns its disabled state: a disabled link is an<a>withouthref, witharia-disabled="true"for the disabled styling and announcement. - ffd63aa
DialogTrigger,DrawerTrigger,SheetTrigger,PopoverTrigger,TooltipTriggerandOptionrendertype="button", so clicking them inside a form no longer submits it. Atypeprop still overrides it, andasChildleaves the child element untouched - 184b98f
Cardtypes itsrefasRef<HTMLElement>to match the rendered<article>(or theasChildelement) and itsHTMLAttributes<HTMLElement>props. - 2b5af5f
DataGrid isolates its stacking context, so the DataGridPicker range highlight is no longer hidden behind the background of a wrapping element.
- bf2b34c
DialogContentfades in and out together with its scale transition instead of appearing and disappearing at full opacity - 171e217
DrawerContentnow lets its own props win over the drawer's internal floating props, likeDialogContentandSheetContent. Arolepassed toDrawerContentis no longer replaced bydialog, and internal event handlers run before yours. - 480483c
DrawerTriggerregisters itself as the reference element instead of the floating one, so focus returns to the trigger when the drawer closes - 5603707
Changed badge colors to WCAG
- 5170410
Checkbox,SwitchandSegmentedControlItemprops extendLabelHTMLAttributes<HTMLLabelElement>, so label attributes such ashtmlForandformare typed. - 03bf865
Size, variant and appearance types (
ButtonSize,TextFieldSize,BadgeVariant,HeadingSizeand the rest) suggest their known values in the editor again. They were unions withstringornumber, which TypeScript collapses into a plainstringornumber; they now end with(string & {})or(number & {}), so any other value is still accepted. - 02aec39
MeterTrackfills relative tominandmaxlike the native<meter>, and the fill is clamped to the range. Previouslyminwas ignored and values outside the range overflowed. ThemaxJSDoc now states the actual default of1. - 0d7649f
NumberFieldfollows<input type="number">:- stepping keeps the decimals of the value and of
step:0.7+0.1gives0.8(before, the mask cut0.7999999999999999to0.79) - the wheel steps the value only when the input is focused and under the pointer; over an unfocused field it no longer blocks the page scroll
- a root
onKeyDownruns after the built-in arrow keys instead of replacing them
@vega-ui/utils:- new
addWithPrecision(value, delta), a sum rounded to the decimals of its operands - new
countDecimals(value), the decimals of a number, also in exponent notation (1.5e-7→ 8) snapToStepkeeps the precision of steps written in exponent notation (step={1e-7}no longer rounds to integers)
- stepping keeps the decimals of the value and of
- c4672d5
Backdrop, PopoverContent and SelectListbox use the
--z-index-overlay/--z-index-popovertokens instead of a hardcodedz-index: 1, so popovers and listboxes open above dialogs, drawers and sheets. The backdrop fade now uses--transition-state-delay, matching the overlay unmount timing so the fade-out is no longer cut off. - 6f1f6f2
PageControlProgress cancels its progress animation frame when the item stops being active or unmounts, so stale loops no longer overwrite its progress value.
- d8ce64e
PaginationEllipsis renders the ellipsis character
…(U+2026) instead of three dots. - 7106cb0
PaginationPropsextendsHTMLAttributes<HTMLUListElement>to match the rendered<ul>and itsref. - 7ce2cf5
Popoverpasses the HTML attributes allowed by its props, such asid,styleanddata-*, to its root element instead of dropping them - a89803a
Enable
react-hookslint rules repo-wide; fix all stale-closure findings; adduseEventCallbackeslint-plugin-react-hookswas installed but none of its rules were enabled — the class of bugs behind the recent Slider and Calendar stale closures was invisible to CI.rules-of-hooksandexhaustive-depsnow run as errors (withrules-of-hooksoff for Storybook CSFrenderfunctions, which are false positives).- new
@vega-ui/hooksexport:useEventCallback— a stable-identity wrapper that always calls the latest handler (the industry "latest ref" pattern à la MUI/Radix/Floating UI), throws in development if called during render useScrollSnap:onSnapChanging/onSnapChange/getSnapPointgo throughuseEventCallback, so inline consumer callbacks no longer resubscribe thescrollendlistener and observers on every render; the remaining deps are honestCalendar:onSelectDayno longer freezes the firstonChange— it reads the latest callback throughuseEventCallbackwhile keeping a stable identity (regression-tested by swappingonChangebetween renders)NumberField:decrementno longer clamps against a stalemax; the native non-passivewheellistener is attached only whilechangeOnWheelis enabled and no longer resubscribes whenmin/max/stepor the value changeuseSelection: a consumer-providedresolveRangeno longer cascades identity changes intoselect/expand/toggleCollapsible:onChangeHiddenfires only whenhiddenactually changes — an inline callback no longer re-triggers the notification effect on every parent render- all remaining findings were stable-value dependencies added for free, plus three documented intentional suppressions (
useMutationObserverper-field options deps,createContextshallow-by-value memoization,SnapScrollerContentunmount-only unregistration)
- new
- 2d877ef
Respect
prefers-reduced-motionin SnapScroller, Calendar, SegmentedControl, PageControl and Collapsible: scrolling jumps, sliding and resizing are instant, and PageControlProgress fades in over its duration, soanimationendstill fires.useScrollSnapno longer forces smooth scrolling:scrollToElementandscrollToElementByKeydefault tobehavior: 'auto', like nativescrollTo, so the CSSscroll-behaviorof the scroller decides. To keep smooth scrolling, setscroll-behavior: smoothon the scroller or pass'smooth'. - df7c7be
SelectwithoutdefaultValuestarts with no selection instead of'', so an option withvalue=''is no longer selected by default and a numericSelectno longer holds a string.defaultValue=''still shows the placeholder. - 3b2445b
Fix Select typeahead skipping options with falsy values
onMatch(typeahead selection while the listbox is closed) guarded the matched value withif (!value) return, so options whose value is0or an empty string could be highlighted but never actually selected — common with numeric IDs. The guard now checks forundefined(a missing map entry) only. Covered with a regression test that selects avalue={0}option by typing. - 70c9eb0
Fix a Select listbox inside a Dialog that could open off-screen because its position was measured before it entered the top layer.
- db3c63f
Sheetanimates its release, opening and closing through its registered--sheet-*variables instead oftransformandclip-path, so the clip, the surface and the position stay in sync, and the bottom edge no longer jerks at snap points. The sheet no longer widens while it opens.--sheet-insetand--sheet-backgroundmust now be set onSheetContentitself: a value from an ancestor no longer reaches them - cd1589b
Remove the stray JSDoc block above
dismissibleofSheetand document itstruedefault - 0efc57b
Overlay parts of
Dialog,Drawer,Popover,Select,SheetandTooltipno longer detach and attach a passedrefon every render. MakeSheetdrag run without React renders on its moves, layout or style recalculation of its content.--sheet-offset,--sheet-expansionand--sheet-clipare no longer inherited by the children ofSheetContent.blurredonSheetContentnow defaults tofalse, like a native iOS sheet. The surface of the sheet is now a separate layer: set its color with--sheet-backgroundinstead ofbackground.::afterofSheetContentis now taken. The content ofSheetContentkeeps its width between snap points, with--sheet-insetadded to its side padding. The sheet follows the pointer exactly, stops under a press while it settles, and withsteppedSnapPointsresists a drag past the next snap point. It settles on a curve without overshoot, and stops below the top safe area. A light flick no longer closes the sheet: momentum counts less towards closing than towards a snap point. The sheet closes over the same duration as it opens, and after a drag it continues at the speed of the pointer. Snap points that share an offset report the last index, and a drag back to the active offset keeps the active snap point - 83b8a95
Size types match the styles:
OptionSizeincludesxsandxl, whichOptionalready styles andSelectpasses downPageControlSize,TextSizeandCalendarBaseVariantsuggest their values and accept a custom one, like the other components- the glossary documents the size scales: named sizes for controls and containers, numeric font steps for
Heading,TextandSpinner
- b5afed6
Changed badge ghost colors
- 065975a
Sliderno longer callsArray.prototype.at, so it works in browsers without it (Safari before 15.4) - 7609961
SnapScrollercreates itsapiRefonce instead of on every render, so a callbackapiRefis no longer detached and attached again on each render. - d7a7658
Table, Calendar, CalendarBase, DayPicker, YearPicker, AvatarStack and Switch use
--spacing-*tokens instead of hardcoded pixel spacing, so they follow a customized--spacingscale. No visual change with the default tokens. - 16303cb
Spinnerhasrole="progressbar"without a value, like a native<progress>withoutvalue, so screen readers announce it as a busy indicator. Name it witharia-labeloraria-labelledby; setaria-hiddenwhen it only decorates something that already announces the loading state. - 3e998c5
--text-color-inverceis renamed to--text-color-inverse.Breaking: themes that set
--text-color-invercemust set--text-color-inverseinstead. - 93dce53
TooltipContentstays mounted until its close transition ends instead of disappearing at once - d8b4396
Tooltippasses the floating styles to its content without copying them on every render - 6f10f80
- Breaking:
setValueanddispatchEventsare replaced bywriteInputValue(input, value)from@vega-ui/utils: it sets the value through the native setter, so React sees the change, and dispatches bubblinginputandchangeevents - the context of
NumberFieldis namedNumberFieldContextin errors instead ofPhoneFieldContext getPending()andgetCommitted()of theSnapScrollerapi ref andindexof theIndexedSnapScrollerapi ref are typednumber | null: they arenulluntil the scroller has measured its items
- Breaking:
2.5.0
Исправления
- 9834a4c
Remove React from
dependencies, keep it only inpeerDependenciesreact(andreact-domin@vega-ui/react) were declared in bothdependenciesandpeerDependencies. With strict resolution (Yarn PnP, pnpm withshamefully-hoist=false, strict npm) consumers ended up with two copies of React —Invalid hook call, contexts not matching, rendering breaking with no clear error.Changes:
- removed
react/react-domfromdependenciesin@vega-ui/react,@vega-ui/hooksand@vega-ui/icons; they stay inpeerDependenciesand were added todevDependenciesfor local development vite.config.tsof@vega-ui/reactand@vega-ui/hooksderived rollupexternalfromObject.keys(dependencies)only, so React would have been bundled intodistafter this change — externals now includepeerDependenciesas well
- removed
- 0ffc52f
useSelection: optionalcompareno longer crashes; newcompareutilcompare?was declared optional but invoked unconditionally inedges,isSelectedandisDisabled— range selection ormin/maxclamping without a user-provided comparator threwcompare is not a function(whileexpandhad a guard, confirming the option was meant to be optional).@vega-ui/utilsnow exportscompare— a three-way comparator constrained to the newComparabletype (number | string | bigint | Date), so types with no universal ordering (objects, symbols) are rejected at compile time; covered with unit testsuseSelectionfalls back to it when nocompareis passed, mirroring the existingequals ?? Object.ispattern; pass an explicitcomparefor non-primitive key typesexpandno longer silently no-ops without a user comparator- empty or
undefinedselectedno longer producesundefinedrange edges:edges()returns[],isSelectedreturnsfalseinstead of comparingundefined DataGridSelectablereuses the sharedcompareinstead of its own inline duplicate of the same fallback (no behavior change)
- 25c721b
Fix stale closure in Slider's
changeValuechangeValuewas wrapped inuseCallbackwith empty deps, freezingvalueanddisabledat their first-render values. Consequences: the slider could never return to its initial value (keyboard stepping got stuck one step away from it, clicking the initial track position was ignored); the same-value dedup guard compared against the initial value instead of the current one, soonChangeValuefired repeatedly with identical values during drags; togglingdisabledafter mount had no effect on interactions (an initially enabled slider stayed interactive when disabled, an initially disabled one stayed dead when enabled).The memoization served no purpose —
changeValueis only used by handlers that are recreated on every render — so it is now a plain function reading fresh props. Covered with regression tests for all three symptoms.
2.4.0
Минорные изменения
- a77ab19
Changed xs, sm, md, lg, xl sizes of all components
Исправления
- 47f3ced
Fixed select listbox background
2.3.1
Исправления
- 3858f99
Refactored color system and semantic tokens
- Updated color palette in
@vega-ui/tokens-core: revised oklch values across all color scales for better perceptual uniformity - Replaced static surface tokens (
surface-ultrathin…surface-ultrathick) withsurface-primary/surface-secondaryin both light and dark themes - Tweaked fill token chroma/lightness values in light and dark themes for improved contrast
- Button ghost/transparent hover and active backgrounds now use
oklch(from …)relative color syntax instead of hardcoded palette steps, making them automatically adapt to any primary/secondary accent color - Added Playground story showcasing Badge, Button, Alert, Checkbox, Radio, Avatar, SegmentedControl and Slider in a single view
- Updated color palette in
2.3.0
Минорные изменения
- 064d8c0
@vega-ui/tokens-core
Complete overhaul of the color palette:
- Colors migrated from
color-mix(in oklch, var(--color-red) X%, white/black)to directoklch()values for more predictable perceptual color space - Removed intermediate steps (50, 150, 250, 350, 450, 550, 650, 750, 850, 950) — scale simplified to 11 steps: 0–100–200–…–1000
@vega-ui/theme-core
Complete overhaul of semantic tokens in
light.css/dark.css:- Added fill tokens:
--fills-primary/secondary/tertiary/quaternarywith hover/active states - Added label tokens:
--label-primary/secondary/tertiary/quaternary - Added surface tokens:
--surface-ultrathin/thin/regular/thick/ultrathick - Added separator tokens:
--separator-opaque/non-opaque - Added border tokens:
--border-colorwith hover/active states - Added disabled state tokens:
--disable-* - Added color accent tokens:
--color-*-accent-*— palette is automatically inverted in dark mode - Renamed:
--text-inverce-color→--text-color-inverce
@vega-ui/react
- All components migrated to new semantic tokens from the theme
- Removed direct color token references in components, replaced with semantic variables
- Colors migrated from
2.2.1
Исправления
- 66317ef
Changed switch colors
2.2.0
Минорные изменения
- 798d27c
Adding New Components
DateField
- A date input field with masking and format validation.
- Uses
useControlledStatefor controlled/uncontrolled values. - Composed of the following components:
DateFieldInputDateFieldCalendar
- Supports date formats (e.g., "dd.MM.yyyy", "MM/dd/yyyy").
- Supports minimum and maximum date restrictions (
minDate,maxDate).
DateTimeField
- A date and time input field.
- Combines the logic of
DateFieldandTimeField. - Composed of the following components:
DateTimeFieldInputDateTimeFieldCalendarTimeSelector(for selecting time)
- Uses
useControlledState.
DateRangeField
- A field for selecting a date range.
- Composed of the following components:
- Two
DateFields (start and end dates) DateRangeCalendar(calendar for selecting the range)
- Two
- Handles range validation (start date ≤ end date).
- Uses
useControlledState.
TimeField
- A time input field.
- Supports masking and time format (e.g., "HH:mm").
- Uses
useControlledState. - Composed of the following components:
TimeFieldInput- Additional controls (arrows, time selector)
Исправления
- bac86b3
Fixed date time field cahnge date
2.1.1
2.1.0
Минорные изменения
- 8380d3b
Refactor Calendar stack to scroll-snap scrollers (DataGridPickerScroller) and remove react-store based state.
@vega-ui/ui
SnapScroller
- BREAKING:
initialIndexrenamed todefaultIndex. - BREAKING: removed
preserveScroll. - BREAKING: removed
onOffset. - Added scroll-snap callbacks:
onScrollSnapChanging?(element, index)onScrollSnapChange?(element, index)
IndexedSnapScroller
- Keeps offset-based infinite behavior (window
shift()/push()) and optionalpreserveScroll. - Supports controlled
index(scrolls to it when in window; rebuilds window when outside).
DataGrid
- BREAKING:
onMove(e, node, axis, dir)replaced withonArrow(e, nextNode, prevNode). - BREAKING:
DataGridApiRefchanged:- removed
keyMap - added
scopes: Map<DataGridScope, DataGridCellKey[]>
- removed
DataGridRowGroupnow supportsscope?: DataGridScopeand provides it via context.- Cells unregister from the grid on unmount (node cleanup).
- Active/selection focus flow updated to sync active cell on focus changes.
DataGridPicker
- Added
DataGridPickerScrollerandDataGridPickerScrollerContent. DataGridPickerScrollerintegrates with scroll-snap events to restore/adjust active focus for the current scope.
DayPicker
- BREAKING: DayPicker scrolling is now driven by
DataGridPickerScroller(instead of IndexedSnapScroller directly). - Added period-to-index mapping via reference anchor:
referenceDate?: DategetIndexByDate?(year, month)getDateByIndex?(index)
- Period changes are emitted during scroll via
onScrollSnapChanging.
YearPicker
- BREAKING: YearPicker scrolling is now driven by
DataGridPickerScroller. - Added year-to-index mapping via reference anchor:
referenceYear?: numbergetIndexByYear?(year, referenceYear)
- Layout derives offset from
yearwhenoffsetis not provided.
Calendar / CalendarBase
- BREAKING:
onYearChange->onChangeYear - BREAKING:
onMonthChange->onChangeMonth - Added controlled/uncontrolled view state for navigation:
year/defaultYearmonth/defaultMonthactiveDay/defaultActiveDay+onChangeActiveDayactiveMonth/defaultActiveMonth+onChangeActiveMonthactiveYear/defaultActiveYear+onChangeActiveYear
- Added
referenceDate?: Dateas an anchor for indexed/virtualized navigation. - Added year-group navigation controls:
CalendarNextYearGroupButtonCalendarPrevYearGroupButton
- Picker/ESC handling updated (Escape now stops propagation).
- Period navigation split into:
nextPeriod/prevPeriodnextYearGroup/prevYearGroup
@vega-ui/hooks
- BREAKING: removed
useStore,useControlledStore(react-store dependency removed). - BREAKING: removed
useIntersectionObserver. - Added:
useScrollSnap(snap measurement +onSnapChanging/onSnapChange)useMutationObserveruseBiMap
useRefMapnow exposesremoveItemRef.useIndexesupdated to support new shifting semantics safely.
@vega-ui/react-store
- BREAKING: package removed / no longer used in the monorepo.
@vega-ui/utils
- Added
BiMapandnearest. - Reorganized data helpers under
utils/data/*with re-exports.
- BREAKING:
2.0.1
Исправления
- 697ebd5
Improved a11y - accordion
2.0.0
Мажорные изменения
- 357ab44
- Add new
Tooltipbuilding blocks: -TooltipArrow
- Add new
Минорные изменения
- 95b6ae7
-
The
Drawercomponent has been refactored to support a fully composable architecture. -
Added the following subcomponents to allow flexible composition and advanced customization:
DrawerTriggerDrawerPortalDrawerOverlayDrawerContentDrawerHeaderDrawerTitleDrawerCloseButton
These additions enable fine-grained control over drawer structure, layout, focus management, and visual presentation, while preserving accessibility, focus trapping, and native interaction patterns
-
- 50bc30f
Refactor form controls architecture and remove deprecated components.
Removed (breaking)
- Remove
FlagIconpackage exports and implementation. - Remove
PhoneSelectFieldand related subcomponents/contexts/styles. - Remove legacy
SelectArrowandSelectPlaceholdercomponents. - Remove legacy
NumberFieldIncrement/NumberFieldDecrementcomponents. - Remove legacy
PinFieldInputcomponent.
Added
- Add new
NumberFieldbuilding blocks:NumberFieldInputNumberFieldIncrementButtonNumberFieldDecrementButtonNumberFieldContext(new contexts structure)NumberFieldtypes module
- Add new
PasswordFieldbuilding blocks:PasswordFieldInput,PasswordFieldToggleIconButtonPasswordFieldShownIcon,PasswordFieldHiddenIconPasswordFieldContextand component index exports
- Add new
PhoneFieldcomposition:PhoneFieldInputPhoneFieldSelect+ subcomponents (Combobox,HiddenSelect,Icon,Listbox,Option,Portal,Value)PhoneFieldContextand component index exports
- Add
PinFieldHiddenInputcomponent (single visually hidden input backing the slots). - Add new
Selectbuilding blocks:SelectHiddenSelect,SelectIcon,SelectPortal,SelectValuehelpersSelectOptionsContext
- Add new
TextFieldInputcomponent andTextFieldContext.
Changed
- Update
PinFieldinternals, contexts, slots, separator, styles and tests. - Update
Select,NumberField,PasswordField,PhoneField,TextFieldinternals, styles, stories and tests. - Update
Optioncomponent and related types/styles. - Update
Drawerinternals and context, plus stories. - Update library root exports (
packages/ui/src/index.ts).
Tests
- Update existing tests for refactored components.
- Add/adjust stories for new subcomponents.
- Remove
- ca0cb2b
The Accordion component has become more composable: the AccordionIcon and the AccordionHeader have been added.
- 35a056a
The Popover component has become more composable: the PopoverBackdrop have been added
- 21e1d64
Made Alert more composable: added the elements alertTitle, AlertIcon, AlertMain, AlertContent
- e58908c
Added Backdrop component
- 7ef3f1b
The Checkbox component has become more composable: the CheckboxHiddenInput, CheckboxIndicator, CheckboxCheckedIcon and the CheckboxIndeterminateIcon have been added.
- 9489f2e
The loading property in the button has been removed to better match the component to the overall architecture and approach
- 4072edd
The Meter component has become more composable: MeterTrack component has been renamed AvatarGroupStackItem The Progress component has become more composable: ProgressTrack component has been renamed AvatarGroupStackItem The PartialTrack component has been renamed (MeterStack), PartialMeterItem is now MeterStackSegment
- 0023797
The AvatarGroup component has become more composable: AvatarGroupPopover, AvatarGroupPopoverIcon, AvatarGroupPopoverTrigger, AvatarGroupPopoverContent, AvatarGroupCount, AvatarGroupStack components have been added, AvatarGroupItem component has been renamed AvatarGroupStackItem
- acaabbc
The AvatarGroup component is now AvatarStack, which more reflects its spirit; Moreover, the AvatarGroupPopover and related components, as well as AvatarGroupCount, have been removed due to the fact that they inflate the codebase and can be implemented with existing primitives
- 5c33866
The CheckboxCard component has become more composable: CheckboxCardContent, CheckboxCardTitle, CheckboxCardDescription, CheckboxCardControl, CheckboxCardControlHiddenInput, CheckboxCardControlIndicator, CheckboxCardControlCheckedIcon, CheckboxCardControlIndeterminateIcon components have been added
- d4d1a53
Unified TextArea sizes
- f9dacd3
The Modal component has been renamed Dialog due to the greater consistency with the naming of native web elements
- 6fae7e6
The Fieldset component has become more composable: the FieldsetHeader and FieldsetLegend components have been added
- bd99cb1
The Switch component has become more composable: SwitchIndicator and SwitchHiddenInput components have been added
- 82d11c9
- The
Sheetcomponent has been refactored to support a fully composable architecture - Added the following subcomponents to allow flexible composition and advanced customization:
SheetPortalSheetBackdrop
- The
- 7b2c7fe
Composable Slider
- d2a2c5a
-
The
Dialogcomponent has been refactored to support a fully composable architecture. -
Added the following subcomponents to allow flexible composition and advanced customization:
DialogTriggerDialogPortalDialogOverlayDialogContentDialogHeaderDialogTitleDialogCloseButton
These additions enable fine-grained control over drawer structure, layout, focus management, and visual presentation, while preserving accessibility, focus trapping, and native interaction patterns
-
- e0a38ab
The SegmentedControl component has become more composable: the SegmentedControlItemHiddenInput and SegmentedControlIndicator have been added.
- 31b2b94
Improved backdrop animations
- eab55a8
The responsive-ui package is no longer supported due to inconsistencies in the overall component design approach
The components that the responsive ui package contained are easily implemented using the composition of existing ones and do not require the support and development of a separate package
- cfb207b
Unified all sizes
1.14.3
1.14.2
Исправления
- 55809c0
Changed deps
1.14.1
1.14.0
Минорные изменения
- a387fda
Added new calendar primitives:
- CalendarBase — foundational layout and styling provider for all calendar components (size, variant, compact mode).
- Calendar — high-level fully interactive calendar with day/month/year pickers, scroll-based navigation, controlled/uncontrolled selection modes, and full provider-based state management.
These components form the new core of the calendar system and enable building flexible, Radix-style declarative/imperative calendar interfaces.
1.13.0
Минорные изменения
- abbdcdc
Add composable calendar picker primitives and index-based snap scroller utilities.
New pickers
-
YearPicker- High-level year selection component built on top of
DataGridPicker<number>. - Supports
single,multiple, andrangeselection modes withfrom/tobounds. - Provides a default
YearPickerLayout(configurablerows,cols,start,offset). - Adds composable primitives:
YearPickerItem,YearPickerRow,YearPickerRowGroupYearPickerScroller,YearPickerScrollerContent,YearPickerScrollerLayout
- Includes helpers like
createYearPickerGridfor generating year grids.
- High-level year selection component built on top of
-
MonthPicker- Wrapper over
DataGridPicker<number>specialized for month selection. - Default active value resolves to the current month.
- Provides:
MonthPickerLayoutwith configurablerows,cols,start,locale,formatMonthPickerItem,MonthPickerRow,MonthPickerRowGroupMonthPickerScroller,MonthPickerScrollerContent,MonthPickerScrollerLayout
- Adds
createMonthPickerGridfor building month matrices (e.g. 3×4 year views).
- Wrapper over
-
DayPicker- Day-level calendar picker built on
DataGridPicker<number>with default active set to “today” (timestamp). - Supports
single/multiple/rangeselection and can respect min/max viaDataGridPicker. - Provides:
DayPickerLayoutwithyear,month,offset,includeOverflowDays,weekStartsOn,rows,cols,locale,formatDayPickerItem,DayPickerRow,DayPickerRowGroupDayPickerScroller,DayPickerScrollerContent,DayPickerScrollerLayout
- Adds
createDayPickerGridto generate month views with optional overflow days and arbitrary week starts.
- Day-level calendar picker built on
New scroller utilities
IndexedSnapScroller- Extends
SnapScrollerwith virtual, index-based paging. - Maintains a sliding window of logical page indexes via
useIndexes({ start, startDir, size, shift }). - Automatically shifts the window when scroll reaches edges (
onOffset(-1|1)). - Exposes:
IndexedSnapScrollercomponentIndexedSnapScrollerContent(injectsindexvia context)IndexedSnapScrollerProvider/useIndexesSnapScrollerContextfor consuming the current index in custom layouts.
- Extends
Formatting helpers
- Add small date-format helpers, suitable for use inside picker layouts:
formatDay(day, month, year, locale?, format?)formatMonth(month, locale?, format?)formatYear(year, locale?, format?)
These additions provide a fully composable calendar system (years, months, days) on top of
DataGridPickerandSnapScroller, while keeping layout and rendering customizable through small, focused primitives. -
1.12.4
1.12.3
Исправления
- b433cff
Fixed RangeSlider performance
1.12.2
1.12.1
Исправления
- 22dea95
A bug was fixed in which it was impossible to expand the selected range on mobile devices and scroll in SnapScroller, as well as minor edits were made: when changing the range to the beginning and end, reset is not triggered.
- 3b2c885
Added selected and default selected as a prop for DataGridSelectable
1.12.0
Минорные изменения
- 30e9724
This release introduces a complete grid, selection, and scroll system for structured, interactive UIs. It combines efficient keyboard navigation, flexible selection logic, and smooth snap scrolling — forming the foundation for advanced table, calendar, and picker interfaces.
📊
DataGridDataGridis a focusable, navigable grid that manages keyboard movement and active-cell focus.- Supports navigation with Arrow, Home/End, and PageUp/PageDown keys
- Optional wrap navigation (horizontal, vertical, or both)
- Configurable rowDelta for page jumps
- Provides an imperative API (grid, keyMap) for advanced logic
- Supports excluded or disabled cells that are skipped during traversal
- Emits onMove events describing direction and axis of movement
Used as the base for all higher-level grid-based components.
🧭
DataGridSelectableDataGridSelectableextends DataGrid with a full selection model.- Selection modes: "single", "multiple", "range"
- Keyboard (Shift + Arrows) and pointer-based range selection
- Optional disabled and bounded ranges (from / to)
- Fully integrated with the useSelection hook
- Provides consistent accessibility and state behavior
Ideal for building interactive tables, lists, and date selectors.
🎯
DataGridPickerDataGridPicker builds on DataGridSelectable to enable picking and highlighting items within a grid.
- Automatically computes rectangular ranges between selected cells
- Supports highlighting of continuous intervals (start → end)
- Can be customized with a user-defined resolveRange function
- Commonly used for date pickers, emoji selectors, or option matrices
🧱
SnapScrollerSnapScrollerprovides smooth, scroll-snap navigation with full control and callbacks.- Optimized for CSS scroll-snap-align behavior
- Exposes imperative API: next(), prev(), element
Triggers:
- onSnap(index) — when snapped item changes
- onOffset(direction) — when scroll reaches start or end
Optional preserveScroll restores snapped position after content updates
Perfect for carousels, paginated lists, or horizontally scrolling pickers.
🪝
useSelectionHookuseSelectionis a composable hook for declarative selection management.- Supports "single", "multiple", and "range" modes
- Provides helpers: toggle, expand, isSelected, edges, and more
- Accepts custom equals, compare, and resolveRange logic
Used internally by DataGridSelectable and DataGridPicker
⚙️
Grid & Matrix UtilitiesThese low-level utilities power the core grid logic and ensure efficient traversal.
gridA high-level controller for navigating 2D layouts:
- Provides directional movement (before, after, above, below)
- Handles row and column wrapping
- Uses Matrix internally for structure and lookup
matrixA modular 2D data engine with the following components:
Matrix— manages all rows and cellsMatrixRow— ordered row container with iterable accessMatrixNode— represents a single cell ([row, col], key, payload)MatrixIndexes— maintains sorted indices with binary searchTogether, they ensure fast lookups and navigation across sparse grids.
This release establishes the foundation for interactive, accessible, and performant grid-based interfaces in Vega UI — enabling developers to build pickers, calendars, tables, and carousels with minimal boilerplate and maximum control.
1.11.4
1.11.3
Исправления
- 0392555
Made graphite color more contrast than gray
1.11.2
Исправления
- 61a382b
The gray colors have been changed, the surface has been added, and the fields styles have also been changed
1.11.1
Исправления
- eef91ab
Fixed sheet paddings
1.11.0
Минорные изменения
- a4c6339
SheetContent will now contain SheetMain, SheetHandle, and SheetHeader inside
1.10.1
1.10.0
Минорные изменения
- d5538a5
Added new sizes (xs, xl) for button, icon button and segmented control
1.9.0
Минорные изменения
- c90a0c1
Added new packages - tokens and theme
1.8.1
Исправления
- c98c982
Added Size prop to PageControl, added hook useRefMap, improved accessability, added mergeEventHandlers util
1.8.0
Минорные изменения
- 83bafaa
Added new component - PageControl
1.7.4
Исправления
- 7031b78
NumberField separated to components
1.7.3
1.7.2
1.7.1
1.7.0
1.6.0
Минорные изменения
- c672c1e
Added accordion item provider
1.5.0
Минорные изменения
- 89c9898
Added new compoents - AccordionTrigger, AccordionContent, that brings new flexibility for styling elements
1.4.2
1.4.1
Исправления
- a136ce0
Deleted @property css
1.4.0
Минорные изменения
- e022b3c
Added new utilities
1.3.0
Минорные изменения
- 279075a
Changed providers of icons - lucide
1.2.2
Исправления
- a80dac4
Changed Alert styles accorded to Figma
1.2.1
Исправления
- 3bdf4de
Changed slider styles
1.2.0
Минорные изменения
- 6224045
Added new component - RangeSlider, Slider and SliderBase
1.1.1
Исправления
- ffa6cc4
Fixed exports
1.1.0
Минорные изменения
- c226a32
Added new components - Meter, MeterStack and Progress
1.0.1
Исправления
- fb2ec42
Changed logo