2 hours ago
officeParser

v7.5.1

v7.5.1: 🛡️ Corrupt Files Fail Loudly, Real-World Archives Detect Correctly & Webpack-Safe Bundles

I am pleased to announce the release of officeParser v7.5.1! This patch release closes three reported issues around one theme: trusting the file in front of us less, and telling you more. Unreadable input now fails with typed errors instead of parsing as an empty document, type detection reads the archive's own declaration when magic-byte sniffing gives up, and the browser bundles no longer break webpack builds.

Thanks to @benhid, @SteveNewhouse and @ayazaurie, whose reports drove this release.

[!WARNING] Behavior changes

  • Corrupt input throws; it no longer parses as an empty document. Data that is not a ZIP archive, an archive cut off in transfer (or carrying data after its end-of-archive record), and a readable ZIP missing the part its format requires (word/document.xml, xl/workbook.xml, ppt/presentation.xml, ODF content.xml, the EPUB OPF) now reject with ZIP_NO_ENTRIES_FOUND, ZIP_TRUNCATED and REQUIRED_PART_MISSING respectively. An empty result therefore means the document really is empty. If you relied on unreadable files resolving quietly, catch and branch on error.officeIssue.code.
  • DOCX headers, footers and comments now appear in output. They were documented but never extracted, so ast.auxiliary.headers / .footers were always empty and comments never reached the AST. Documents that have them will now produce them; ignoreHeadersAndFooters and ignoreComments restore the old shape if you want it.
  • Config objects are no longer shared with the library. Reusing one config across calls previously leaked each parse's warnings into earlier, already-returned ast.warnings arrays, and generation could silently rewrite htmlConfig.containerWidth on your own object. Resolution now copies; callbacks and abortSignal keep their identity.

🌟 Key Highlights

