Astryx v0.5.3
[!WARNING] Stepper context compatibility: v0.5.3 changed the package-exported
StepperContextValue/useStepperContextshape. Ordinary<Stepper>and<Step>usage is unaffected, but consumers that call the context hook directly or constructStepperContextValueshould remain on v0.5.2 while a source-compatible repair is evaluated. See #5659.
Astryx 0.5.3 — all @astryxdesign/* packages ship at this version.
npx astryx upgrade --apply
- Add built-in
popover,bottom-sheet, and compact-touchadaptivepresentation policies to DropdownMenu, MoreMenu, and ContextMenu. (#5395) - Add popover, bottom-sheet, and adaptive presentation options to Selector and MultiSelector, with docsite examples for both bottom-sheet variants. (#5395)
- Add
isReadOnlyto Selector and MultiSelector so selected values remain focusable and form-submittable without exposing selection menus or editing affordances. (#5805) - Add the opt-in theme-local token contract for maintained theme families. (#5844)
- Add
elevationprop to ToggleButton for floating (FAB-style) toggles, mirroring Button; retained inside a ToggleButtonGroup. (#6012)
-
Add structured accessibility requirements and theme coverage support to component documentation. (#5713)
-
Banner: the header's supporting line now carries a stable theme target,
astryx-banner-description. (#5483) Only the header, the status icon and the content panel were themeable before, so a theme restyling the description — its colour, its type, or the space between it and the title — had to reach in with a structural selector like.astryx-banner > div:nth-child(2) > div:nth-child(2). Purely additive: no existing class, data attribute, or style changes. Nothing else in the header becomes a target. The end area is a layout row — flex, wrap, and the edge compensation that lets its buttons overhang the header padding — not a painted surface, and a theme that wants the header to grow around its buttons instead of letting them overhang setspadding-blockon the existingbannertarget, which reaches the same height without exposing a private margin. The title, the two controls and the text column are likewise left alone: the column paints nothing (display: flex; flex-direction: column; gap: 0) and the space it owns is expressible onbanner-description, while the title and the controls already render the way the consuming theme wants them. -
Add
nativePickerto DateTimeInput for browser and OS date/time pickers, with Astryx time fallbacks for seconds, custom increments, and preset options. Native fields follow DateInput's compact minimum sizing in fit-content layouts. (#5620) -
Let themes add typed Heading visual roles with a safe semantic-level fallback when the owning theme styles are unavailable. (#6026)
-
RadioListItem and CheckboxListItem accept rich
labelanddescription(#5257)RadioListItemtypedlabelanddescriptionasstringwhile its siblingCheckboxListItemalready typedlabelasReactNode— so the same slot had two contracts, and an app whose option descriptions carry links could not type them on either component. Both now takeReactNode; the runtime already rendered it.RadioListItemgains thearia-labelescape hatchCheckboxListItemestablished, with the same meaning: a plain-text accessible name for the control. The radio differs in one way worth knowing — it points at its visible label for its accessible name, so a rich label still names it from its own text, andaria-labelis there to narrow a name that reads badly rather than to supply a missing one.aria-labelnow lands on the radio instead of the row<div>, where ARIA ignored it. -
Stepper:
--step-connector-gap, so a theme can stop the on-track connector short of the indicator The on-track layouts draw the connector as one segment either side of the node. A theme that wants the track to leave a hole around the indicator had to reach the two segments separately, and they are only distinguishable by sibling position — which changes withindicator="none".One public var does it instead, declared on the Stepper root because component vars are root-owned: a theme writes
stepper: {base: {'--step-connector-gap': '4px'}}and every connector inherits it. Astryx spends it on whichever side each segment faces the node from, so the pair leaves a symmetric hole and the caller never names the pieces.0pxby default: the shipped track still reads as one unbroken line.Measured in Chromium against a built theme override, reading painted pixels down a 12px segment:
| value | clipped away | stepper height | | ------- | ------------- | -------------- | |
6px| 6px | unchanged | |-4px| 0 | unchanged | |1rem| capped to 8px | unchanged | |999px| capped to 8px | unchanged | |10%| 1px (of 12px) | unchanged | |50%| capped to 6px | unchanged |Four things that had to be true and are:
A theme override reaches it. The default is declared once on the root, not on each connector. Declared per-connector, every connector re-declared
0pxon itself, and a value declared on an element beats an inherited one — so a generatedstepperoverride compiled cleanly and changed nothing.The value is bounded, and both halves earn it — neither for padding's reasons.
max(0px, …)becauseinset()accepts a negative length: Chromium computesinset(0 0 -4px 0)as written rather than clamping it the way it clamps negative padding, so the floor has to be declared.min(…, --spacing-2)— the flexible segment's ownmin-height— so an oversized gap leaves a short track rather than an unbounded one. Neither can grow the Stepper; a clip cannot change layout. (An earlier padding-based revision grew a three-step Stepper 108px → 144px at1rem.)The horizontal clip mirrors under
dir="rtl".clip-path: inset()is physical — top/right/bottom/left, no logical form — while the row itself reverses. Left unflipped, the leading segment sits to the right of the node in RTL and still clipped its right edge, so the hole opened at the join between steps instead of at the indicator. Measured before the fix:con0 x=622, indicator x=606, clips RIGHT edge. After:clips LEFT edge, with LTR unchanged. The block axis needs no handling —dirdoes not reverse it.One declaration covers both layers. The gap has to reach the track (the segment's own background) and the accent fill (an absolutely placed
::before). Spending it on each separately meant two declarations on two boxes, so a percentage resolved against a different containing block for each and stopped them ~1.2px apart. A singleclip-path: inset(…)on the segment clips the element and its pseudo-element together against one reference box, so every accepted value behaves identically on both — which is what #5824 requires of a public input across its full value domain. Clipping also cannot change layout, so the node the segment positions cannot move.No indicator, no gap.
indicator="none"renders no node, so a gap there is a hole in a track that is meant to be continuous.Any CSS length or percentage is accepted and behaves the same way on both layers. A percentage resolves against each segment's own box, so a fixed and a flexible segment clip by slightly different amounts from one declared value — cosmetic, bounded by the cap, and recorded as accepted rather than fixed.
Why a custom property and not a guaranteed CSS property. A theme target reaches the element, never its
::before. Measured against a built theme override onstep-connector:paddingBlock: 6pxproduces no hole at all — the background paints to its border box and the fill is out of reach — its only effect being the Stepper growing 108px → 120px;paddingBlockEnd: 6pxproduces no hole either, and addresses only one of the two edges. Only the component can clip both layers together, mirror per axis and direction, and clamp first.Adds
Stepper.spec.md, the canonical owning record for this public property, carrying that admission argument, the value contract, and the anatomy-to-target map.Stepper.doc.mjsgains the anatomy entries its existingstepper,step, andstep-connectortargets never had, so every current target is anchored to a described part.Supersedes the
segmentvariant this PR previously proposed. That exposedlead/rail/contentas public theming vocabulary, which does not hold up: the words never appeared in the generated docs, they emit barelead/contentclasses where a consumer's own stylesheet can collide with them, andleadmeans different geometry per orientation. The pieces are how this layout happens to be drawn today, not a contract. -
Stepper's
horizontalOptions.collapsedVariantlets a flow choosewithLabelAndControls,withLabel, orhiddenLabelfor its compact presentation. UsewithLabelwhen the surrounding flow owns Back/Continue, orhiddenLabelwhen surrounding UI owns both the current-step heading and navigation and only a bare progress track is needed. The default preserves both label and controls, its controls requireonStepClick, and every step keeps its name in the accessible sequence at any width. (#5659) -
Stepper's
horizontalOptions.minimumStepWidthconfigures the per-step width at which a horizontal Stepper collapses. Numbers are interpreted as pixels and strings accept CSS lengths such as7rem,calc(6rem + 8px), and custom properties. The browser resolves string units through an invisible measurement element, and changes to the resolved value update the compact layout. Omitting the option preserves the existing 112px threshold. (#5659) -
Stepper: add
astryx-step-labelandastryx-step-descriptiontheme targets. (#5728) Both text parts declare their own typography and color, so themes cannot reach them through thesteptarget by inheritance. The new targets apply in both indicator positions and reflectprogressandstatus.step-labelalso reflectsdisabled, because the label owns Stepper's disabled text paint.step-descriptiondoes not. The new targets change no default style. -
Stepper collapses itself in narrow containers instead of leaving each consumer to hand-roll a fallback: a horizontal stepper measures its own width and, once a step has under
horizontalOptions.minimumStepWidth(112px by default), drops the labels to a bare track and uses the configuredcollapsedVariantbeneath it. The breakpoint follows the step count rather than the viewport. Bothseparatedandon-trackleave their compact track presentational; navigation moves to named prev/next controls when configured and whenonStepClickis set. On-track indicators stay on the rail without repeating the active indicator beside the compact label. The full sequence stays intact for screen readers throughout. (#5659) [fix] Step labels hold to a single line and ellipsize rather than wrapping and breaking mid-word, so a row of horizontal steps keeps one height and the track under it stays straight. The full label is still carried in the step's accessible name.[fix] The gap between connector segments is now
--spacing-1, matching the connector's own thickness, so the track reads as one dashed line at any theme scale. -
Add semantic Table row statuses while restoring custom-marker compatibility. Named custom icons keep their released Icon color mapping; raw CSS custom icons now use the caller's paint as required by the current contract. Canary users relying on implicit glyphs should switch from
colortostatus. (#5832) -
TabList: add an
isFullBleedprop so a tab bar can bleed out to its container's inline content edges instead of requiring hand-written negative-margin CSS (#2622). Like Divider'sisFullBleed, it cancels the nearest padded Layout container's--container-padding-inline-*custom properties with negative margins; the inner strip pads back by the amount the bleed exceeds a tab stop's own padding so edge labels remain aligned to the content inset. It is inline-only: TabList owns the inline full bleed, and the container owns the block-end dock. For that, LayoutHeader gains apaddingBlockEndper-edge override in Section's existing spelling —paddingBlockEnd={0}docks the header's last child on its bottom edge so a tab strip's underline meetshasDividerat any header padding. Thedetail-pagetemplate now uses both props, aligns its ghost panel toggle with the container inset, and no longer carries any hand-written tab-row CSS. -
Add
nativePickerto TimeInput so coarse pointers use the browser/OS time picker by default, withalwaysandneveroverrides. Seconds and custom increments retain Astryx's typed field. (#5811)
-
Keep AppShell's section top bar solid in auto-height mode while content scrolls beneath it. (#5873)
-
Extend attached field-status backgrounds behind the lower half of their controls so rounded and pill-shaped inputs connect without visible gaps while the control remains visually above and receives pointer input across the overlap. (#5769)
-
BottomSheet now keeps the iOS Safari browser-bar edge consistent with the sheet surface for both modal and non-modal presentations. (#5373)
-
Keep loading-button spinners at full contrast while interaction is blocked, and suppress pressed feedback for disabled and loading buttons. (#5627)
-
Carousel: mirror the single-edge fade gradients under RTL so the mask fades the physical edge that actually hides content (overflowStart/overflowEnd are logical edges, the gradients were always physical left/right) (#5586)
-
ChatComposerInput no longer discards a pending draft when you click the composer's padding and press ArrowUp. Focusing a contentEditable collapses the caret to the start of the draft, which is the one position where ArrowUp means "recall history", so the first ArrowUp after that click replaced what you had typed. The composer now places the caret after the draft when it focuses itself — clicking the space after the text means "put me there" — so ArrowUp moves the caret with a draft present and still recalls history when the composer is empty. Multi-line caret navigation is unchanged. (#6051)
-
ChatComposer: add a keyboard-only focus ring around the composer body when its editor receives focus (#5648) The ring uses the shared theme focus tokens and does not appear for pointer focus or when an internal action button owns focus.
-
Chat/useChatStreamScroll: an upward scroll releases auto-follow in both motion modes, and only the reader can release it. While following, the hook owns the container's position: it disables CSS scroll anchoring on the scroll element, so the only move the browser makes on its own is the resize clamp onto the bottom, and any other upward move is read as the reader. A wheel or drag a nested scroller consumes, or a block collapsing above the viewport, no longer touches the lock either way; unlocked, anchoring is restored. The wheel and touch listeners are gone.
jumpToBottomalso cancels the spring's pending frame, so animation loops cannot stack. (#5662, #5663) -
ChatToolCalls now announces pending, running, complete, and failed statuses to assistive technology, including expandable rows and collapsed tool-call groups. (#5666)
-
ChatComposerInput: ArrowUp/Down only recall message history at the text boundaries, so the caret can move between lines of a multi-line draft (#4284)
-
CheckIndicator: start the docsite properties preview in the checked state (#5972) Seeds a
checkedplayground default so the properties-tab preview shows a visible indicator on first load instead of an empty stage. -
Collapsible's trigger label now fills the row instead of hugging its own content, so a composed trigger can put something at the far edge next to the chevron. The trigger is aspace-betweenflex row, but its label span had noflex-grow— so the free space collected between the label and the chevron, and a trigger built as<HStack>with a right-hand element (a date, a count, a status) had that element parked against the label with a gap after it, unable to reach the edge thatspace-betweenimplies.flexGrow: 1on the label is the whole change. For a plain text trigger nothing moves: the label was already flush to the start edge and the chevron to the end, and the box that grew is one the text does not fill. The flex floor is deliberately left atauto, so no label can now be squeezed narrower than its own content and start overlapping the chevron. (#5933) -
DropdownMenuRadioItem: add playground wrapper and wire wrapper selection state for docsite preview (#5917) Wraps DropdownMenuRadioItem in DropdownMenuRadioGroup wrapper and keeps the wrapper's selection independent from the item's value knob, so aria-checked stays false until the item is activated and updates on click.
-
Keep DropdownMenu and submenu flyouts inside the viewport with safe inline gutters and viewport-aware height limits. Only overflowing menus become internal scroll containers, while
menuWidthkeeps its existing minimum-width behavior up to the available space. (#5395) [feat] Add an opt-inpresentationprop for data-driven DropdownMenu instances so products can render the same actions as an anchored popover or a modal bottom sheet according to their own responsive input policy. -
FieldLabel: a field's description now sits flush under its label without breaking existing label layout overrides. (#5673) A label and its description are one block of text, but nothing in
FieldLabelsaid so. It returned a fragment, leaving the<label>and the description<span>as bare siblings of whatever column happened to hold them — so the space between them was set by that parent'sgap, the same declaration that separates the label group from the control below it. No caller could close the pair without also pulling the control up against the description, and each had picked its own value.Measured in Chromium as
description.top - label.bottom:| | label → description | description → control | | ------------------------- | ------------------- | ----------------------------------- | |
Field,TextInput| 4px → 0px | 4px → 4px | |CheckboxInput,Switch| 2px → 0px | n/a — control sits beside the label |The label and description now share a wrapper of their own, so the space between them is theirs to set rather than a side effect of the caller's column. Only the pair closes up: the description → control gap is unchanged, so fields keep their existing rhythm.
CheckboxInputandSwitcheach carried a 2px label wrapper to do this job locally, which the shared wrapper makes redundant, so all three callers now agree instead of each choosing a value.A hidden label group takes
display: contents, so the wrapper box leaves the caller's layout entirely and the sr-only label and description stay out of flow exactly as they were — a hidden label still costs no space and draws no gap.This is one change in
FieldLabelrather than a change across the ~20 input components, because every input reaches its label throughField. -
useFocusTrap only restores focus when focus actually entered the trap while it was active. (#5651)
useFocusTrapcaptureddocument.activeElementon activation and restored focus to it on deactivation whenever focus would otherwise be lost to<body>. For popups that deliberately keep DOM focus on their trigger — a Typeahead or PowerSearch listbox opened withrole: "none"andhasAutoFocus: false— the trap never receives focus, so the restore fired on outside-click dismissal and re-focused the anchor input. Because the input was then already focused, clicking it again fired nofocusevent andhasEntriesOnFocuscould not reopen the menu — the control was stuck until a second outside click.The restore effect now tracks whether focus entered the trap container at any point while it was active (via a
focusinlistener). If focus never entered, the restore is skipped entirely. Popups that do take focus — Dialog, DropdownMenu, a Typeahead option click — are unaffected. -
Core: track keyboard and pointer modality once per document instead of initializing global listeners from every consuming component. (#5881)
-
LayoutHeader: add playground wrapper and default children for docsite preview (#5918) Prevents the properties-tab preview on the docsite from rendering an empty stage by wrapping LayoutHeader inside a Layout scaffold with representative header text.
-
LayoutPanel: add playground wrapper and default children for docsite preview (#5919) Prevents the properties-tab preview on the docsite from rendering an empty stage by wrapping LayoutPanel inside a Layout scaffold with representative panel content in start slot.
-
Streamed Markdown no longer goes blank when the line still arriving contains an escaped pipe. A
\|is literal text, not a table-cell delimiter, so a line carrying only escaped pipes is ordinary prose and renders as it streams instead of being held back as an unfinished table header. Genuine partial table syntax is still suppressed, and incremental parsing stays bounded to the stream tail. (#6051) -
Popover layers now cap explicit widths and match-trigger sizing to the available viewport with alignment-aware token safe-area gutters, preserving trigger alignment while keeping the painted surface at least one spacing token from both viewport edges. Long content scrolls inside the layer instead of forcing page overflow on narrow viewports. Repeated resize and content-change signals coalesce overflow measurement to once per animation frame. Pointer-activated dialog popovers focus the labeled dialog container so the first action does not appear preselected, while keyboard activation still focuses the first content control. Read-only content uses the same container target without revealing the fallback close button, while preserving Tab access to that fallback escape control. (#5373)
-
Reuse
DateRangeInputfor PowerSearch date-range values so endpoint selection always emits an ordered range. (#6004) -
useResizable: percentage configuration with an explicit basis (AST-010) Implements the accepted AST-010 contract. Percentages configure a pixel size; they never create a second, responsive sizing mode.
-
ResizeHandle: a drag survives the cursor crossing an embedded frame. (#5297) The handle listened for
pointermove/pointeruponwindowwithout taking pointer capture, so the browser hit-tested every later event — and the moment the cursor entered an<iframe>inside the resizable region the events went to the guest document instead. Measured in Chromium, the host received 0 of 25 pointermoves once the cursor was over the frame, the panel stopped tracking, and thepointerupwas never heard: the handle stayed armed withdata-resizingset and the body cursor/user-selectoverrides stuck. The drag now takes pointer capture on the grab zone onpointerdown, so the whole gesture is delivered there whatever is underneath, and the move/up/cancel handlers sit on that element rather than onwindow(the same shape as Slider and BottomSheet). -
Breadcrumbs mirrors its built-in slash separator in right-to-left layouts (#5365) Fixes #5364.
-
sharedResizeObserver: independent subscriptions per element (#5817) The module held one callback per element —
callbacks.set(element, callback)overwrote. A second hook observing the same node silently replaced the first, and either one callingunobserveResize(element)blinded the other.Two hooks on one element is ordinary rather than exotic: a
TabListroot, auseOverflowcontainer and auseTruncationtarget are all nodes another hook may reasonably watch.observeResizenow returns an unsubscribe that removes only its own registration, and every caller in the package uses it.unobserveResize(element, callback)does the same by hand; the callback-lessunobserveResize(element)still drops every callback on the element and stays for a caller that owns its element outright.Dispatch snapshots the callback keys, so a callback may unsubscribe while the batch is running without skipping its neighbour.
Prerequisite for AST-010 §Implementation-requirements 9, kept separate so it is reviewable on its own. No component behaviour changes: 8534 core tests pass, and the five observer regressions fail against the old module.
-
Spinner: a narrow flex host no longer compresses the box and clips the ring (#5484) The spinner's box carried
overflow: hiddenfrom the canvas ring it no longer draws. It clipped nothing — the painted circle is inscribed in the box, so hiding or showing the overflow renders the same pixels at every size and shade — but a flex item whose overflow is notvisiblehas an automatic minimum size of zero. That left the box with no floor: a flex host narrower than the spinner compressed it while the ring kept drawing at the size its own attributes ask for, and the clip then cut the ring off at the box edge, silently, because a sliced ring still spins.Ordinary layouts reached it. A
mdspinner beside a label in a 140px row rendered a 16px box around a 20px ring; anlgspinner next to aflex: 1 0 100pxsibling lost half of its ring. The clip is gone and the box isflex-shrink: 0, so the box and the ring stay one measurement and a spinner that does not fit overflows its host visibly instead. Nothing moves for a spinner whose host already fitted it. -
Spinner: the drawn frame follows a themed
--spinner-diameter, so a themed ring is no longer clipped or off-centre. (#5214)--spinner-diameterand--spinner-stroke-widthset the ring in CSS, and the box the ring sits in is composed from those same two vars — but the<svg>was sized and given itsviewBoxin JS, from the size's own constants. Theming the diameter therefore left the frame behind: the svg stayed at its default while the box shrank around it, and an overflowing grid item aligns to start rather than centre. Measured in Chromium across the four sizes, a themed ring rendered 1.5-3.3px off-centre with its far edge cropped.The svg is now sized in CSS from
--_spinner-box-size— the same composed var the span is sized from — with noviewBox, so one user unit is one pixel and the frame moves with the box. (Not a percentage: the span is a grid whose area is not always definite in both axes, and an unresolved percentage height on an SVG falls back to the replaced-element default of 150px.) The pxwidth/heightattributes remain as the no-stylesheet fallback, asrandstroke-widthalready were. Both circles centre oncx/cy="50%", and the arc's twelve-o'clock offset is a CSS rotation about the shape's own box rather than an SVG transform about a centre in user units.No change to the default render at any size — same box, ring, stroke and sweep, verified against a build of
main. What changes is that the documented claim "the rendered box … follows automatically" is now true. -
Table's sortable header button now follows its column's
align, so analign: 'end'oralign: 'center'column no longer gets a start-hugging header label sitting above right-aligned figures. Sorting wraps the header in a full-width flex button, which thetextAlignthatalignsets on the cell cannot position; the alignment is now carried onto the button's main axis with a flow-relativejustify-content, so it keeps mirroring under RTL. (#5928) -
Route table-row outcomes and completed or failed tool calls through the theme's semantic icon registry. (#5671)
-
themingTargets.test.tsnow discovers component sources at any depth undersrc, not only in a top-level directory. (#5784) Sources nested a level down —Table/plugins/<name>/— were silently exempt from the guard, which is the same drift #3741 was filed to prevent. Nothing was failing (no nested source rendered athemeProps()class before this release), so this closes the hole rather than fixing a live break: the guard goes from 294 to 302 assertions. -
Timestamp relative and compact-relative labels now follow the active provider locale, including locale-specific plural rules and word order. (#5859)
-
Toast: the card's shadow is no longer clipped away. (#5547) Each toast's grid row used
overflow: hiddenthroughout its lifetime. The clip is load-bearing while the row opens and closes — it makes the toast read as folding into the stack — but at rest it hugs the card's border box with zero slack on every side and cuts off every shadow the card casts. Astryx's own--shadow-medwas declared and invisible: against a white page, every sampled pixel below a stock toast was pure white.The row now keeps its cross-engine
overflow: hiddenboundary during entry and exit, and releases it tooverflow: visibleonly after the opening transition settles. Dismissal restores the clip synchronously. The wrapper keeps its ordinary pointer boundary, so a second click while the toast is still visible is absorbed by the toast rather than falling through to an obscured control underneath.This avoids
overflow-clip-margin, which WebKit 26.5 does not support, while preserving the exact paint boundary the exit shipped with before this fix.Settled state is held on the mounted row rather than in a set of toast ids on the viewport, so it cannot outlive the row it describes. A row leaves the DOM by more paths than dismissal —
maxVisibleevicts the oldest when a newer toast arrives, and auniqueIDoverwrite swaps a new entry into a replaced toast's place — and on neither path does anything on the dismissal path run. An evicted toast that resurfaces once the stack drains therefore mounts clipped and runs its own entry transition, instead of releasing the clip over a row that is still opening.One further lifecycle guard: only the row's own transition is read, since
grid-template-rowsis not private to the wrapper andtransitionendbubbles from any descendant animating its own grid. Reading a descendant's event as the row's own releases the clip before the row has finished opening, and during exit it unmounts the toast mid-collapse.Below a settled stock toast on a white page, sampling straight down from the card's bottom border box:
255,255,255at every offset before; after, the shadow paints223at +0px and fades237 → 243 → 247 → 250 → 253 → 254, reaching white again at +12px. During exit the row clips again, so anything outside the shrinking row is neither painted nor hit-testable — while the wrapper itself keeps the ordinary pointer boundary it has always had, and still absorbs a click aimed at a toast that is still on screen. -
Reset Toast swipe state when a second touch begins so native pinch and two-finger gestures remain available, and clear transient drag styles before a successful swipe dismissal. (#5676)
-
ToastViewportresets the UA popoverwidth, so an end-positioned toast lands on the end edge again. (#5822) The viewport reaches the top layer throughpopover="manual", and the UA stylesheet gives every popoverwidth: fit-content. Since the placement rework the viewport is positioned by spanning the inline axis and aligning within itself, and a shrink-wrapped box cannot span — both inset edges cannot be honoured, so the box resolves against the start edge andalign-items: flex-endaligns the toast to the right of a box sitting on the left. Measured in Chromium at 1200px: a 438px viewport at x=0, with the defaultbottomEndtoast at x=19 instead of x=781. The reset block already neutralisedinset,margin,borderandbackground;widthbelongs with them. -
Tokenizer: render and interact in the docsite properties preview (#5982) Seeds playground defaults for the required
valuearray so the properties-tab preview shows a labeled field with tokens on first load instead of the missing-required-props placeholder, and wires the preview'sonChangebridge back to the controlledvalueso removing a token updates the field. -
TreeList: respect consumer
onKeyDownpreventDefaultcancellation for APG tree keyboard navigation (#5606)TreeListpreviously processed built-in APG keyboard navigation on the inner<ul role="tree">before consumeronKeyDownran on the root<div>, preventing consumerevent.preventDefault()from suppressing built-in arrow navigation.Root
onKeyDownnow invokes consumeronKeyDownon the root container first and checksevent.defaultPreventedbefore handling internal tree navigation for keydown events originating inside the<ul role="tree">. Callingevent.preventDefault()inonKeyDownnow successfully cancels built-in navigation and leaves focus and roving tabindex unchanged while preserving root handler target contracts. -
Typeahead: the field keeps its width when a value is selected, and the value stays out of the end controls (#5560) Two halves of one promise from the input-field family contract (
docs/families/input-fields.md): FR1, a field's available width does not change because its value did; and FR2, a visible end affordance does not have field content painted under it.FR1 — the input keeps its place. Every other field in the family gets a stable width for free: the
<input>stays in flow, and the field is as wide as the input's own intrinsic width. Typeahead took the input out of flow and zeroed its width while a token showed, so the field was left measuring the token. In any shrink-to-fit parent it snapped to the value's length. Block-level parents hid it, because they fill their container whatever their content is, which is why no story caught it. The input now keeps its place in the row and its own width — it is only made invisible and inert — and the token is painted over that space rather than beside it. In flow the token would add its own width instead, which is the same value-dependent sizing from the other direction: a long value would grow the field.FR2 — the value is bounded by a content lane. The input and the token share a content lane: an ordinary flex item,
flex: 1withmin-width: 0, that ends exactly where the end lane begins. That is TextInput's own arrangement — the lane takes the free space so the end controls sit in the corner, and yields all of it when the field is narrow, so a narrow field cannot overflow. The token is anchored at both of the lane's inline edges, so a long value ellipsizes at the lane's edge instead of reaching the controls. Positioned against the whole field instead, as the first revision of this change did, it had no idea where those controls start.Measured in Chromium. Widths are the field's border box, field in a
max-contentparent,Field.widthotherwise unset:| | empty | short value | long value | | --------------------------------- | ----- | ----------- | ------------ | | TextInput (family baseline) | 199px | 227px | 227px | | Typeahead before | 199px | 54.7px | 224.09px | | Typeahead after | 199px | 223px | 223px | | Typeahead in
InputGroup, before | 397px | 252.7px | 422.09px | | Typeahead inInputGroup, after | 397px | 421px | 421px |The 24px between the empty and valued columns is the clear button entering the row — ordinary for any field whose clear is conditional, it does not vary with the value, and TextInput's is 28px.
Overlap is the value's trailing edge past the clear button's leading edge; escape is how far the value reaches past the field's border. The middle column is this change's own first revision, which fixed the width and made the overlap worse:
| field, long value | overlap on main | first revision | now | | ----------------- | --------------- | -------------- | --------------- | | shrink-to-fit | 12px | 28.09px | none, 7px clear | | in
InputGroup| 12px | 33px | none, 7px clear | | 220px | 12px | 31.09px | none, 7px clear | | 180px | 12px | 33px | none, 7px clear | | 140px | 12px | 33px | none, 7px clear | | escape, 140–220px | none | up to 4px | none |No new API and no constants. An earlier revision floored the field with a
--typeahead-min-widthpublic var defaulting to 200px, which review rightly rejected: it was a second sizing contract beside the documentedField.widthprop, it was hand-derived (the empty field measures 199, so the floor overshot by 1),InputGroupcancelled it, and it could not helpTokenizer. Nothing here states a width; the lane'smin-width: 0is the opposite of a floor.Tokenizeris not fixed here. It shares the family promise and breaks it — 199px empty to 114.7px with one token, in the same probe — but by a different mechanism: its tokens are in flow and wrap, and its input deliberately becomes a 40px continuation lane after them, so what a wrapping multi-value field's width should be is a design question rather than this bug. Its numbers are identical before and after this change. -
Typeahead, Tokenizer: the busy indicator is a Spinner in the field's end lane, and the input keeps its text out from under it (#5555) Three defects in one block. The indicator a search painted was
<Icon icon="clock">— a static glyph, in a family where every other input paints busy with aSpinner, and whereclockotherwise means time. It was an in-flow item at the row's inline end, which is where each field independently parks its clear button, so the two landed on each other: 17×20px of overlap in Typeahead and 19×20px in Tokenizer. The overlap is visual, not functional — the clear button is positioned, so it paints above the in-flow indicator and stays clickable across the whole covered band. And the combobox never carriedaria-busy, unlike every sibling input.The base engine now reports the busy state to the field, which paints it in the one inline-end lane it already owns beside its clear button and end content, and sets
aria-busyon the input. A caller usingBaseTypeaheaddirectly is unaffected: it still renders its own visible, named "Loading" status, now a Spinner rather than the clock.Typeahead puts both controls in flow, as ordinary flex siblings of the input, exactly as TextInput does with its own spinner and clear button — an in-flow box takes up room, so the input cannot run under it and there is nothing to measure. Getting there meant dropping
flex-wrap: wrapfrom its wrapper, which the shared field base does not set and TextInput does not use: this field holds at most one token, so there is no second row to wrap to, and wrapping is what made an in-flow lane impossible, since flex moves an item to a new line rather than shrinking it. Measured in Chromium: withflex-wraprestored and a token too wide to share the row, the end controls drop to a second row and a 280px field grows from 32px to 46px tall. Unwrapped, a long value ellipsizes in the token instead.Tokenizer's own pre-existing case of the overlap closes with it: at 280px with a token and no search running, its clear button covered 20px of the input's content box, and covers none now.
Tokenizer keeps a measured lane, because it cannot use the in-flow shape: its lane stays pinned to the field's first row while tokens wrap below it, so it has to be out of flow, and an out-of-flow box reserves nothing. Its width is measured with
offsetWidthrather thangetBoundingClientRect(). The rect is in viewport space — it carries every CSS transform above the element — while the padding it feeds is in local space, so mixing them broke under any transform: measured in Chromium,scale(.5)reserved half of what was needed and put the query back under the controls by 22.83px, andscale(2)left the caret in a 202.69px gap.offsetWidthis the untransformed border-box width and reports the same number at every scale.The measurement reaches CSS as a custom property written to the field wrapper, never as React state, so a lane that grows or shrinks repaints without re-rendering the field. Held in state it cost a second commit every time the lane changed size — once as the spinner arrived and once as it left — which doubled the field's commits across a search for a value no JavaScript reads. The observation is shared too, through the same
observeResizesingletonuseTruncationuses, so a page of fields costs one callback per frame rather than one observer each. The property is--_tokenizer-end-lane-width: private and component-named, like every other runtime layout var in the package, and never something a theme writes.The busy indicator now appears in each field's documented anatomy, delegating its theming to
component:Spinnerrather than gaining a target of its own — the dispositionTextArea,CheckboxListandCommandPalettealready use for the same part.
- Keep Tooltip refs stable across rerenders (#5951)
- Markdown streaming bounds four incremental-parse operations by the mutable tail: splitting, fence/boundary detection, link-definition collection, and block re-parsing no longer grow with the already-settled document. The parser contract is unchanged: each call returns a fresh, never-mutated snapshot, and replacing already-settled text still re-parses the document. Two costs intentionally remain proportional to the whole input on each call because that contract requires them — the settled-prefix comparison that detects a replaced document, and the pointer-per-block copy behind each returned snapshot. (#5515)
- Typeahead: skip the loading cycle for synchronous bootstrap sources (#5955)
BaseTypeaheadnow applies an array returned bySearchSource.bootstrap()immediately instead of entering and leaving the asynchronous loading state. An empty synchronous bootstrap becomes a render no-op, while synchronous entries still open normally. Switching from an in-flight search to a synchronous bootstrap also clears the superseded search's loading state. Promise-backed bootstrap sources keep the existing loading behavior.
- Grid, Stack, HStack, VStack, GridSpan, and StackItem: seed example content via playground defaults (and, for the two sub-components, a real parent wrapper) so the docsite properties-tab preview renders a working component instead of an empty stage. (#5892, #5893, #5894, #5898, #5899, #5900)
- The namespaced-icon rationale and the add-a-semantic-icon intro in the icons guide, and the
SideNavItemactionsprop description, now use a comma and a colon in place of prose em dashes. Meaning unchanged. (#5647) - The Popover presentation best practice and the Banner collapsible best practice now use a straight apostrophe instead of a curly one, so the strings match the rest of the doc copy. Meaning unchanged. (#5772)
- The Spinner CSS-variable and size descriptions, and the
useTableGroupedRowsdescription, now use colons and semicolons in place of prose em dashes. Meaning unchanged. (#5597) - The Stepper progress bar anatomy description now sets its nested aside in parentheses instead of paired em dashes, so the sentence about multi-segment spans reads plainly in the CLI and doc site. Meaning unchanged. (#5691)
-
Core's postinstall no longer hand-mirrors the setup contract.
packages/core/scripts/agent-doc-state.mjsis now GENERATED byte-for-byte from the CLI's dependency-free leafpackages/cli/foundation/agent-docs/agent-doc-state.mjs, andpnpm check:setup-contract— wired intocheck:repo— fails the build when the two differ. (#4162) The previous guard compared two hand-edited constant lists. That caught a new agent-doc path or a new marker, and nothing else: the predicate itself, and theshouldNudgedecision matrix duplicated in both postinstall scripts, could still drift and leave layer 1 and layer 2 disagreeing about "is this project set up?" with the test green.shouldNudgeand the nudge string move into the contract as well, so all four things — paths, markers, predicate, decision — now have one definition and one place to edit.Behavior is unchanged, and verified rather than assumed: the nudge text is byte-identical, legacy
<!-- XDS:START -->blocks still count as set up, all six agent-doc locations are still detected, and both scripts still exit 0 on every path including failure. Core loads its copy with a dynamic import, so a packaging mistake degrades to "no nudge" instead of throwing out of module evaluation and failing a consumer's install.check:setup-contractalso fails if core stops listing the generated file infiles, so it cannot go missing in the first place. -
minSize/maxSizejoindefaultSizein one vocabulary: a non-negative finite number, an exactNpx, an exactN%from 0–100, Table's existingpixel(value), orpercent(value, {min: pixel(value)})/percent(value, {max: pixel(value)})for a percentage with exactly one pixel floor or ceiling.percent()requires its options;'40%'remains the only unbounded percentage spelling.minSizePx/maxSizePxremain deprecated aliases, each an exact mutually-exclusive TypeScript union with its replacement; if untyped code supplies both, the unified prop wins and development names the ignored alias. -
containerRef(caller-owned) changes only what a percentage is a share of: that element's content-box size on the active axis,directionselecting inline or block. Omitted, percentages keep the released one-timewindow.innerWidthresolution with its 1200px server fallback. -
A percentage default resolves once into a pixel selection, applying its optional structured floor or ceiling exactly once. Percentage bounds re-resolve with their basis, apply that one pixel bound, and clamp the selection — they never rescale it. A basis change is not a user interaction: it fires no
onSizeChangeand persists only resolved pixels. -
Everything else stays pixels, exactly as released: pointer, keyboard, snaps, collapse/expand, persistence, callbacks, and
resize(number).resize('50%')remains a type error, andresize(NaN),resize(Infinity)or a negative now warn and keep the last legal size instead of poisoning state. -
Invalid configuration repairs deterministically — 250px for a default, 50px for a minimum, unbounded for a maximum — identically in development and production, warning only in development. Explicit
maxSize: InfinityandmaxSizePx: Infinitykeep the released unbounded behavior. The deprecated aliases retain their released exact atomic-string behavior for untyped callers. An inverted pair warns and the maximum wins, preserving the released clamp order.The structured API follows Table's existing shape rather than parsing CSS expressions:
Resizable/utilsis a server-safe subpath that re-exports the exact samepixel()binding andPixelWidthtype asTable/utils, alongside Resizable'spercent()and types.pixel(value)is the canonical structured static size; raw numbers and exactNpxremain compatible.proportional()remains Table-only because it describes sibling weight, not a literal percentage of one measured basis. CSSmin()/max()strings are deliberately unsupported.The defect this closes: a percentage ceiling could previously only be written in CSS, and CSS stops the paint but not the state.
ResizeHandlepublishes the hook's size asaria-valuenow, so the separator announced a width the panel did not have — measured at 899.5 against a 434px panel. Bounds now clamp the state, so paint, persistence and ARIA describe one geometry.ResizeHandlealso warns in development when itsdirectiondisagrees with its region's, which previously failed silently. Existing vertical panels must passdirection: 'vertical'touseResizableas well asdirection="vertical"to the handle.The container basis follows the ref, not the element it first pointed at: replacing the element behind the same
containerRefre-resolves against the replacement, and the element left behind is unobserved. A container that is not laid out yet — unmounted,display:none, detached — measures 0, which is not a measurement: percentages hold the documented temporary 1200px basis until it is real, and nothing is written toautoSaveIdstorage from it. Once the first real basis resolves, the default is committed as a pixel selection with its initial clamp included; a 321px default clamped to 200px therefore stays 200px when the container later grows instead of reviving the raw default.A gesture that is cancelled rather than completed —
pointercancel, a lost pointer capture, a handle unmounted mid-drag — releases the basis it froze through a new optional_onResizeCancelonResizableProps. It is not a resize end (a cancelled drag deliberately signals none, per #5297), but it is the end of the gesture._onResizeCanceland_directionare both optional:ResizablePropsis exported, so an object literal that satisfied the released type still compiles.Not in scope, per the spec: SideNav's simplified
defaultWidth/minWidth/maxWidthstays pixel-only.A pixel-only configuration keeps its single render pass even when a
containerRefis supplied. With no percentage anywhere there is no basis to observe or ref identity to follow, so the pixel selection is made at mount; only a basis-dependent configuration with a supplied container defers until that measurement exists.
- Add popover, bottom-sheet, and adaptive presentation options to Selector and MultiSelector, with docsite examples for both bottom-sheet variants. (#5395)
- Reuse Neutral-owned local tokens for semantic status fills across badges, status dots, step indicators, and progress bars. (#5854)
- Add Neutral's reproducible, theme-owned OKLCH palette without changing its runtime token mappings. The request, receipt, generated result, and CLI template artifacts are committed together for review. (#5987)
- Add the opt-in theme-local token contract for maintained theme families. (#5844)
-
Add structured accessibility requirements and theme coverage support to component documentation. (#5713)
-
Add the checkout wizard page template. (#5660)
-
CLI: record every command run and hand it to a function you supply. (#4812)
// astryx.config.mjs export default { debug: event => appendFileSync('runs.ndjson', JSON.stringify(event) + '\n'), };
That is the whole feature. Setting
debugopts in; the function receives oneDebugEventper invocation and decides what happens to it. The CLI stores nothing.Each event carries the command, its arguments and flags (with their Commander source, so you can tell a typed flag from a default), the outcome, exit code, duration, error code, a coarse environment snapshot including which coding agent invoked the CLI, and — under
output— everything the command printed to stdout and stderr. That last part is the answer the user actually got, which is what makes a record useful for improving the output rather than just counting invocations. Streams are captured separately with their true byte counts, and truncated past 32KB per stream so a command that prints a whole file does not dominate the record. Coverage is the point: handled errors, parse errors,--help, rejected invocations, uncaught throws, and Ctrl-C all report. The event is delivered from aprocess.on('exit')listener because the CLI's error path exits synchronously — anything hooked to normal completion would report successes and almost no failures — and the handler is loaded before parsing, because parse errors and--helpshort-circuit before any hook runs.eventis a published contract:DebugEventis exported from@astryxdesign/cli/debugwith a sealed zod validator,parseDebugEvent, drift-locked to the type so the recorder cannot add a field without publishing it.schemaVersionis a literal, so widening it turns every consumer's branch into a compile error rather than a silent misread.The handler runs synchronously at exit — a returned promise is never awaited, so network delivery from inside it will not work; write a file or spawn a detached child. It receives a copy, so a handler that throws, or mutates what it was given, can neither fail the command nor affect anything else. Follow-up hardening keeps a handler from replacing the command's exit code and routes handler writes away from stdout so a
--jsonenvelope stays valid. (#5929)Nothing changes for a project that has not set
debug. Startup is unmoved: the environment probe is deferred to delivery rather than run inbegin, because its firstIntlcall initialises ICU and that alone was ~9% of the CLI's startup for everyone. Nor does the config run:Project.loadevaluates the config module and loads its integrations, which most commands never did, so the file is read as text first and only loaded when the worddebugappears in it. Measured across eight commands, no command evaluates a config that did not already.Values are scrubbed before delivery: home paths, absolute paths inside stack frames, email addresses, URL credentials, credential-shaped strings, and the value half of a sensitive assignment wherever it appears — including where an error message, a stack frame and the captured stderr all quote the flag that was rejected. Sensitive names are matched with
-and_stripped, so--api-key,--api_keyand--apiKeyare one rule;key,patandpware matched whole so they do not take--keyboardand--pathwith them.argvis scrubbed pairwise, so--token hunter2loses its value the way--token=hunter2does. Oversized values are clamped.Hardened against three adversarial chaos runs and an independent review, each finding mutation-tested before its fix landed: a
__proto__key silently reparenting the record that carried it, one oversized value discarding the whole event, an exit that bypassedcliErrorbeing indistinguishable from a classified failure, a signal-terminated run leaving no record at all, a sensitive--flag=valuescrubbed inargvbut written back out in full through the error message and captured stderr that quote it, absolute paths surviving inside stack frames — where nothing puts whitespace in front of them — and taking the machine's username with them, a graceful Ctrl-C recorded as a failure with an exit code the process never returned,--api-keyand--token valuereaching a handler intact, and the two startup costs above.One change reaches beyond this feature:
installJsonShimnow shims commands as they join the command tree rather than in a single walk at startup, so a command registered later can no longer silently fall out of the--jsoncontract. -
CLI:
astryx init --jsonnow works. It emits the install receipt as a standard envelope —init.runwith the mode, the features that ran, the agent-doc files written, any softdocsError, and the template outcome, orinit.removefor--remove-agents. Human output is suppressed so stdout carries only the envelope, and the exit code is unchanged from human mode. (#4812)initwas the last side-effecting command still refused by the--jsongate. That gate existed to stop a command writing half a project and only then reporting that--jsonwas unsupported; sinceinit()already returned a typed receipt, the fix was to emit it rather than to keep refusing.themeandlayoutremain off the allowlist, but both are command groups with no output of their own. -
Add result and agent-session context to DebugEvent (#5971)
-
Add the dialog wizard page template. (#5798)
-
Let themes add typed Heading visual roles with a safe semantic-level fallback when the owning theme styles are unavailable. (#6026)
-
Add the form wizard page template. (#5664)
-
Add the inline wizard page template. (#5797)
-
An integration can now supply a
debughandler, so installing it turns on its debug logs with no change to the app. Exportdebugfromastryx.integration.*; the app's owndebugstill runs, both get every event, and a handler that throws cannot affect the command. Opt out with{"astryx": {"inheritDebug": false}}. (#5998) -
Mute the low-tone edge of Neutral's dark chromatic palette while preserving its light and neutral ramps. (#6069)
-
Rebuild the
table-pagetemplate as a searchable, filterable, sortable table pattern with filter-aware totals, row detail, a scrolling document masthead, and guidance organized around narrowing, sorting, and communicating filtered state. (#5865) -
TabList: add an
isFullBleedprop so a tab bar can bleed out to its container's inline content edges instead of requiring hand-written negative-margin CSS (#2622). Like Divider'sisFullBleed, it cancels the nearest padded Layout container's--container-padding-inline-*custom properties with negative margins; the inner strip pads back by the amount the bleed exceeds a tab stop's own padding so edge labels remain aligned to the content inset. It is inline-only: TabList owns the inline full bleed, and the container owns the block-end dock. For that, LayoutHeader gains apaddingBlockEndper-edge override in Section's existing spelling —paddingBlockEnd={0}docks the header's last child on its bottom edge so a tab strip's underline meetshasDividerat any header padding. Thedetail-pagetemplate now uses both props, aligns its ghost panel toggle with the container inset, and no longer carries any hand-written tab-row CSS. -
Add the vertical wizard page template. (#5672)
-
Add the
work-item-detailpage template for task, ticket, issue, story, bug, card, and request detail surfaces. It includes responsive main-content and details-rail layouts, editable metadata, subtasks, attachments, comments, activity, and a narrow-viewport details dialog. (#5926)
-
build: a page that matched one word of the query is no longer offered as a direct match. A page template's keywords include every component its source renders, so
build "actionable warning banner"returnedlogin,contact-formanddocumentation-designat 95 apiece — an exact keyword hit on "banner" alone, plus the coverage garnish, landing exactly on the direct-match threshold. Three pages that are not warnings, presented as the page to start from. Coverage now gates the pages group rather than garnishing its score. Score alone could not carry the gate, soscoreQuerynow reports the coverage it already computed:matchedTerms/queryTermson every search result, with a whole-phrase hit reporting full coverage. A single strong hit and a broad weak one land on the same score, so a caller cannot tell "one of three concepts" from "three of three" without it.Rebased onto current
main, which landed integration search (#5259) and the scorer-level false-direct-match fix (#5614) while this was open. Both aremain's implementations, untouched here — this branch no longer rewritesgatherComponents, so the two regressions that rewrite caused are gone with it: an integration result reports its own package again, and a broken config no longer turns a Corebuttonsearch into an empty success.The other two pieces this branch used to carry now ship separately, as asked: the guidance-tier indexing in #5937 and the thin-kit hint in #5938.
-
A thin
buildkit now says what to try instead of looking empty.build "quantum flux capacitor telemetry"returned one incidental component and the always-on frame list, and said nothing else. An agent reading that does not conclude its wording was wrong — it concludes the package has nothing and falls back on its own memory of what Astryx contains, which is the failurebuildexists to prevent.Below three offerable results the kit carries a
hintnaming the two commands that browse rather than search, and saying plainly that this is keyword matching, not semantic. The threshold counts what SURVIVED the score floors, not what search returned:hasResultsis already true for a query that matched things and then filtered them all out, and that is the case most likely to be misread.hintis structured —{reason, commands}with bare subcommands — not a sentence with commands baked into it. The API cannot know how a project invokes the CLI, and a hardcodedastryx component --listdoes not resolve in a pnpm workspace, where every other command in this output renders aspnpm exec astryx. The renderer formats them throughformatCliCommand, so they are runnable as printed, and a JSON caller gets the parts rather than prose to re-parse.hintis present only when it applies, so a healthy kit is byte-identical to before. The CLI renders it last, as aFEW MATCHESsection listed in the legend's section order, so it is the line the reader leaves with.Split out of #5320 at review request. Public response doc (
build.doc.mjs) and theBuildKitResponsetype both updated. -
The shared CLI blog adapter (
blog.list,blog.detail) cleared its 15-second abort timer as soon asfetchreturned response headers, leaving the later body read unbounded in time, and buffered the entire response before checking the 5 MB size limit, so the limit didn't actually cap how much was read into memory. (#5286) The abort timer now stays active through body consumption. The body is read as a stream where available, checking decoded size after each chunk and aborting the read as soon as it exceeds the limit, instead of buffering the full response first. -
CLI: recorded runs no longer carry a raw agent session id, and the environment snapshot is scrubbed like every other value. (#6051) A
DebugEventclaimedredacted: truewhileenvhad never been through the scrubbing pass, and it stored the rawagentSessionIdbeside its hash. A session id follows one person across every run they make, and a handler may forward these records anywhere — so the record shipped a stable identifier, and an agent name pasted in from the environment went out verbatim, under a flag that said neither had.The contract is now explicit on
DebugEventEnv: no identity, attribution only from positive evidence, and free text scrubbed.env.agentSessionIdis always null — join runs onenv.agentSessionIdHash, which is what the raw value was for. Everything the CLI derives itself (platform, CI provider, locale, the hash) is still recorded verbatim, because a scrubbed snapshot is not worth keeping.redactedis set only on the sealed copy, after every pass has actually run.DebugSchemaVersionwidens to1 | 2and the CLI emits2, so code that switches on it is forced to handle both rather than silently reading a field that no longer means what it did.parseDebugEventis version-aware to match: a v1 record may carry the raw id, a v2 record may not and is rejected if it does.Not a breaking change:
debugand the wholeDebugEventsurface are unreleased — they land in this same release — so no published consumer ever saw the raw identifier. -
A manifest key this CLI does not know no longer discards the whole integration.
astryx.integration.*was parsed with a strict schema, so one unrecognized field failed the parse — and an integration whose manifest fails to parse contributes nothing, taking its components, templates and codemods down with it. Since an integration is published once and installed against many CLI versions, a field added by a newer CLI reached every older consumer as total, silent loss of that package (#5119). Unknown fields are now ignored with anunknown_manifest_keywarning naming them, and the rest of the manifest still applies; a known field of the wrong type is still an error. (#5311 follow-up) -
CLI: a stray lockfile no longer overrides the
packageManageryour project declares. (#6051) Oneyarn installinside a pnpm project leaves ayarn.lockbehind forever. A single lockfile used to outrank thepackageManagerfield, so the CLI answered "yarn" for a project that says pnpm — and printedyarn astryx …in every command it suggested, including the invocation line written into agent docs, where agents copy it.astryx doctorcalled that setup healthy.The declared
packageManagerfield now decides, whatever lockfiles sit beside it. The documented fallbacks are unchanged: with nothing declared, a single lockfile still answers, a committedpnpm-workspace.yaml/.yarnrc.yml/bunfig.tomlstill breaks a multi-lockfile tie, an unbroken tie still resolves to the neutralnpxform with a doctor FAIL, and the runner is still consulted only when the whole walk found nothing.astryx doctornow WARNs when a lockfile contradicts the declaration, names the file, and says what to delete — instead of reporting the project as fine. -
astryx search(andastryx build, which shares its ranking) never surfaced a component whose exact multi-word keyword phrase was searched, if enough other unrelated candidates happened to each contain one of the query's individual words. Searching"table of contents"returned no results forOutline, even thoughOutline.doc.mjsdeclares'table of contents'verbatim as a keyword, becauseTable-related templates each matchedtableandcontentsseparately and their combined per-word score outranked Outline's single exact match. A query that exactly matches a candidate's declared keyword (or name) verbatim is now promoted to a top-tier score, so it always outranks a candidate that only coincidentally contains several of the query's individual words. Single-word queries and queries that don't exactly match a keyword are unaffected.Follow-ups #6001 and #5994 preserve the coverage counts needed by build ranking while keeping them out of the public search result shape.
-
CLI:
searchandbuildnow report how many results MATCHED, not how many were returned. (#6051)matchCounton abuild.kitenvelope, andoutput.resultCounton a recorded run, were both the length of the list after--limithad cut it. A query matching two hundred things and one matching exactly twenty filed the same number, so nothing downstream could tell a capped answer from a complete one — and a thin kit read as "the package has nothing" when it was really "the cap hid the rest".search --jsonnow carriesmatchCountalongsideresults, and the text view saysResults for "x" (2 of 57)when the list was cut short. The payloads themselves are unchanged:resultsis still bounded by--limit, and the kit still surfaces at most 3 pages, 5 blocks, and 6 components. -
Rename five dashboard page template catalog slugs to reusable pattern names, per the naming convention in Contributing Templates:
dashboard-data→dashboard-comparison,dashboard-executive-summary→dashboard-scorecard,dashboard-portfolio→dashboard-composition,dashboard-project-status→dashboard-progress, anddashboard-service-monitoring→dashboard-alert-rail. Each old slug named the data or task rather than the reusable pattern, so it under-served neighbouring requests: the composition-over-time shape is not specific to portfolios, and the alert-rail shape is not specific to service monitoring. The old slugs no longer resolve because catalog lookup is exact-match; use the new current-catalog values above. Thetemplatecommand and machine-readable schema are unchanged. (#5927) Two categories move with their slugs:dashboard-comparisontakesDashboard - Comparison(it previously sharedDashboard - Analyticsverbatim with thedashboardtemplate, so neither owned the keyword) anddashboard-scorecardtakesDashboard - Scorecard. Both values are added to theTemplateCategoryunion; the superseded values stay reserved. Domain vocabulary — portfolio, holdings, monitoring, uptime, executive summary — is untouched in eachdescription, which is where retrieval actually reads it from.Also fixes a typo in the scorecard template's
namefield ("Executive Summary Dashoard"). -
Deduplicate parent-owned theming targets in CLI discovery while preserving each child component's direct documentation. (#5767)
-
Preserve anatomy when loading localized component docs directly (#5761) The validated component-doc loader now applies the same full-overlay fallback as the CLI loader, so omitted localized anatomy inherits the canonical structure while explicit localized anatomy still wins.
-
Package-manager detection: don't let a stray lockfile decide (#5301)
detectPackageManagerchecked lockfiles in a fixed order and returned the first hit, so a directory holding more than one lockfile was resolved by array position.yarn.lockis first in that array, which means a singleyarn installinside a pnpm project silently switches the CLI's answer to yarn — permanently, because the stray lockfile stays on disk.Every command the CLI prints is then wrong, including the invocation line written into the agent-docs block, which agents copy verbatim into their own runs.
An explicit
packageManagerdeclaration is authoritative even when the project also contains one or several lockfiles. Without a declaration, a single lockfile remains decisive. When several lockfiles sit in one directory, the tie is broken only from other evidence the project owns: a committed package-manager config file (pnpm-workspace.yaml,.yarnrc.yml,bunfig.toml). A strayinstalldrops a lockfile; it writes none of those.The runner (
npm_config_user_agent) deliberately does NOT break that tie. An agent handed the wrongyarn astryxline runs the CLI through yarn, so the runner agrees with the mistake and regenerating agent docs writes the wrong line again — the failure reproduces itself. The same holds for an installed binary invoked from that shell. Both now have regressions that start from the wrong line.When nothing project-owned decides it, the CLI does not guess.
detectPackageManagerreturns the neutralnpx, which is correct under every package manager, and the newexplainPackageManagerreportsambiguouswith the tied candidates.astryx doctorturns that into a FAIL naming the directory and the fix — add apackageManagerfield, or delete the lockfile that does not belong. It is the refusalfindConfigPathalready makes for coexisting config files. -
LayoutPanel: add playground wrapper and default children for docsite preview (#5919) Prevents the properties-tab preview on the docsite from rendering an empty stage by wrapping LayoutPanel inside a Layout scaffold with representative panel content in start slot.
-
Preserve canonical anatomy in localized component docs (#5753) Localized component docs now inherit canonical anatomy when they omit it, while explicit localized anatomy still takes precedence.
-
Make the table-filter page template usable on narrow and touch surfaces: View options, the detail panel, the saved-view dialogs and the filter overflow adapt to bottom sheets, the filter and saved-view rows hold one line, and column freezing is dropped where there is too little width to scroll the rest. (#5829)
-
Correct Neutral Banner interaction tints so light mode uses translucent light overlays and dark mode uses translucent dark overlays. (#5936)
-
Use palette-backed red interaction overlays for Neutral destructive buttons, solid dark-palette tone-25 backgrounds (tone 20 for gray), and calmer dark-mode text colors. Use a palette-backed muted blue tint for dark info banners while preserving the existing light-mode non-semantic color mappings. (#6049)
-
Give Neutral segmented controls a roomier inset while preserving their outside height. (#5851)
-
Rename built-in syntax theme identifiers. (#5847)
-
Remap Neutral's semantic, syntax, and categorical color tokens to the reviewed theme-owned palette through named stop references. Keep the maintained CLI template synchronized. (#6034)
-
Keep query-coverage metadata internal to build ranking while preserving it for promoted exact-phrase matches. (#5994)
-
searchindexes a component's usage guidance, one tier below its description. (#5937) A component's best practices are where the reader's vocabulary lives.Bannerdescribes itself as "a persistent message"; only its guidance says "caution", "problems", "form errors". None of those words found it, because guidance was never read — 97 core components ship guidance, and all of it was invisible to search.Measured on the real registry, before and after:
caution,problems,sourcesandattentioneach now return the component whose guidance defines them, and each returned nothing relevant before.Guidance scores 45, below description's 50, so a component that IS the answer still outranks one whose advice merely mentions the term — the ordering that put
ToastbehindCard,DialogandItemon "notification".It sits deliberately BELOW
MIN_TOKEN_SCORE, so it never counts as a matched concept in a multi-word query. That is not a detail: letting it count was measured movingnested menufrom SideNav to List, andexplain why a field is requiredfrom Field to TextInput — a component whose guidance happens to mention the other word displacing the one that is the answer. Breadth is not relevance, the same reasonweakKeywordsare capped. With the floor left at 50, a 28-query sweep shows zero top-result changes and zero regressions, while the single-word gains above are kept. -
Table inbox replies now preserve an unsent body only for the same conversation, preventing text from following changed recipients. (#5934)
- The namespaced-icon rationale and the add-a-semantic-icon intro in the icons guide, and the
SideNavItemactionsprop description, now use a comma and a colon in place of prose em dashes. Meaning unchanged. (#5647) - The description prose of 12 page templates now uses parentheses, commas, and colons in place of em dashes. These strings feed the CLI template list and the doc site, so plain punctuation reads better there. Meaning unchanged. (#5679)
-
Core's postinstall no longer hand-mirrors the setup contract.
packages/core/scripts/agent-doc-state.mjsis now GENERATED byte-for-byte from the CLI's dependency-free leafpackages/cli/foundation/agent-docs/agent-doc-state.mjs, andpnpm check:setup-contract— wired intocheck:repo— fails the build when the two differ. (#4162) The previous guard compared two hand-edited constant lists. That caught a new agent-doc path or a new marker, and nothing else: the predicate itself, and theshouldNudgedecision matrix duplicated in both postinstall scripts, could still drift and leave layer 1 and layer 2 disagreeing about "is this project set up?" with the test green.shouldNudgeand the nudge string move into the contract as well, so all four things — paths, markers, predicate, decision — now have one definition and one place to edit.Behavior is unchanged, and verified rather than assumed: the nudge text is byte-identical, legacy
<!-- XDS:START -->blocks still count as set up, all six agent-doc locations are still detected, and both scripts still exit 0 on every path including failure. Core loads its copy with a dynamic import, so a packaging mistake degrades to "no nudge" instead of throwing out of module evaluation and failing a consumer's install.check:setup-contractalso fails if core stops listing the generated file infiles, so it cannot go missing in the first place.
withAstryx()now resolves an app's own@astryxdesign/*imports to the packages'sourceentries. The scoped webpack rule only governs requests issued from insidenode_modules, so app code resolved the library throughdefaulttodistwhile PostCSS compiled it from source — the two emit disjoint class names and the app rendered unstyled without erroring. (#5932)
- Rename built-in syntax theme identifiers. (#5847)
- Rename built-in syntax theme identifiers. (#5847)
- Rename built-in syntax theme identifiers. (#5847)
- Rename built-in syntax theme identifiers. (#5847)
- Reuse Neutral-owned local tokens for semantic status fills across badges, status dots, step indicators, and progress bars. (#5854)
- Add Neutral's reproducible, theme-owned OKLCH palette without changing its runtime token mappings. The request, receipt, generated result, and CLI template artifacts are committed together for review. (#5987)
- Mute the low-tone edge of Neutral's dark chromatic palette while preserving its light and neutral ramps. (#6069)
- Correct Neutral Banner interaction tints so light mode uses translucent light overlays and dark mode uses translucent dark overlays. (#5936)
- Use palette-backed red interaction overlays for Neutral destructive buttons, solid dark-palette tone-25 backgrounds (tone 20 for gray), and calmer dark-mode text colors. Use a palette-backed muted blue tint for dark info banners while preserving the existing light-mode non-semantic color mappings. (#6049)
- Give Neutral segmented controls a roomier inset while preserving their outside height. (#5851)
- Rename built-in syntax theme identifiers. (#5847)
- Remap Neutral's semantic, syntax, and categorical color tokens to the reviewed theme-owned palette through named stop references. Keep the maintained CLI template synchronized. (#6034)
- Rename built-in syntax theme identifiers. (#5847)
- Rename built-in syntax theme identifiers. (#5847)
Thanks to everyone who contributed to this release:
@cixzhang @ernestt @freddymeta @Geervan @harjothkhara @HelloOjasMutreja @imdreamrunner @jiunshinn @josephfarina @kentonquatman @Kyujenius @Lee-Dongwook @ManoharPaturi @mattandryc @nynexman4464 @PRIEYAN @rubyycheung @trakshan-mishra @yyq1025
Full Changelog: https://github.com/facebook/astryx/compare/v0.5.2...v0.5.3
v6.4.0
- [basic-modules] Allow table cells to preserve and accept video and code-block content while rejecting unsupported custom blocks and nested tables.
- [core] Allow table cells to contain block descendants such as paragraphs and lists while preserving legacy text-only cells through normalization and HTML round trips. Core now exposes HTML-to-content conversion and a composable initial-content transform hook for modules that need boundary migrations.
Package versions
| Package | Version | Source |
|---|---|---|
@wangeditor-next/basic-modules |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/code-highlight |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/core |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/editor |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/editor-for-react |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/editor-for-vue |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/editor-for-vue2 |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/list-module |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/plugin-attachment |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/plugin-ctrl-enter |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/plugin-float-image |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/plugin-formula |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/plugin-link-card |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/plugin-markdown |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/plugin-mention |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/table-module |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/upload-image-module |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/video-module |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/yjs |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/yjs-for-react |
6.4.0 |
Source (tar.gz) |
@wangeditor-next/yjs-for-vue |
6.4.0 |
Source (tar.gz) |
v1.13.0
See CHANGELOG.md for details.
v3.10.0
useAsyncEffect支持同步返回清理函数,在依赖变化和卸载时由 React 执行清理。注意:这不支持async () => cleanup,异步函数返回的清理函数不在本次支持范围内。#2958useLocalStorageState新增getInitialValueInEffect,允许挂载后再读取存储,以避免 SSR hydration 不一致。#2906useSetState支持省略初始状态,返回状态类型为Partial<T>。#2905useAntdTable支持表单实例的validateFieldsReturnFormatValue,兼容 ProForm 的transform。
useRequest修复被取消或被后续调用覆盖时的异步调用悬挂问题,并提供CancelledError/isCancelledError。#2951useRequest修复节流场景下runAsync不生效,以及ready=false时防抖前沿调用影响后续请求的问题。#2899、#2946useRequest修复默认参数场景的类型推导,并在删除缓存时清理相关定时器。#2907、#2909useInfiniteScroll修复首次loadMore期间闭包读取旧数据的问题。#2896useKeyPress修复exactMatch下修饰键的keyup事件匹配。#2944useLongPress修复 Pointer Events 支持。#2947useTheme为旧版 Safari 提供媒体查询监听回退。#2916- 修复
useEventListener显式泛型与 ref target 的兼容性,并保留非空 ref 的返回类型。#2903、#2956 - 移除已废弃的
intersection-observer依赖。#2904
runAsync / refreshAsync 被取消或被新调用覆盖时,会以 CancelledError 拒绝,而不再一直保持 pending。直接调用这些异步 API 的代码应捕获异常,并用 isCancelledError 区分取消与业务错误;run / refresh 会内部处理取消。
- Support synchronous cleanup functions in
useAsyncEffect, with React managing cleanup on dependency changes and unmount. Returning cleanup from anasynccallback remains unsupported. #2958 - Add
getInitialValueInEffecttouseLocalStorageStateto defer storage reads until after mount and avoid SSR hydration mismatches. #2906 - Allow
useSetStatewithout an initial state, returningPartial<T>. #2905 - Support ProForm's
transforminuseAntdTablethroughvalidateFieldsReturnFormatValue.
- Settle cancelled or superseded
useRequestasynchronous calls withCancelledError; exportCancelledErrorandisCancelledError. #2951 - Fix throttled
runAsynccalls and debounce leading behavior whileready=false. #2899, #2946 - Fix default-parameter type inference and clear timers when request cache entries are deleted. #2907, #2909
- Fix stale data captured during the initial
loadMoreinuseInfiniteScroll. #2896 - Fix modifier-key
keyupmatching withexactMatchinuseKeyPress. #2944 - Fix Pointer Events support in
useLongPress. #2947 - Fall back to legacy media query listeners in
useThemefor older Safari versions. #2916 - Fix explicit generic and ref target compatibility in
useEventListener, and preserve non-nullable ref return types. #2903, #2956 - Remove the deprecated
intersection-observerdependency. #2904
Cancelled or superseded runAsync / refreshAsync calls now reject with CancelledError instead of remaining pending. Catch errors when using these APIs directly and use isCancelledError to distinguish cancellation from service errors. run / refresh handle cancellation internally.
Full changelog: https://github.com/alibaba/hooks/compare/v3.9.7...v3.10.0
v2.11.2
- Concurrent calls to
ZipWriter#add()compress concurrently again. Since v2.10.0 every entry of a batch took the path that writes directly into the zip file, and each of them then waited for the previous entry to be written, so the batch was compressed one entry at a time. The writer now records that choice in the same step that makes it, so the first entry is written directly into the file and the others are buffered, as before. Measured on 8 entries of 8 MB with the nativeCompressionStream, the same batch of concurrentadd()calls goes from 2211 ms to 607 ms. The archive is unchanged, only the scheduling was wrong - A
Readerthat declares its size and always returns the number of bytes it is asked for no longer makesZipWriter#add()read it forever. The writer did not pass that size when it built the readable stream, so the stream ended only when the reader returned an empty array. The stream also advances by the number of bytes actually returned instead of by the requested chunk size, so a reader that returns a short chunk in the middle of the data no longer skips the rest of the chunk
- The
keepOrderoption no longer states that concurrent calls toZipWriter#add()compress one entry at a time and needbufferedWriteto overlap. That described the bug above, not the intended behavior
- The benchmarks report the size each library produced next to every time, and a new
bench-codecs.jscompares the codecs alone, sorted by output size. A compression level is not a unit shared between libraries, so a table matched on level reads a difference in compression ratio as a difference in speed
Tabler v1.5.0
Tabler 1.5 is out. It's the biggest release we've done, with more than 250 changes across the framework, the demo pages and the docs. The sidebar folds now. Cards can have gradients, backgrounds can have patterns, charts got seven new types, and the demo comes with two new dashboards. Bootstrap also moved into the Tabler source tree, and that's where a lot of the smaller changes in this release come from.
The vertical sidebar can fold down to a narrow strip of icons with navbar-folded. With navbar-folded-hover it stays folded and opens when you hover over it. Submenus open as flyouts next to the icon, and there's a pin toggle if you want to keep the sidebar open.
Two smaller things came with it. Section titles in the sidebar (nav-section-title) turn into short separators while it's folded, so you don't lose the grouping. And there's a new navbar-footer zone for the user block at the bottom. The navigation scrolls between the pinned brand and the pinned footer.
The sidebar is also light and 16rem wide by default now.
The theme panel does more than light and dark now. It also switches the layout, through four attributes you can set on <html> yourself: data-bs-layout for the container width (default, fluid, boxed), data-bs-navbar-position for whether the page shows the vertical or the horizontal navigation, data-bs-navbar for a sticky top bar, and data-bs-navbar-theme for coloring the navigation dark or primary. The folded sidebar has its own data-bs-sidebar.
The panel itself was redesigned around them, with an illustrated intro, color scheme presets and thumbnail tiles for most settings. A Customize entry in the sidebar footer and in the navbar opens it.
.card-gradient gives a card a gradient background. There are variants for each theme color, modifiers for the direction, and an animated version.
The gradient stops are plain utilities, so you can use them anywhere else too. .bg-gradient-from-*, -via-* and -to-* now also take transparent and -inverted.
There's a new Card gradients page in the demo with all the combinations.
Backgrounds can have a pattern now. Dots, grids, stripes and a few more, through a set of .bg-pattern-* utilities.
You can also control how strong the pattern is. --tblr-pattern-opacity-factor scales the opacity globally, and .bg-pattern-opacity-* sets it per element.
Seven chart types joined the demo and the docs: radar, polar area, treemap, timeline, box plot, bubble and funnel. There's also a new Advanced charts page for the harder cases, with two y-axes, annotations, a zoom brush and synced chart groups.
Chart colors aren't hardcoded per chart any more. There's a --tblr-chart-1 through --tblr-chart-5 palette wired into the ApexCharts theme tokens, so charts generally follow the current color mode on their own. ApexCharts itself went from 3.54.1 to 7.0.0.
Two dashboards joined the demo. One is a CRM dashboard built from reusable cards, the other a crypto dashboard with a portfolio overview, market data and order history.
There's also an onboarding page, a task list and a pay page, plus four new modals: change password, confirm delete, edit profile and new task.
Bootstrap 5.3.8 now lives in the Tabler source tree as Sass modules and TypeScript components, so Tabler doesn't depend on the Bootstrap package any more. A few other things changed along the way:
- The npm package ships TypeScript declarations, so
import { Modal } from "@tabler/core"is typed. - The default color mode is
autoand follows the system setting. - Tabler doesn't bundle a web font any more. The default stack is the system one, so nothing gets downloaded.
- Components accept
data-tblr-*attributes next todata-bs-*. - The supported browsers are now Chrome 123, Firefox 128 and Safari 17.5, which is what the CSS actually needs.
- The Turbo integration is gone, along with a number of unused Sass variables.
Every breaking change is in the Upgrade to 1.5 guide, with a before and after example for each one.
- 9ea657b: Added
.text-gray-50through.text-gray-950utility classes alongside the existing.bg-gray-*utilities. - 100a37b: Added background pattern utilities and documentation, including updated preview demos.
- 9d5c83f: Added Bootstrap 5.3.8 to the core source tree, with SCSS as modules and components converted to TypeScript.
- e1ecd39: Updated the supported browser baseline to what the CSS needs: Chrome 123, Firefox 128, Safari 17.5.
- 9c5d729: Added
.btn-ghostbutton variant with transparent background and hover effects. - ec94693: Added
.card-gradientcomponent with gradient variants, direction modifiers, and animated backgrounds. - 324b0fb: Added
--tblr-card-header-bgand--tblr-card-footer-bgvariables so both backgrounds can be overridden independently. - 09d419a: Added a
--tblr-chart-1…--tblr-chart-5palette and wired ApexCharts theme tokens, so every chart follows the color mode. - d2c1271: Added TypeScript declarations to the npm package, so
import { Modal } from "@tabler/core"is typed. - 9d5c83f: Added support for
data-tblr-*attributes alongsidedata-bs-*for dropdown and other components. - bf9e7ad: Added Driver.js to
libs.jsonanddist/libsfor product tours. - bf9e7ad: Added
--tblr-dropdown-item-gap,--tblr-dropdown-item-icon-sizeand--tblr-dropdown-item-icon-colorto.dropdown-menu. - 4f6e99b: Added a folded sidebar (
navbar-folded,navbar-folded-hover) with flyout submenus, a pin toggle and a light16remsidebar by default. - 70f996b: Added the
.font-sans-serif,.font-serifand.font-comicutilities next to.font-monospace. - d2c1271: Added
.bg-gradient-{from,via,to}-transparentand-invertedgradient stops, which the gradient docs already described. - 5baf073: Added 74 new payment provider icons imported from
tabler-paymentsand removed 12 outdated providers likedotpayandsolo. - 5e119d4: Added
bg-blurutility and increasedcontainer-tightwidth for layout flexibility. - 70f996b: Added the
data-bs-layout,data-bs-navbar-position,data-bs-navbaranddata-bs-navbar-themelayout settings. - 0c79963: Added
media-printmixin and print styles to hide interactive components during printing. - 48dbd1e: Updated the core build system from Rollup to Vite, with identical UMD and ESM output.
- 4ce08ca: Updated the navbar-side component and reorganized its apps, language, notifications and user sections.
- 70f996b: Added
.navbar-sidesupport in the vertical navbar: a wrapper for a trailing.navbar-navgroup pinned to the bottom of the menu. - f11ece4: Added
--tblr-pattern-opacity-factorand.bg-pattern-opacity-*utilities for background patterns. - cad8eb8: Removed the
$prefixSass variable; the--tblr-prefix is now applied at build time by PostCSS. - 9c5d729: Added Progress Background component with text labels and value display.
- 9c5d729: Added
.progress-lgand.progress-xlsize variants for the progress component. - 9c5d729: Added Progress Steps component for step-by-step navigation indicators.
- bea97f8: Removed
@hotwired/turbointegration, including.turbo-progress-barstyles and the Turbo loader preview demo. - 8962710: Removed unused SCSS
!defaultvariables, which now raise a Sass error when set via@use ... with (...). - 9820d11: Updated core SCSS to the Sass module system with
@useand@forward. - 4f6e99b: Added
nav-section-titlegroup labels to the vertical sidebar, shown as short separators in the folded state. - 4f6e99b: Added a
navbar-footersidebar zone with a user block; the sidebar nav scrolls between the pinned brand and footer. - ff24af9: Updated the default
$font-family-sans-serifand$font-family-monospaceto the system font stacks. Tabler no longer bundles a web font, so no font files are downloaded. - 9dd26fd: Changed the default theme of
tabler-theme.jstoauto, following the system color scheme. - 7556ae2: Added an
autocolor mode to theme settings with systemprefers-color-schemesupport. - e3d86c5: Updated
apexchartsfrom3.54.1to7.0.0and added--chart-{id}-color-{index}variables. - 1effe22: Fixed invisible keyboard focus indicators and added
prefers-reduced-motionandforced-colorssupport. - 09d419a: Documented the ApexCharts dual license, which applies to the copy shipped in
dist/libs, in the readme and chart docs. - 080d3aa: Fixed the ApexCharts tooltip arrow staying white on the dark tooltip by setting the
--apx-tt-bgand--apx-tt-bordertokens. - ffe3489: Updated
.badges-listto.badge-listand.tags-listto.tag-list, keeping the old names as deprecated aliases. - 059bae1: Updated Bootstrap exports to a single source of truth in
bootstrap.jsand removed the duplicates fromtabler.js. - 4f6e99b: Moved
btn-floatingto the end side of the screen, so it does not cover the sidebar. - 5018aa9: Fixed
.btn-iconto be square by aligningmin-widthcalculation with base.btnformula. - a508bb6: Updated hardcoded
remandpxvalues to SCSS variables across core components for easier theming. - c71a321: Updated the
@tabler/coreREADME with package usage, optional stylesheets, Sass setup and browser support. - a0d84f6: Updated the npm package README with badges, quick links, CDN usage, documentation and changelog links.
- c860288: Fixed icon alignment for
.btn-smand.btn-xlsizes. - 1adb710: Fixed
.alert-actionand.alert-linkcolors inside.alert-importantso links stay readable. - 2dc7eda: Updated
$border-color-translucent-darktorgba(128, 150, 172, 0.2)for better dark mode visibility. - 09ab0bc: Fixed disabled buttons falling back to
currentColorfor the border and to a transparent background. - febfa9f: Fixed the missing focus ring on buttons and
btn-checkbutton groups by using the shared focus ring token. - 8324701: Fixed
.card-headerbackground being overridden by abackground: transparentshorthand. - 0187b26: Fixed the
card-status-*strips leaving a thin line over the card border and a mismatched corner radius. - 70ec683: Fixed card corner radius in tab layouts when tabs sit above or below tab content.
- c1e1fdf: Fixed the corner radius and the double bottom border on the first and last rows of a table inside a
.card. - de44d61: Fixed
.card-tabs .nav-tabssharingz-indexwith.dropdown-menu, which hid dropdowns behind card tabs. - 6414238: Fixed barely visible checkbox and radio borders in dark theme by using
$input-border-color. - b1d49e9: Fixed CountUp to parse formatted number targets and avoid double-start when
enableScrollSpyis enabled. - 09d419a: Fixed chart colors in dark mode: axis lines and ticks, marker and treemap outlines, and the tooltip title.
- 070248d: Fixed dark mode link contrast:
--tblr-link-coloris now a lighter tint of--tblr-primaryon dark surfaces. - 601e950: Fixed dark mode text selection contrast with a new
$selection-bgSass variable. - d0a793c: Fixed the disabled form control background in dark theme with a new
--tblr-bg-forms-disabledvariable. - b1d49e9: Fixed dropdown
data-bs-boundary="viewport"to usedocument.documentElementinstead of the first.btnelement. - c527135: Fixed
.input-iconinline-start padding for.form-select. - 70f069c: Fixed
.form-selectkeeping its default box-shadow inside.input-group. - 9c78cf6: Fixed
.bg-gradientconflicts that brokefrom/via/torendering and updated the gradient docs. - bc24b3a: Fixed
--tblr-gray-*-fgtokens to map directly to--tblr-gray-*instead of contrast-based fallbacks. - c8b8b24: Fixed gray theme custom properties output using SCSS interpolation and updated default
$body-colorto$gray-500. - 70193fe: Fixed
.icon-pulse,.icon-tadaand.icon-rotatenot animating webfont icons. - f0b909d: Fixed the
smandlgsize mismatch between form controls, buttons and input groups. - 6e656ad: Fixed
.input-icon-addonz-index issue with form validation feedback and added default height. - b1d49e9: Fixed input mask
lazyoption to readdata-mask-visibleviadataset.maskVisible. - fc16b6a: Defined
--tblr-body-text-align,--tblr-nav-link-font-sizeand--tblr-nav-link-active-color, which the css already read. - a883531: Fixed
.list-group-item-{color}: the palette colors had no styling at all and no variant had its background. - 9dd26fd: Fixed the markdown table header keeping its surface background instead of going transparent.
- 9d04e14: Fixed the marketing hero, browser and shape components reading custom properties nothing defined.
- 9dd26fd: Fixed
offcanvas-narrow, which had no effect on the width of the panel. - f5f75d4: Fixed print styles: hidden navbar/sidebar, forced light
color-scheme, and avoided breaking.card/table rows. - 1da70a7: Fixed ScrollSpy throwing on target ids that start with a digit, such as headings like
1. Setup. - 464a522: Fixed oversized and mismatched validation icons on
.form-selectand Tom Select selects. - 8bc6fa7: Fixed status color classes to use CSS variables and to include the social colors.
- c527135: Fixed
.stepshorizontal overflow on small screens by enabling scrollable overflow below thesmbreakpoint. - cd0b210: Fixed the typographic
.stepsrule leaking its guideline and spacing onto the.stepscomponent. - 90c42f2: Fixed Tom Select's
.ts-dropdownlosing its z-index, background, and colors to the bootstrap5 preset CSS. - 6849337: Fixed Tom Select styles to use
--tblr-*variables instead of undefined--bs-*references. - e206d7a: Fixed white space next to the scrollbar by using
scrollbar-gutter: stableonhtml. - bf9e7ad: Updated
.flagto size by width with$border-radius-xsonxs, and narrowed tooltippadding-xtospacer-2. - b8b63d7: Fixed Sass mixed-declaration warnings in the navbar, card, nav and table styles.
- 9432835: Updated SCSS files to use the
border-radiusmixin. - 9c5d729: Updated
stroke-widthfor.icon-smfrom1to1.5for better visibility. - bf9e7ad: Updated
.input-group-flataddons to drop the inner border and sit above the control. - fa678a7: Updated root color tokens to use CSS
light-dark()so paired values live in one:rootdeclaration. - 7ae422f: Updated core SCSS to logical properties and a
--tblr-dirmultiplier, so RTL works with plaintabler.css. - 301e778: Updated
rgba()calls to the moderncolor-mix()andcolor-transparent()functions. - 9dd26fd: Fixed the avatar corner radius inside
.form-imagecheck-imageand set.navfont size to the body font size. - 4f6e99b: Fixed the
navbar-togglericon: the middle bar was flex-squeezed, breaking the open-state X and shortening the hamburger. - 9c5d729: Added smooth transitions for progress bar
widthandbackground-colorchanges. - 1489b13: Added
.prosealias for markdown content and updated preview/docs references and redirects. - f35aab3: Added the same border and radius to
figureimages as plain images in.proseand.markdowncontent. - 66dc336: Fixed the
caret()mixin by restoring$caret-widthto0.36em. - 70f996b: Fixed the sidebar marking two items as selected: a group holding the current page is now emphasized, not filled.
- 70f996b: Fixed the vertical navbar brand sitting at the far edge on small screens when nothing follows it in the top bar.
- 9c5d729: Updated skip-link to use
visually-hiddenfor improved accessibility. - 346e091: Fixed oversized
dist/libsby copying only the runtime files each library declares inlibs.json. - d2c1271: Fixed
tabler-theme.jsreplacing a server-rendereddata-bs-themewhen the visitor has no stored choice. - 736e604: Updated deprecated global Sass functions to module equivalents (
map.merge,string.slice,math.percentage, etc.). - b8b63d7: Updated Bootstrap to v5.3.8.
- 9c5d729: Updated trending component to use
arrow-up/arrow-downinstead oftrending-up/trending-down. - 70ec683: Updated
$card-status-sizedefault from$border-width-wideto3px. - 666ccd6: Updated shadow tokens (
--tblr-shadow-*) to use the newxs–2xlandoverlayvalues.
- 09d419a: Added a
charts-advancedpage and docs for two y-axes, chart annotations, a zoom brush and synced chart groups. - 5e119d4: Added Pay page with dedicated layout, navigation link, and card/PayPal payment form.
- d8956a0: Updated the
previewanddocspackages to build with Astro instead of Eleventy. - ec94693: Added new
card-gradientspage showcasing various gradient card styles and components. - b0fa655: Added Change Password modal with a strength indicator, confirm validation and show/hide toggles.
- ad22d04: Added a color palette to the signature pad component for selecting the pen color.
- b0fa655: Added Confirm Delete modal with a warning icon and a checkbox that enables the delete button.
- 62178f8: Added new
dashboard-crmpage with reusable CRM cards. - 4ce08ca: Added new Crypto Dashboard page with cryptocurrency portfolio overview, market data, and order history.
- 118ca4b: Updated the demo pages to show their title and description in the page header, with
pageHeaderfalling back totitle. - b0fa655: Added Edit Profile modal with avatar upload, personal information fields, social links, and date of birth.
- 8d8727f: Added language selector dropdown to navbar with flag indicators for multilingual support.
- 70f996b: Added layout options to the theme settings panel and removed the dead demo script and the
layout-combopage. - 4ce08ca: Updated the page-menu structure for dashboards and reorganized the navigation menu.
- 09d419a: Added radar, polar area, treemap, timeline, box plot, bubble and funnel chart types to the charts preview and docs.
- b0fa655: Added New Task modal with fields for task name, description, assigned user, priority, due date, and category tags.
- 9c5d729: Added new onboarding page with progress indicator and navigation layout.
- 118ca4b: Removed the
actionspreset prop fromDefaultLayout; pages now fill apage-header-actionsslot instead. - cc298a6: Added a
PageTitlecomponent and used it withCardSubtitlein place of raw.page-titleand.card-subtitlemarkup. - 5363668: Added the missing Prose demo page, linked from the menu but not previously built.
- 83ec6f8: Added Tour demo page using Driver.js for product tours and onboarding guides.
- d7cbe87: Added
colorandverticalprops to theStepscomponent and used it on the steps preview page. - 09d419a: Added a straight
linechart demo and setstroke-curveto straight on the line and area demos, so the spline ones differ. - 99b9ea4: Added a Task List page with tasks grouped by status and a modal for adding new tasks.
- 1effe22: Fixed keyboard access by turning JavaScript-only
<a href="#">controls into real<button>elements. - 1effe22: Added missing ARIA roles and states to
Pagination,NavSegmented,Accordion,Steps, tabs,Modal,OffcanvasandCarouselCard. - 1effe22: Added
aria-labelto theDatepickernavigation buttons and made theDropzoneupload area keyboard-operable. - 1effe22: Added
<fieldset>and<legend>around radio and checkbox groups so screen readers announce the group purpose. - 1effe22: Fixed form accessibility with matching
for/idlabels,aria-invalid,aria-describedbyandautocompletetokens. - 1effe22: Fixed the skip link to appear on focus and added missing
<main>and labelled<nav>landmarks. - 1effe22: Added a
labelprop toFlag,Payment,StatusDot,TrendingandAvatarstatus badges for screen readers. - 0fd35c3: Updated the
active-users-2card chart to usechart-id="active-users-2"withheight="11"for a more compact layout. - 1adb710: Added
actionandlinkexamples to the important alerts in the alerts preview and docs pages. - 8704725: Fixed root-absolute
Buttonhrefs in demos, so error-page links work in the downloadable package. - da11f08: Added a short description and a docs link to each card on the Buttons demo page, grouped into Styles and Colors.
- 118ca4b: Fixed heading order by making
CardTitleandCardHeaderrenderh2, so cards no longer skip a level under the pageh1. - 632b69f: Updated the changelog page to redirect to tabler.io/changelog instead of rendering
CHANGELOG.md. - 09d419a: Removed dead chart options (
groups,spline,fill,debug,remove-padding,show-labels) fromcharts.json. - 4ce08ca: Added
crypto-markets.jsonandcrypto-orders.jsondata files for the crypto dashboard. - 70f996b: Unified the Customize entry: the navbar and the sidebar use the same
.navbar-sidebutton with thebrushicon. - b3e873a: Fixed the
valuekey inselects.jsonnot preselecting options in the demo selects on the modals and form elements pages. - 8704725: Updated preview and docs examples to the unified demo component props:
variant,color,size,ariaLabel. - 0f8dcb0: Updated preview and docs to use the shared
date-format,string-formatandpseudo-randomhelpers. - 09d419a: Fixed the combination chart demo so it mixes columns and lines instead of drawing plain bars.
- 3cca8bf: Fixed task cards not showing their due date and removed dead props and classes such as
fluidSearchandtext-*-lt-fg. - 3f1ad9d: Fixed the navbar not highlighting the active page for nested, RTL and settings pages.
- f2004da: Fixed payment icons on the all-elements page by rendering separate light and dark variants.
- 9dd26fd: Removed the non-existent
mtclass from the placeholder card. - 1da70a7: Fixed the marketing footer layout, timeline social icons, missing
altandaria-labelattributes and invalid nesting in demos. - f2004da: Fixed the ribbon example background on the all-elements page to use
var(--tblr-bg-surface-secondary). - 1adb710: Fixed the sign-in cover page in dark mode by replacing
bg-whitewithbg-surface. - c7e895b: Updated the footer to show the version link everywhere and the
Generatedtimestamp only on preview builds. - ac87b76: Updated preview templates to replace deprecated
font-weight-*classes with Bootstrap-compatiblefw-*utility classes. - 8704725: Fixed icon-only demo buttons rendering a generic
aria-label="Button"instead of a real label. - 25f466b: Updated the icon count on the icons pages to read from
icons-info.json, so it follows the installed version. - 8f86f1f: Restored the
import-iconsandimport-illustrationsscripts. - 5363668: Made Interface demo pages consistent with the Buttons page: card subtitles, one docs link, responsive grids.
- 8704725: Updated the marketing CTA
Learn morebutton to the.btn-ghoststyle. - 70f996b: Removed
aria-current="page"from menu groups, so only the link to the current page carries it. - 7cadbb8: Updated
Newbadges inmenu.jsonto mark only pages added since 1.4, and dropped them from older pages. - 8947d7c: Updated the activity feed messages in
activity.jsonand the activity preview page. - 863884e: Added
DocsLinkto the header of 20 more demo pages, including Cards, Charts, Tables and Typography. - b90554b: Moved the
import:iconsandimport:illustrationsscripts to the repository root, next toimport:payments. - f35aab3: Added a Tabler Payments docs section with
@tabler/payments-*package pages for React, Vue, Preact and Astro. - 38df58d: Added the
500illustration to the preview 500 error page. - d2c1271: Removed classes that no stylesheet defines from demo markup and added the onboarding and settings plan pages to the menu.
- 118ca4b: Added a
metadescription tag, filled from the pagedescriptionprop. - 7305d84: Fixed Vercel deployment to serve
error-404.htmlas the custom 404 page. - 43eee38: Added
Progress Stepcomponent documentation and cleaned up the progress steps preview markup for cleaner rendered output. - 09d419a: Replaced the placeholder chart data on the charts page and in the chart docs with realistic series, and titled every demo card.
- da11f08: Replaced lorem ipsum with unique placeholder text on the Scroll spy demo page and fixed its menu highlight.
- 70f996b: Added a Customize entry to the sidebar footer that opens the theme settings panel.
- 70f996b: The sidebar now always renders the user block, so the vertical layout keeps the profile menu on every page.
- 552cf1f: Removed the
<lastmod>element fromsitemap.xml, which carried the build time instead of a content date. - da11f08: Reorganized the Star Ratings demo page into Basic/Icons/Sizes and Colors cards with short descriptions.
- 70f996b: Redesigned the theme settings panel with an illustrated intro, color scheme presets and thumbnail tiles for most settings.
- bd35fd3: Fixed responsive layouts on the Form Elements page.
- 53f5244: Updated the
IllustrationandEmptycomponents to accept only the bundled illustration names, checked at build time. - ee4c88f: Updated
@tabler/iconsto v3.46.0. - 369322a: Updated Tabler Illustrations to v1.17.0 with 25 new illustrations.
- c707018: Added an All Elements page showing every UI component and Bootstrap element.
- 4a97921: Added
Accordiondocumentation page with usage variants and Bootstrapcollapsebehavior examples. - f5f75d4: Added a Printing docs page covering
d-print-*utilities and themedia-printmixin. - 3277fa0: Added
Astroicons library documentation page for the new@tabler/icons-astropackage. - 73f7c2a: Added
Accept: text/markdowncontent negotiation for docs pages, with q-value parsing and406responses. - 9dd26fd: Added an Accessibility section to every UI documentation page.
- d2c1271: Added a Background blur page, gray utilities on the colors page and a language selector section on the navbars page.
- 135f38d: Added
Info,Tip,Warning,DangerandNotecallouts, usable in any MDX page, with a reference page under Resources. - 9dd26fd: Added installation and usage sections to the chart and countup pages, covering the
.chart-*size classes and sparklines. - 9dd26fd: Added a class reference table to every component page, from the new
classnamesfront matter. - 6e6084a: Added docs pages for the Datepicker and Tom Select form plugins,
form-datepickerandform-select-tomselect. - 9dd26fd: Updated the docs layout: elevated article panel, rounded sidebar navigation, "On this page" rail and restyled prev/next links.
- 9dd26fd: Listed every component class in
llms.txt, from theclassnamesfront matter. - 73f7c2a: Added a
llms-full.txtpage with all docs in one file,Content-Signalin robots.txt and markdownLinkalternate headers. - 9dd26fd: Added a source link and a copy-as-markdown button, and moved the class reference to the end of the page.
- 9dd26fd: Added
classnamesto the social icons and flags pages. - 9dd26fd: Rewrote the autosize, range slider, WYSIWYG and dropzone plugin pages with installation, usage and accessibility sections.
- 9dd26fd: Expanded the social icons, payments, vector map, inline player, PDF, EPS, illustrations preview and references pages.
- 9dd26fd: Documented
avatar-square,mention,offcanvas-narrow,btn-floating,card-cover,td-truncateand other variants. - 416ca63: Added framework integration guides for Laravel, React, Next.js, Vue, Angular, Nuxt, Symfony, Django, Rails, SvelteKit, and Astro.
- 1adeb68: Added a Docs for LLMs page explaining
llms.txtand the.mdpage mirrors, with a sidebar link. - 9dd26fd: Removed the EPS icons page, since
@tabler/icons-epsis no longer maintained. - fb3d7dc: Added an RTL support docs page covering the
dir="rtl"attribute, the published*.rtl.cssbuilds, how rtlcss generates them, and which utility classes are direction-aware. - bd4e381: Added
Star Ratingdocumentation page with static and interactive rating examples based on existing classes. - 8af57f9: Added
Tagdocumentation page with examples for icon, media, badge, checkbox, and list usage. - 7b64726: Added a Theme base colors page documenting the five
data-bs-theme-basegray palettes intabler-themes.css. - f4c514a: Added an
Upgrade to 1.5page with the breaking changes, renamed classes and Sass updates from 1.4. - 2a06640: Added
added-inbadges to Card gradient, Progress steps and new getting-started guides; fixed background patterns' version. - 46da1f7: Updated background patterns documentation with missing pattern variants, transparent utility usage, and size coverage.
- 1ec82d0: Updated the contributing guide, README and Docker setup for the Astro-based development toolchain.
- 38df58d: Added the
not-foundillustration and a search button to the docs 404 page. - 9dd26fd: Documented card status, progress, actions, subtitle, surfaces, scrollable body, tables, links and overlays.
- 9dd26fd: Fixed highlighted code blocks using hardcoded colors instead of the Tabler surface tokens.
- 9dd26fd: Fixed the copy button in docs examples to be a
buttonwith an accessible name. - 684f40e: Updated the documentation to explain font sizing and system color CSS variables.
- 9dd26fd: Fixed docs example code blocks gluing inline elements like
<label>and<input>onto one line. - 9dd26fd: Added a
darkbackground option to the docs<Example>component. - 9dd26fd: Updated docs examples to use the
<Icon />component and consistent Prettier formatting. - d2c1271: Fixed duplicate ids and missing targets in the modal, offcanvas, page headers and page layouts examples.
- 9dd26fd: Fixed keyboard access in docs examples for carousel controls, disabled links,
btn-loadingand progress bars. - 9dd26fd: Fixed install snippets pointing at urls that do not resolve on the vector map, inline player and icon pages.
- 9dd26fd: Fixed docs examples using classes that do not exist, such as
alert-facebook,btn-close-white,bg-gray,btn-xs,alert-titleandhr-text-center. - 9dd26fd: Added tooltips and accessible names to the footer icon links.
- 9dd26fd: Stacked form docs examples in a column and tightened the sidebar nested menu indent.
- 9dd26fd: Moved the form pages backed by a third-party library into the Plugins section.
- 9dd26fd: Renamed form docs pages without the
form-prefix and flattened the Illustrations and Emails sections. - a0d84f6: Updated the How to Contribute guide with starter issues, Codespaces setup, commands and PR conventions.
- f35aab3: Added Introduction pages with quick starts and cover images to the Icons, Illustrations, Emails and Payments docs sections.
- 1ec82d0: Fixed documentation formatting issues: heading hierarchy, missing image alt texts and broken list structure across docs pages.
- 9dd26fd: Split the getting started menu group into Getting started and Resources.
- 9dd26fd: Updated the docs navbar to use
container-lg. - 4afc2ea: Updated the prose on 75 docs pages to plain English, shortened the page summaries and merged duplicate sections on the button and card pages.
- 9dd26fd: Moved components that need a third-party library into the Plugins section.
- 9dd26fd: Moved the Website, Preview and Support links from the docs sidebar to the top navbar.
- 9dd26fd: Restyled the related and prev/next cards, and moved prev/next below the article panel.
- 9dd26fd: Restored the
docs.scsssource for the docs styles, compiled with Sass instead of a checked-indocs.css. - 9dd26fd: Fixed the search modal using the Algolia palette instead of Tabler colors, including an unreadable selected result.
- 9dd26fd: Darkened the docs sidebar links, kept rows to one line and added a visible focus ring.
- c430cfe: Updated UI component docs to singular file names and frontmatter, with redirects from plural routes.
- 826a073: Added
sitemap.xmlandrobots.txtendpoints for the docs site and fixed docs layout title rendering outside production. - 2f8f495: Fixed the docs header not staying sticky, and the table of contents sliding under it.
- 9dd26fd: Documented sortable headers, selectable rows, stacked mobile tables, and outline, dot and icon-only badges.
- 9dd26fd: Rewrote the timeline and datagrid pages with markup, variants and accessibility notes.
- 9dd26fd: Fixed plugin demos showing their stock styles, because library CSS loaded after
tabler-vendors.css. - ee4c88f: Updated
@docsearch/jsand@docsearch/cssto v5 and kept the docs search on the keyword-only entry point. - 1adeb68: Fixed html comments in docs code examples running into the closing tag of the element before them.
- 09d419a: Fixed the small chart example on the chart docs page, which shared an element id with the line chart example and stayed empty.
- c547329: Fixed the
Pluginscard on the docs homepage linking to a 404/pluginsroute instead of/ui/plugins. - 1da70a7: Fixed the docs logo link name, dead example links in the navbar and offcanvas pages, and the vector map error on its plugin page.
- ee4c88f: Fixed docs pages with callouts falling back to their MDX source in
llms.txtinstead of the rendered examples. - c71a321: Fixed the Sass import in the framework guides to use
@useinstead of the deprecated@import. - 70f996b: Documented the layout theme settings on the color modes and page layouts pages.
- 1adeb68: Fixed the
.mddocs mirrors showing component tags like<Icon />instead of the rendered html. - 08cad98: Updated the
Progress Bardocumentation with new variants and full-width stacked previews. - 4d04c10: Removed the unused
bootstrapLinkfront matter field fromDocsLayout,DocsMdxLayout, and all docs pages.
v7.1.0
- PERF: DayGrid with large number of events, when
dayMaxEvents:true(limited by natural row height), only a necessary subset of events will be DOM-inserted, not all- BREAKING: As a result, a subset of events will be run through event render hooks like
eventContent
- BREAKING: As a result, a subset of events will be run through event render hooks like
- DayGrid event slicing
- FEATURE: Better event packing, including smarter positioning decisions for fewer slices
- FEATURE: Related slices have more similar y-coordinates
- FIX: Events unnecessarily going to +more link when higher-level slot would accommodate
- TimeGrid event positioning
- FIX: Events with custom ordering and
eventOrderStrict:truecan overlap withslotEventOverlap: false(#7914) - FIX: Overlapping events can have tiny width when event content not visible (#7879)
- FIX: Events with custom ordering and
- FIX: In Timeline and TimeGrid, when custom
eventOrder, DOM order respects start-time first, theneventOrder. Better for a11y and tabbing through events sequentially - FIX: React StrictMode: DayGrid events permanently invisible (#8088)
- FIX: Timeline view, smoother virtualized fast scrolling, especially with trackpad and especially while scrolling up with irregular height resource rows
- FIX: Timeline view, account for DST in timeslots (#7620)
- FIX: Resource TimeGrid/DayGrid,
filterResourcesWithEventsshould exclude columns (#6149)
- FEATURE: Print renders business-hours for print-previews that enable it
- FIX: Better page-wrapping of tall DayGrid rows with many events
- FIX: Better page-wrapping of tall Resource-Timeline rows with many events
- FIX: Events are not visible when we print using
window.print()(#8097)
- PERF: General improvements with option-changes. Users of
@fullcalendar/preactmust upgrade theirpreactpeer dependency to >=10.29.8 - FIX: Screen-reader improvement for Resource-Timeline timeline header text