1. Corrupt, Truncated and Mislabeled Files Fail Loudly (#107)

Since the 7.3.0 streaming ZIP rewrite, a corrupt buffer resolved into an empty AST with no warnings, indistinguishable from a genuinely empty document. Three distinct failure modes are now typed rejections, and every thrown error carries its structured issue so you branch on a stable code instead of matching message text:

try {
    const ast = await parseOffice(buffer, { fileType: 'docx' });
} catch (err) {
    switch (err.officeIssue?.code) {
        case 'ZIP_NO_ENTRIES_FOUND':  // not a ZIP archive at all
        case 'ZIP_TRUNCATED':         // cut off in transfer, entries incomplete
        case 'REQUIRED_PART_MISSING': // readable ZIP, but not the format it claims
            console.error('Unusable file:', err.officeIssue.message);
            break;
        default:
            throw err;
    }
}

The OfficeError type is exported for TypeScript users. Files that are legitimately empty still parse and now say so: a chartsheet-only workbook emits NO_WORKSHEETS_FOUND and a zero-slide deck emits NO_SLIDES_FOUND through onWarning / ast.warnings, so an empty result is never silent in either direction. Two ODF gaps closed alongside: a valid .ods/.odp without a mimetype entry was walked as a text document and came back empty (it now falls back to your fileType or the extension), and a missing root content.xml can no longer silently promote an embedded Object N/content.xml chart to the document body.

2. Type Detection Reads the Archive's Own Declaration (#82)

Passing a bare Buffer relied entirely on magic-byte sniffing, which walks a ZIP under fixed budgets: at most 1024 entries, and roughly 1 MiB of scanning when entry sizes are deferred to trailing data descriptors (general-purpose flag bit 3, what streaming ZIP writers produce). A valid PPTX whose [Content_Types].xml sat beyond either budget was reported as generic zip, so parseOffice threw "Sorry, OfficeParser currently supports docx, pptx, xlsx... add support for zip files" for a perfectly good document. Both layouts occur in the wild, and every ZIP-backed format was affected, in Node and in the browser.

When sniffing is inconclusive, the archive is now opened with officeParser's own reader, which has neither budget, and the format is taken from [Content_Types].xml or the ODF/EPUB mimetype entry. Detection inflates at most 4 MiB regardless of your decompression limits, a correct fileType hint skips the archive scan entirely and remains the fastest path, and a bare zip sniff is no longer misreported as a BUFFER_TYPE_MISMATCH against your own hint.

3. Webpack-Compatible Browser Bundles (#108)

One dynamic import inside the bundles escaped the build's webpackIgnore annotations, because the annotator treated an interpolated template literal as a static string. Webpack does not skip a specifier it cannot resolve: it builds a context module over the whole directory, so consumers ended up bundling all of dist/, Node-only files included, and their builds failed on child_process. The annotator was rewritten around a shared, tested classifier, child_process and url now resolve to browser stubs, and a webpack 5 build of the ESM and slim ESM bundles is warning-free. Shipping checks now scan every bundle so this class of regression cannot ship again.


🔧 Also Fixed

  • DOCX headers, footers and comments were never extracted. The parse code existed but the parts were missing from the archive extraction filter, so it could never run. Part names now also match past header9.xml, which documents with several sections reach.
  • PPTX document-property parts were parsed as slide candidates. docProps/app.xml and custom.xml are now skipped in the slide loop on identity, closing the same phantom-slide trap that ppt/presentation.xml needed.
  • Typed errors were reported twice, with a doubled [OfficeParser]: prefix and their code flattened to FILE_CORRUPTED by the wrapping layer. Errors now pass through once, intact.
  • Archive extraction errors ignored outputErrorToConsole and onWarning, always writing to the console. They now report through your handlers like every other issue.
  • Memory: the Word, Excel and PowerPoint parsers each kept the full XML source of every extracted part in a write-only buffer under includeRawContent. Dropped; serialized ASTs are byte-identical.

🛠 Getting Started

npm install officeparser@7.5.1

🔗 Full Changelog: View v7.5.1 details 🔗 Documentation & Visualizer: officeparser.harshankur.com

2 hours ago
astryx

v0.2.0

@astryxdesign/core

Breaking Changes

  • TabList: remove orientation prop (misleading no-op). The prop did not render vertical tabs; it only toggled the keyboard-hint badge arrows. Arrow navigation has always accepted both axes (horizontal and vertical) via orientation: both in useListFocus. Run astryx upgrade to auto-strip the prop from your code.

New Features

  • Avatar gains optional interactivity via href/onClick (with as/target/rel), following Button's element-swap trichotomy: href renders a link through useLinkComponent, onClick (no href) renders a <button type="button">, and with neither the avatar stays the static, non-focusable element it is today (non-breaking default). Interactive avatars get the focus-visible accent ring and a required accessible name (from alt/name). Inside AvatarGroup, interactive avatars — and an interactive AvatarGroupOverflow — now share a single Tab stop with roving ArrowLeft/ArrowRight focus, and the group exposes a screen-reader keyboard hint via aria-describedby. A purely static facepile is unchanged. (#4170)
  • Citation: CitationSource.icon now accepts a ReactNode (e.g. an Astryx <Icon>, an SVG, or a custom element) in addition to an image URL string, and a new CitationSource.src field holds a favicon/logo image URL (mirroring Avatar/Thumbnail). Additive and non-breaking: a string icon still renders as the favicon <img>, so existing callers are unaffected. When both a node icon and src are set, the node wins. The icon stays decorative — the accessible name still comes solely from the citation's aria-label.
  • CodeBlock: move the collapse chevron to the left of the title/language label, following the leading-disclosure convention (points right > when collapsed, down v when expanded). It grows into place (width + inline margin) so it slides the title over smoothly instead of popping in and shifting the header. Respects prefers-reduced-motion (#4513)
  • Collapsible: expose the trigger button as a distinct theming target (astryx-collapsible-trigger) so themes can style the trigger independently from the content — e.g. a heading font on the trigger while the content keeps the body font.
  • DateInput: add astryx-date-input-clear-icon and astryx-date-input-toggle-icon theme targets on the clear and calendar-toggle glyphs, so consumers can recolor, resize, and hover-style each icon — and style the toggle's open/closed state — via defineTheme instead of a fragile descendant selector or raw CSS. The toggle reflects its open/closed state as a data-state attribute. Icon now fully handles its styling props (className, style, xstyle) so they compose with its base styles instead of being dropped. Default rendering is unchanged.
  • DateRangeInput: add astryx-date-range-input-clear-icon and astryx-date-range-input-toggle-icon theme targets on the clear and calendar-toggle glyphs, so consumers can recolor, hover-morph, and resize them via defineTheme instead of a fragile descendant selector or raw CSS. The toggle icon reflects its open/closed state as a data-state attribute. Icon now fully handles its styling props (className, style, xstyle) so they compose with its base styles instead of being dropped. Default rendering is unchanged.
  • DateTimeInput: add astryx-date-time-input-date-segment and astryx-date-time-input-time-segment theme targets on the two segment wrappers, so a theme can restyle their geometry (padding/height/font) via defineTheme instead of being unable to reach them at all. Both reflect size and status as data attributes, mirroring the root target. Default rendering is unchanged.
  • DropdownMenu: add submenus via a single DropdownMenuSubMenu component (or a nested items array in data mode). The row adopts DropdownMenuItem semantics (label / icon / description / isDisabled) and its children — or an items array — become the flyout content. Flyouts open inline-end with auto-flip, hover-intent, and full keyboard support (Right/Enter/Space opens and focuses the first item; Left/Escape closes and returns focus to the trigger).
  • Bordered inputs gain a statusVariant="tooltip" option that hides the status message box and surfaces the status as an info-tip on the on-field status icon. The icon is a real focusable button so the status is reachable by everyone: keyboard users tab to it (with a visible focus ring) and see the message on focus, pointer users see it on hover, and touch users tap to toggle it. The message is piped into both the input's and the button's aria-describedby, and the tooltip is dismissible with Escape. Added to TextInput, TextArea, NumberInput, DateInput, DateRangeInput, TimeInput, and FileInput.
  • The bordered input family now accepts a statusVariant prop ('attached' | 'detached', default 'attached') that forwards to the underlying Field, letting you float the status message below the input with spacing instead of overlapping it. Added to TextInput, TextArea, NumberInput, DateInput, DateRangeInput, TimeInput, Selector, MultiSelector, Typeahead, Tokenizer, FileInput, and PowerSearch. Non-breaking: the default matches today's behavior. (#4187)
  • Add RTL direction API: useDirection() hook, getLocaleDirection(locale) server-safe helper, and an optional dir prop on InternationalizationProvider.
  • RTL: mirror directional disclosure/navigation chevrons under RTL via a shared rtlStyles.mirror CSS transform, applied to the icon wrapper in Lightbox and the Table tree / grouped-rows / row-expansion plugins. The mirror composes correctly with the Table chevrons' state-rotation (expanded chevrons still point down under RTL). Semantic aria-labels are unchanged.
  • Selector & MultiSelector: add astryx-selector-clear-icon, astryx-selector-indicator-icon, astryx-multi-selector-clear-icon, and astryx-multi-selector-indicator-icon theme targets on the clear and chevron glyphs, so consumers can recolor, resize, and hover-style each icon — and style the chevron's open/closed state — via defineTheme instead of a fragile descendant selector or raw CSS. Each chevron reflects its open/closed state as a data-state attribute. Icon now fully handles its styling props (className, style, xstyle) so they compose with its base styles instead of being dropped. Default rendering is unchanged.
  • add size prop (sm / md) to Switch to match CheckboxInput and RadioList boolean control scales (#4230)
  • Table: rowIndexStart and rowCount props expose row numbering as a table-level ARIA concern, so aria-rowindex/aria-rowcount reflect a row's position in the full dataset: correct across pagination and even when no visible index column is rendered. Opt-in; tables that set neither prop are unchanged. Closes #3939.
  • Timestamp: new tooltipEntries prop renders the hover tooltip across several time zones and/or formats at once — one line per entry, each with an optional timezoneID (IANA id; omit it or pass 'local' for the viewer's zone), format (every non-relative TimestampFormat plus 'full'), and label. The default is unchanged: with no entries the tooltip stays the single full absolute line in the viewer's zone. Configuring entries also attaches the tooltip to absolute formats, which previously had none — note that this gives those timestamps a tab stop and focus ring, as relative timestamps already have, so a column of them gains one tab stop per row. hasTooltip={false} still suppresses the tooltip, and an empty array counts as no configuration. Also corrects isTimezoneShown's documentation, which claimed it applied to the system_date_time and system_time formats; it never has, and those formats stay machine-readable. (#4188)
  • Token: make the color prop extensible via module augmentation. TokenColor is now derived from a TokenColorMap interface, so theme packages can add custom colors (and astryx theme build generates the type augmentation), matching Badge and Button.
  • TreeList: the per-level indentation step is now the themeable --tree-list-indent variable (default var(--spacing-4)), so a theme can retune the indent metric via defineTheme on the tree-list target instead of the previously hardcoded, unreachable step (#4308).
  • TreeList: add a variant prop ('lineGuides' | 'noGuides', default 'lineGuides') to select the base hierarchy guide-line look. noGuides hides the connector lines while keeping indentation intact. Orthogonal to density (spacing); the guides stay themeable via the astryx-tree-list-guide target. Non-breaking — omitting the prop renders exactly as before.

Fixes

  • Avatar: compose the status dot's label into the avatar's accessible name so assistive tech can reach the status the role="img" root previously pruned (WCAG 4.1.2)
  • Calendar: expose selected state in day-button accessible names, announce range-selection progress and completion via the polite live region, and set aria-multiselectable on the grid in range mode
  • CommandPalette: announce result counts, empty, and loading states to screen readers via the shared polite live region (WCAG 4.1.3)
  • Divider: expose the label as the separator's accessible name via aria-labelledby; Spinner: name the status element from the visible label instead of duplicating it as aria-label
  • FileInput: announce the required state via a visually hidden description on the trigger (aria-required is unsupported on role="button") and announce validation errors exactly once
  • hooks: resolve focus-trap Escape by DOM depth instead of push order, exclude aria-hidden subtrees from trap tab cycles, and auto-clear live regions after announcing so stale status text does not linger
  • List: keep list semantics for all listStyle variants by always emitting an explicit role="list", since the base style strips list-style-type for every variant and Safari/VoiceOver drops implicit list roles for such lists (WCAG 1.3.1)
  • NumberInput: announce the units text through the input's accessible description, and stop TextInput/NumberInput from referencing the non-rendered status message id in aria-describedby inside InputGroup
  • reset: stop suppressing :focus-visible outlines on coarse-pointer devices so keyboard users keep the WCAG 2.4.7 focus indicator
  • hooks: auto-detect RTL direction for arrow-key navigation in useListFocus and useGridFocus (WCAG 1.3.2)
  • Slider: constrain range thumb aria-valuemin/aria-valuemax by the sibling thumb (including minStepsBetweenThumbs) and render the label as a group label wired via aria-labelledby instead of an inert
  • TopNav: disabled TopNavItems now render href-less anchors so they no longer navigate or fire clicks, and Outline's active item uses aria-current="location"
  • Avatar: avoid remounting the avatar subtree when the name tooltip toggles — render the tooltip as a conditional sibling instead of forking the return so the avatar keeps its position in the React tree (and its image-load state) across tooltip changes.
  • Card: rest the bordered variant on the subtle --color-border instead of --color-border-emphasized, so a Card's outer frame matches its own LayoutHeader/LayoutFooter dividers and neighboring ClickableCards instead of rendering a heavier edge.
  • CheckboxInput, RadioList, Switch: align control sizes. The visible checkbox and radio controls now fill their size exactly (20px at sm, 24px at md) instead of being inset 2px. The sm Switch track is now 32px wide with a 2px inset.
  • Export the BaseProps type through the @astryxdesign/core/BaseProps subpath. Previously it was only reachable through the package barrel, so the import type {BaseProps} from '@astryxdesign/core/BaseProps' specifier that astryx swizzle generates failed to resolve (#4091).
  • Guard DropdownMenu item hover styles with @media (hover: hover) to prevent sticky highlights on touch devices. Forward BaseProps pass-throughs to the menu element.
  • FieldStatus renders a leading status icon on the detached message so status is not conveyed by color/position alone (WCAG 1.4.1). The icon is decorative for assistive tech; the message text and live-region announcement carry the status. The attached variant is unchanged.
  • FileInput no longer nests interactive controls (the clear and status buttons) inside a role="button" trigger. The trigger is now a visually hidden button alongside them in a non-interactive container, resolving the nested-interactive a11y violation (WCAG 4.1.2) while keeping click, keyboard, and drag-and-drop behavior. (#4522)
  • Inputs no longer show the hover ring while disabled. The shared input wrapper's disabled state now suppresses both the base and status hover shadows, so TextInput, TextArea, NumberInput, DateInput, TimeInput, Selector, MultiSelector, Typeahead, and Tokenizer stay visually inert on hover when disabled.
  • HoverCard: move themeProps className to the layer container (where bg/radius/shadow live) so themes can target the visual surface. Forward consumer xstyle/className/style to that same layer container so surface customization lands next to the theme class, instead of silently dropping them.
  • With statusVariant="detached", bordered inputs no longer render a status icon inside the control (this also covers DateTimeInput, which is fixed to the detached presentation) — the detached message box already carries a leading icon, so the on-field glyph was a duplicate. Also centers the detached message's icon on the first line of text.
  • DropdownMenu/ContextMenu: mouse hover now moves the highlight instead of adding a second one, so keyboard focus and pointer hover share a single highlighted item (#4493)
  • utils: clamp plainDateAddMonths to the target month's last day Adding a month to Jan 31 landed on Mar 3 (Date#setMonth overflow) instead of Feb 28, so month arithmetic from end-of-month dates skipped February entirely. The helper now uses pure month arithmetic and clamps the day, matching Temporal.PlainDate.add and date-fns.
  • Calendar RTL: month-navigation chevrons now mirror correctly under RTL (via the shared rtlStyles.mirror transform on the nav-icon wrapper), and the range-selection / hover-preview fill pills use logical CSS (insetInline*, border*Start/EndRadius) so their rounded start/end caps follow the reading direction instead of the physical left/right. LTR rendering is unchanged.
  • Carousel now supports RTL: the directional scroll-button chevrons mirror under RTL, the scroll buttons respect RTL scroll semantics (previously the button was a no-op under RTL), and the button pills sit on the correct edges.
  • RTL: migrate physical left/right CSS properties to their logical equivalents so components mirror correctly under dir="rtl". This is the Phase 2 mechanical, one-to-one follow-up to the RTL direction API — a no-op in the default LTR direction with no visual change.
  • RTL Phase 4 (behavioral): mirror directional behavior that logical-CSS and icon name-swaps alone couldn't fix. SideNavCollapseButton and TreeListItem now compose rtlStyles.mirror on the icon wrapper outside the state rotation, so the chevrons point toward the correct edge in every collapsed/expanded × LTR/RTL combination. TreeList connector/guide lines position via logical inset-inline-start/inset-inline-end so they mirror to the inline-start (right) edge under RTL alongside the chevron and row indent. Slider positions its thumb, fill, and marks via logical inset-inline-start and flips the physical centering transform under RTL, and its pointer/click math measures the value fraction from the inline-start (right) edge under RTL — so a click at 25% of the track maps to 75 instead of 25.
  • RTL Phase 4b behavioral fixes: ChatMessageBubble grouped-bubble tail corners now use logical border radii so the tail follows reading direction (mirrors under RTL, text unaffected); Table sticky-column shadows make their translateX and gradient direction-aware so the shadow fades from the pinned edge toward scrolled content in both LTR and RTL instead of rendering inside-out, and gate shadow visibility on Math.abs(scrollLeft) so the start/end shadows still appear under RTL (where spec-compliant browsers report a negative scrollLeft); ResizeHandle's hit-area bias is now direction-aware (mirrors about center under RTL) and the pointer-drag delta reads the handle's computed direction so dragging resizes intuitively in RTL.
  • Markdown honors the components.image override for standalone (block) images, matching the inline image path. A standalone ![alt](src) line parses as a block image, whose render path previously hardcoded a bare <img> and ignored a supplied components.image; it now uses the override just like an inline image does.
  • Selector & MultiSelector: keep group headers visible while searching; hide groups with no matching items. Previously, typing a query flattened grouped options into a single ungrouped list; now each group header stays above its matching items and a group is hidden only when none of its items match.
  • SideNav: remove the top border above the footer region so the footer slot no longer renders a divider line.
  • Slider: round snapped values to the min/step decimal precision With fractional steps, min + steps * step accumulated binary floating-point error, so a keyboard nudge on a step={0.1} slider emitted 0.30000000000000004 through onChange/onChangeEnd (and into aria-valuenow/the value tooltip once the consumer echoed it back). Snapped values are now rounded to the combined decimal precision of min and step, which removes only the error — exact steps are unaffected.
  • Tooltip: dismiss the tooltip when its trigger is pressed. Previously the tooltip stayed open through a click (e.g. a "Copy link" button's tooltip lingered after activation); now pressing the trigger hides its own tooltip. Applies to uncontrolled tooltips only.
  • Typeahead: omit aria-activedescendant when search results are empty or index is out of bounds (#4059)

Documentation

  • document width prop across 17 input component doc files (#4163)

Other Changes

  • Add @astryx/no-physical-properties ESLint rule that flags physical left/right CSS properties inside stylex.create() and suggests the CSS logical equivalent for RTL support.
  • KEY-BASED: marginLeft/marginRight, paddingLeft/paddingRight, borderLeft/borderRight (+ their Width/Style/Color longhands), left/rightinsetInlineStart/insetInlineEnd, and the four physical corner radii → their diagonal-aware logical names (borderTopLeftRadiusborderStartStartRadius, etc.).
  • VALUE-BASED: textAlign: 'left'|'right', float: 'left'|'right', and clear: 'left'|'right' (the key stays, only the physical value is flagged).
  • Scoped strictly to stylex.create() — physical identifiers used elsewhere are ignored.
  • useDirection() returns 'ltr' | 'rtl' for the current provider context (falls back to 'ltr' when called outside a provider).
  • getLocaleDirection(locale) computes direction from a BCP 47 locale via Intl.Locale.getTextInfo() — safe to call from React Server Components and Next.js layouts to set <html dir>.
  • <InternationalizationProvider locale="ar"> auto-derives dir="rtl". Pass an explicit dir prop to override (useful for RTL testing under an English catalog, or to force LTR).
  • Pagination is the first component to consume the hook: prev/next chevron icons flip under RTL while the aria-labels stay semantic.
  • Storybook gains a global Direction toolbar for toggling every story between LTR and RTL.
  • Component-level CSS migrations (borders, chevrons, sliders, calendar range pills, etc.) land in follow-up PRs.
  • textAlign: 'left' | 'right''start' | 'end' (Selector, Typeahead, Chat trigger menu, DropdownMenu, CommandPalette, NavMenu items).
  • borderLeft*/borderRight*borderInlineStart*/borderInlineEnd*, kept as separate start/end declarations (Banner, Table cell/header dividers, DateRangeInput preset sidebar).
  • Static left/right positioning → insetInlineStart/insetInlineEnd for full-bleed overlays and single-side offsets (Button spinner overlay, Chat dock/blur/placeholder, Field sr-only label, Lightbox close/nav/counter buttons, TabList indicators, Thumbnail remove slot, CodeBlock copy button).
  • Inline marginLeft indentation → marginInlineStart (TreeList rows).

@astryxdesign/cli

Breaking Changes

  • cli/json: remove the central CLIAnyResponse, CLIResponseType, and CLIResponseDataMap types. jsonOut is now a structural serializer and parseResponse / assertResponse return the structural CLIResponse ({type, data, meta?}) instead of the discriminated union, so result.data is unknown until you narrow it yourself. Runtime output is unchanged (every --json envelope is byte-identical). This only affects consumers importing those types or relying on parseResponse / assertResponse to auto-narrow .data.
  • component/hook --json list responses collapsed. --detail compact/full previously emitted distinct component.brief/component.full (and hook.*) envelopes; they now all emit component.list (resp. hook.list) with a data.detail: 'names' | 'compact' | 'full' field. Migrate: switch on data.detail, not the .brief/.full discriminator. Removed types: ComponentBriefResponse, ComponentFullResponse, HookBriefResponse, HookFullResponse.

New Features

  • CLI: blog is now a normal, agent-facing command — it appears in --help and the capability manifest and supports --json (emitting blog.list / blog.detail envelopes), instead of being hidden. Human output is unchanged; the reader still consumes the public RSS feed. Also scriptable through the ./api barrel as blog(slug?).
  • CLI: init is now fully scriptable through the ./api barrel — the non-interactive installer (agent-docs cheat sheet, starter template, --remove-agents) lives in api/init and returns a typed receipt (init.run | init.remove), with the CLI reduced to a thin parse → API call → render wrapper. Human output is emitted through an injectable logger, so a scripted init() stays silent while the CLI output is byte-identical for existing usage.
  • CLI: theme build is now fully scriptable through the ./api barrel — the ~1,000-line theme compiler (defineTheme extraction, CSS generation via @astryxdesign/core/theme, variant/type-declaration + icon-module generation, override validation) lives in api/theme/build and returns a typed theme.build receipt, with the CLI reduced to a thin parse → API call → render wrapper. Human progress is emitted through an injectable logger, so a scripted themeBuild() stays silent while the generated CSS/JS/.d.ts, the --json envelope, and human output stay byte-identical for existing usage. Watch mode remains a thin CLI loop.
  • CLI: upgrade is now fully scriptable through the ./api barrel — the version-to-version pipeline (codemods + agent-docs refresh) lives in api/upgrade and returns a typed receipt (upgrade.list | upgrade.status | upgrade.run), with the CLI reduced to a thin parse → API call → render wrapper. Human progress is emitted through an injectable logger, so a scripted upgrade() stays silent while the CLI output and --json envelopes are unchanged for existing usage.
  • Timestamp: new tooltipEntries prop renders the hover tooltip across several time zones and/or formats at once — one line per entry, each with an optional timezoneID (IANA id; omit it or pass 'local' for the viewer's zone), format (every non-relative TimestampFormat plus 'full'), and label. The default is unchanged: with no entries the tooltip stays the single full absolute line in the viewer's zone. Configuring entries also attaches the tooltip to absolute formats, which previously had none — note that this gives those timestamps a tab stop and focus ring, as relative timestamps already have, so a column of them gains one tab stop per row. hasTooltip={false} still suppresses the tooltip, and an empty array counts as no configuration. Also corrects isTimezoneShown's documentation, which claimed it applied to the system_date_time and system_time formats; it never has, and those formats stay machine-readable. (#4188)

Fixes

  • astryx theme build: component-override keys for multi-word components (TextInput, DateInput, NumberInput, DropdownMenu, SideNav, TopNav, etc.) now match the hyphenated class the component actually renders. The known-component registry used de-hyphenated keys, so overrides authored against them emitted dead selectors (.astryx-textinput instead of .astryx-text-input) that silently never applied (#4109).

Other Changes

  • CLI: blog reorganized into api/blog leaf shape — list/detail leaves projecting a shared RSS adapter (_adapter.mjs owns all network fetch + feed parsing), with blog.mjs kept as a dispatcher+barrel so the same blog export, the CLI wrapper, api/index.mjs, and the --json/human output stay byte-identical.
  • CLI: build reorganized into the api/build leaf shape — build.mjs is now a dispatcher + barrel that routes no-query → build.help (api/build/help/help.mjs) and a query → build.kit (api/build/kit/kit.mjs), with each leaf projecting its single {type, data} envelope. Pure reorganization: the build export, the ./api barrel, and the CLI consumer are unchanged, and the --json and human output stay byte-identical for existing usage.
  • CLI: component reorganized into the api/component leaf shape over a shared _adapter resolver — component.mjs is now a dispatcher + barrel that routes to per-type leaves (list, detail, detail/props, detail/source, detail/showcase, detail/blocks), each a thin projection of a subject the adapter resolves once (core/external/scoped/integration ownership, ambiguity handling, and fuzzy search, deduped). Pure reorg: every --json envelope and human output stays byte-identical across all modes.
  • CLI: discover reorganized into api/discover leaf shape (list, detail, detail/doc, search) behind a shared _adapter that owns external-package discovery and doc loading; discover.mjs is now a dispatcher+barrel keeping the same exports. Pure reorg — --json and human output are byte-identical and api/index.mjs + the CLI consumer are untouched. Adds colocated leaf tests.
  • CLI: docs reorganized into api/docs leaf shape — docs() in api/docs/docs.mjs is now a dispatcher + barrel that routes by argument shape into three leaves (api/docs/list, api/docs/detail, api/docs/detail/section), each projecting into a single { type, data } envelope. The discovery, overlay loading, and topic resolution shared by ≥2 leaves live in api/docs/_adapter.mjs. Pure reorganization: the docs export, api/index.mjs, the CLI consumer, and all --json and human output are unchanged (byte-identical).
  • CLI: hook reorganized into api/hook leaf shape — hook.mjs is now a dispatcher+barrel routing to colocated leaves (list/list.mjs → hook.list, detail/detail.mjs → hook.detail, detail/params/params.mjs → hook.detail.params) over a shared _adapter.mjs resolver. Pure reorg: --json and human output are byte-identical across all modes, and the hook export surface (api/index.mjs + CLI) is unchanged.
  • CLI: init reorganized into api/init leaf shape — init.mjs is now a dispatcher + barrel that routes to api/init/run/run.mjs (the default / --features / --all install path) and api/init/remove/remove.mjs (the --remove-agents path), with the shared plain-logger contract in api/init/_adapter.mjs. Pure reorg: getNextSteps, noopInitLogger, and the InitOptions / InitLogger types stay re-exported from the barrel, so api/index.mjs, the CLI command, and the programmatic API are unchanged. Human and --json output are byte-identical.
  • CLI: layout reorganized into the api/layout leaf shape — a shared _adapter.mjs (analyze/loadBlocks/formatIssue over lib/xle) with thin expand/, check/, and grammar/ leaves, plus a layout.mjs barrel. api/index.mjs and the CLI are unchanged (they import via the barrel). Pure reorg: layout expand/check/grammar --json envelopes and human output are byte-identical.
  • CLI: swizzle reorganized into api/swizzle leaf shape — the flat command splits into api/swizzle/list (swizzle.list) and api/swizzle/copy (swizzle.copy receipt, incl. rewriteImports), with shared @astryxdesign/core discovery + component listing deduped in api/swizzle/_adapter.mjs, and swizzle.mjs reduced to a dispatcher + barrel that keeps its existing exports (swizzle, rewriteImports). Pure reorganization with no behavior change: human output and every --json envelope stay byte-identical, and the CLI command, the ./api barrel, and the central types/swizzle declarations are untouched.
  • CLI: template reorganized into api/template leaf shape (shared helpers preserved on the barrel). Pure reorg — --json and human output stay byte-identical: shared discovery/IO moved to api/template/_adapter.mjs, the command modes split into list/show/skeleton/copy leaves, and template.mjs becomes a dispatcher + barrel that re-exports every previously-exported symbol (template, discoverTemplates, discoverAll, discoverAllWithErrors, discoverIntegrationTemplatesForOne, findShowcase, findRelatedBlocks, stripTemplateAssetRefs, listTemplates, extractComponents, and the DiscoveredTemplate/TemplateDiscoveryError types) so component/layout/search/init/discover/validate-integration and lib/project keep resolving api/template/template.mjs unchanged.
  • CLI: theme add/list are reorganized into the fractal api/theme/ leaf shape — a shared _adapter.mjs (bundled-theme manifest reader + slug resolver) with thin add/ (copy → theme.add receipt) and list/ (theme.list) leaves over it, plus a theme.mjs barrel, mirroring the theme build extraction (#4462). themeList() is now exported from @astryxdesign/cli/api alongside themeAdd. Pure reorg: theme list/add --json envelopes and human output are byte-identical, with new direct-API tests for both leaves.
  • CLI: upgrade reorganized into api/upgrade leaf shape — the flat pipeline is split into a dispatcher+barrel (upgrade.mjs), a shared _adapter.mjs (version detection + agent-docs refresh + codemod selection/execution machinery), and list/status/run leaves (upgrade.list | upgrade.status | upgrade.run). Pure reorg: the ./api barrel + CLI consumer are unchanged, and both the human output and --json envelopes are byte-identical.

@astryxdesign/theme-neutral

Fixes

  • Neutral theme: express the light --color-border as #00000014 (translucent black) instead of the opaque #ebebeb. Same rendered color over a white surface, but it now blends over any background — matching the translucent dark-mode value.

Contributors

Thanks to everyone who contributed to this release:

  • @AKnassa
  • @arham766
  • @bhamodi
  • @cixzhang
  • @ernestt
  • @freddymeta
  • @HelloOjasMutreja
  • @humbertovirtudes
  • @josephfarina
  • @kentonquatman
  • @lexs
  • @nynexman4464

Full Changelog: https://github.com/facebook/astryx/compare/v0.1.9...v0.2.0

3 hours ago
mobx

mobx-react@10.0.0

Major Changes

  • 1926c69f53168619d688f348aa587e8f3ae579ae #4671 Thanks @kubk! - Release MobX 7, mobx-react-lite 5, and mobx-react 10.

    Bundle sizes are down: ESM prod 17.02 KiB gzip -> 13.96 KiB gzip; a minimal tree-shaken example is 10.32 KiB gzip now.

    It removes long-deprecated compatibility paths and keeps the React bindings split between mobx-react-lite for function components and mobx-react for class-component support.

    MobX 7

    MobX 7 is a cleanup release focused on the modern runtime and decorator model.

    • MobX now always uses Proxy-backed observable objects and arrays. The ES5/non-proxy fallback has been removed.
    • configure({ useProxies: ... }) is no longer supported.
    • { proxy: false } options for observable, observable.object, and observable.array are no longer supported.
    • Legacy decorators are no longer supported.
    • Namespaced annotation and comparer properties now use named exports to reduce bundle size:
    Removed API Replacement
    observable.ref observableRef
    observable.shallow observableShallow
    observable.deep observableDeep
    observable.struct observableStruct
    computed.struct computedStruct
    action.bound actionBound
    flow.bound flowBound
    comparer.identity compareIdentity
    comparer.default compareDefault
    comparer.structural compareStructural
    comparer.shallow compareShallow
    • The public trace API and its related runtime support have been removed. Use toJS, getDependencyTree, getObserverTree, spy or mobx-log package for debugging.

    mobx-react-lite 5 and mobx-react 10

    mobx-react-lite 5 and mobx-react 10 require MobX 7 and React 18 or later.

    mobx-react-lite remains the function-component package. mobx-react remains a thin wrapper around mobx-react-lite that adds class component and Stage 3 @observer class decorator support.

    • Keep function-component imports on mobx-react-lite if you do not need class component support.
    • Use mobx-react when you need class components or @observer class decorators.
    • mobx-react-lite supports function components and forwardRef; mobx-react delegates function components to mobx-react-lite and handles classes itself.
    • Remove React batching imports, including the stale React Native batching deep import. React 18+ renderers handle batching.

    The recommended public React binding surface for both packages is:

    • observer
    • Observer
    • useLocalObservable
    • enableStaticRendering
    • isUsingStaticRendering

    The following APIs have been removed from the React binding packages:

    • Provider, inject, and MobXProviderContext; use React.createContext directly.
    • disposeOnUnmount; dispose reactions in componentWillUnmount or return cleanup functions from useEffect.
    • PropTypes; use TypeScript or the regular prop-types package.
    • useObserver; wrap components with observer or use <Observer>.
    • useLocalStore; use useLocalObservable.
    • useAsObservableSource; synchronize values from props into local observable state explicitly.
    • useStaticRendering; use enableStaticRendering.
    • observerBatching, isObserverBatched, batchingForReactDom, batchingOptOut, and batchingForReactNative; remove these imports because React 18+ renderers handle batching.
    • Deprecated observer(fn, { forwardRef: true }); pass an already-created React.forwardRef(...) component to observer instead.
    • Legacy function-component contextTypes handling.

Patch Changes

3 hours ago
mobx

mobx-react-lite@5.0.0

Major Changes

  • 1926c69f53168619d688f348aa587e8f3ae579ae #4671 Thanks @kubk! - Release MobX 7, mobx-react-lite 5, and mobx-react 10.

    Bundle sizes are down: ESM prod 17.02 KiB gzip -> 13.96 KiB gzip; a minimal tree-shaken example is 10.32 KiB gzip now.

    It removes long-deprecated compatibility paths and keeps the React bindings split between mobx-react-lite for function components and mobx-react for class-component support.

    MobX 7

    MobX 7 is a cleanup release focused on the modern runtime and decorator model.

    • MobX now always uses Proxy-backed observable objects and arrays. The ES5/non-proxy fallback has been removed.
    • configure({ useProxies: ... }) is no longer supported.
    • { proxy: false } options for observable, observable.object, and observable.array are no longer supported.
    • Legacy decorators are no longer supported.
    • Namespaced annotation and comparer properties now use named exports to reduce bundle size:
    Removed API Replacement
    observable.ref observableRef
    observable.shallow observableShallow
    observable.deep observableDeep
    observable.struct observableStruct
    computed.struct computedStruct
    action.bound actionBound
    flow.bound flowBound
    comparer.identity compareIdentity
    comparer.default compareDefault
    comparer.structural compareStructural
    comparer.shallow compareShallow
    • The public trace API and its related runtime support have been removed. Use toJS, getDependencyTree, getObserverTree, spy or mobx-log package for debugging.

    mobx-react-lite 5 and mobx-react 10

    mobx-react-lite 5 and mobx-react 10 require MobX 7 and React 18 or later.

    mobx-react-lite remains the function-component package. mobx-react remains a thin wrapper around mobx-react-lite that adds class component and Stage 3 @observer class decorator support.

    • Keep function-component imports on mobx-react-lite if you do not need class component support.
    • Use mobx-react when you need class components or @observer class decorators.
    • mobx-react-lite supports function components and forwardRef; mobx-react delegates function components to mobx-react-lite and handles classes itself.
    • Remove React batching imports, including the stale React Native batching deep import. React 18+ renderers handle batching.

    The recommended public React binding surface for both packages is:

    • observer
    • Observer
    • useLocalObservable
    • enableStaticRendering
    • isUsingStaticRendering

    The following APIs have been removed from the React binding packages:

    • Provider, inject, and MobXProviderContext; use React.createContext directly.
    • disposeOnUnmount; dispose reactions in componentWillUnmount or return cleanup functions from useEffect.
    • PropTypes; use TypeScript or the regular prop-types package.
    • useObserver; wrap components with observer or use <Observer>.
    • useLocalStore; use useLocalObservable.
    • useAsObservableSource; synchronize values from props into local observable state explicitly.
    • useStaticRendering; use enableStaticRendering.
    • observerBatching, isObserverBatched, batchingForReactDom, batchingOptOut, and batchingForReactNative; remove these imports because React 18+ renderers handle batching.
    • Deprecated observer(fn, { forwardRef: true }); pass an already-created React.forwardRef(...) component to observer instead.
    • Legacy function-component contextTypes handling.
3 hours ago
mobx

mobx@7.0.0

Major Changes

  • 1926c69f53168619d688f348aa587e8f3ae579ae #4671 Thanks @kubk! - Release MobX 7, mobx-react-lite 5, and mobx-react 10.

    Bundle sizes are down: ESM prod 17.02 KiB gzip -> 13.96 KiB gzip; a minimal tree-shaken example is 10.32 KiB gzip now.

    It removes long-deprecated compatibility paths and keeps the React bindings split between mobx-react-lite for function components and mobx-react for class-component support.

    MobX 7

    MobX 7 is a cleanup release focused on the modern runtime and decorator model.

    • MobX now always uses Proxy-backed observable objects and arrays. The ES5/non-proxy fallback has been removed.
    • configure({ useProxies: ... }) is no longer supported.
    • { proxy: false } options for observable, observable.object, and observable.array are no longer supported.
    • Legacy decorators are no longer supported.
    • Namespaced annotation and comparer properties now use named exports to reduce bundle size:
    Removed API Replacement
    observable.ref observableRef
    observable.shallow observableShallow
    observable.deep observableDeep
    observable.struct observableStruct
    computed.struct computedStruct
    action.bound actionBound
    flow.bound flowBound
    comparer.identity compareIdentity
    comparer.default compareDefault
    comparer.structural compareStructural
    comparer.shallow compareShallow
    • The public trace API and its related runtime support have been removed. Use toJS, getDependencyTree, getObserverTree, spy or mobx-log package for debugging.

    mobx-react-lite 5 and mobx-react 10

    mobx-react-lite 5 and mobx-react 10 require MobX 7 and React 18 or later.

    mobx-react-lite remains the function-component package. mobx-react remains a thin wrapper around mobx-react-lite that adds class component and Stage 3 @observer class decorator support.

    • Keep function-component imports on mobx-react-lite if you do not need class component support.
    • Use mobx-react when you need class components or @observer class decorators.
    • mobx-react-lite supports function components and forwardRef; mobx-react delegates function components to mobx-react-lite and handles classes itself.
    • Remove React batching imports, including the stale React Native batching deep import. React 18+ renderers handle batching.

    The recommended public React binding surface for both packages is:

    • observer
    • Observer
    • useLocalObservable
    • enableStaticRendering
    • isUsingStaticRendering

    The following APIs have been removed from the React binding packages:

    • Provider, inject, and MobXProviderContext; use React.createContext directly.
    • disposeOnUnmount; dispose reactions in componentWillUnmount or return cleanup functions from useEffect.
    • PropTypes; use TypeScript or the regular prop-types package.
    • useObserver; wrap components with observer or use <Observer>.
    • useLocalStore; use useLocalObservable.
    • useAsObservableSource; synchronize values from props into local observable state explicitly.
    • useStaticRendering; use enableStaticRendering.
    • observerBatching, isObserverBatched, batchingForReactDom, batchingOptOut, and batchingForReactNative; remove these imports because React 18+ renderers handle batching.
    • Deprecated observer(fn, { forwardRef: true }); pass an already-created React.forwardRef(...) component to observer instead.
    • Legacy function-component contextTypes handling.

Patch Changes

4 hours ago
react-intersection-observer

v11.0.0

v11.0.0

v11 delivers a ground-up observer lifecycle rewrite, making observation and cleanup more resilient across React 17, 18, and 19. Shared callback-ref handling, idempotent cleanup, and improved threshold behavior make hooks more predictable in real-world mounting and unmounting scenarios.

It also introduces a new Blume-powered documentation site with clearer guides and examples. Storybook and the README have been refreshed to make getting started easier.

Smaller improvements include private vulnerability reporting, stronger PR quality checks with Fallow, dependency updates, and expanded observer lifecycle tests.

What's Changed

Full Changelog: https://github.com/thebuilder/react-intersection-observer/compare/v10.1.0...v11.0.0

11 hours ago
vite

create-vite@9.1.2

Please refer to CHANGELOG.md for details.

11 hours ago
vite

v8.2.0

Please refer to CHANGELOG.md for details.

16 hours ago
Babylon.js

9.19.0

Core

  • Restore transitive side-effect registrations - [Bug Fix] by RaananW (#18751)

Loaders

  • Restore transitive side-effect registrations - [Bug Fix] by RaananW (#18751)
20 hours ago
wangEditor-next

v6.1.1

What's Changed

  • @wangeditor-next/basic-modules@6.1.1
  • @wangeditor-next/code-highlight@6.1.1
  • @wangeditor-next/core@6.1.1
  • @wangeditor-next/list-module@6.1.1
  • @wangeditor-next/table-module@6.1.1
  • @wangeditor-next/upload-image-module@6.1.1
  • @wangeditor-next/video-module@6.1.1
Package versions
Package Version Source
@wangeditor-next/basic-modules 6.1.1 Source (tar.gz)
@wangeditor-next/code-highlight 6.1.1 Source (tar.gz)
@wangeditor-next/core 6.1.1 Source (tar.gz)
@wangeditor-next/editor 6.1.1 Source (tar.gz)
@wangeditor-next/editor-for-react 6.1.1 Source (tar.gz)
@wangeditor-next/editor-for-vue 6.1.1 Source (tar.gz)
@wangeditor-next/editor-for-vue2 6.1.1 Source (tar.gz)
@wangeditor-next/list-module 6.1.1 Source (tar.gz)
@wangeditor-next/plugin-attachment 6.1.1 Source (tar.gz)
@wangeditor-next/plugin-ctrl-enter 6.1.1 Source (tar.gz)
@wangeditor-next/plugin-float-image 6.1.1 Source (tar.gz)
@wangeditor-next/plugin-formula 6.1.1 Source (tar.gz)
@wangeditor-next/plugin-link-card 6.1.1 Source (tar.gz)
@wangeditor-next/plugin-markdown 6.1.1 Source (tar.gz)
@wangeditor-next/plugin-mention 6.1.1 Source (tar.gz)
@wangeditor-next/table-module 6.1.1 Source (tar.gz)
@wangeditor-next/upload-image-module 6.1.1 Source (tar.gz)
@wangeditor-next/video-module 6.1.1 Source (tar.gz)
@wangeditor-next/yjs 6.1.1 Source (tar.gz)
@wangeditor-next/yjs-for-react 6.1.1 Source (tar.gz)
@wangeditor-next/yjs-for-vue 6.1.1 Source (tar.gz)