Skip to content

Release prerelease packages (next) - #3041

Merged
TomTomB merged 1 commit into
nextfrom
changeset-release/next
Aug 2, 2026
Merged

Release prerelease packages (next)#3041
TomTomB merged 1 commit into
nextfrom
changeset-release/next

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to next, this PR will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

next is currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, run changeset pre exit on next.

⚠️⚠️⚠️⚠️⚠️⚠️

Releases

@ethlete/components@1.0.0-next.33

Major Changes

  • #3041 df55f32 Thanks @github-actions! - Bracket: layouts are opt-in values you register, so an app bundles only the renderers it draws with.
    Pass factories to provideBracketConfig({ layouts }) or the layouts input on either host. The
    layout input and BracketConfig.swiss are gone - mirrored is a layout, swiss options live on
    swissBracketLayout() - and an unregistered mode throws ET3413.

    - provideBracketConfig({ swiss: { colors } });
    - <et-bracket layout="mirrored" [source]="source()" />
    + provideBracketConfig({ layouts: [mirroredSingleEliminationBracketLayout(), swissBracketLayout({ colors })] });
    + <et-bracket [source]="source()" />
  • #3041 beec05f Thanks @github-actions! - Breadcrumb: collapsing the trail is now opt-in. Import BREADCRUMB_COLLAPSE_IMPORTS and apply etBreadcrumbCollapse to the breadcrumb, the outlet, or any ancestor to keep the overflow control; without it the trail is clipped and the toggletip's overlay runtime stays out of your bundle.

  • #3041 beec05f Thanks @github-actions! - Grid: GridDebugComponent moved out of GRID_IMPORTS into GRID_DEBUG_IMPORTS, so the development-only overlay no longer ships in production bundles. Import that barrel where you use <et-grid-debug />.

  • #3041 caa8c92 Thanks @github-actions! - Query error: labels default to English only — the German status tables are no longer bundled or auto-selected by locale. Keep the old behavior with provideQueryErrorLabels(queryErrorLabelsForLocale) (or GERMAN_QUERY_ERROR_LABELS); the migrate-query-error-labels generator finds affected sites.

  • #3041 6be90f2 Thanks @github-actions! - Rich text editor: the link editor popover is opt-in via provideRichTextEditorLinkEditor() — without
    it the link tool falls back to prompt(). Run
    nx g @ethlete/components:migrate-rich-text-editor-link-editor to find affected editors.

  • #3041 a0e5424 Thanks @github-actions! - Rich text editor: the 'heading' block-style menu is now an opt-in tool -
    provideRichTextEditorHeadingTool(), like the align/table/image tools. It stays in the default toolbar,
    so that call is all it takes; without it no block-style control renders (Markdown # autoformat is
    unaffected). It was the only default tool needing the menu system, worth 8.5 kB gz to every editor.

  • #3041 2c0d3c9 Thanks @github-actions! - Scrollable: the buttons, dots, drag and snap are now opt-in directives on the <et-scrollable> itself, so a plain track no longer bundles them. Replace renderButtons / buttonPosition / stickyButtons with [etScrollableButtons] (SCROLLABLE_NAVIGATION_IMPORTS), renderNavigation with etScrollableNavigation, snap / snapOrigin / cursorDragScroll with etScrollableSnap / etScrollableDrag (SCROLLABLE_DRAG_IMPORTS), and darkenNonIntersectingItems with etScrollableDarken (SCROLLABLE_DARKEN_IMPORTS). ScrollableMasksDirective / ScrollableButtonsDirective / ScrollableNavigationDirective are renamed to …Component; the directive names now belong to the opt-ins.

  • #3041 beec05f Thanks @github-actions! - Stream: STREAM_IMPORTS now holds only the shared consent, loading, error and slot pieces. Add the barrel of each platform you embed (STREAM_YOUTUBE_IMPORTS, STREAM_TWITCH_IMPORTS, … STREAM_SOOP_IMPORTS) and STREAM_PIP_IMPORTS for picture-in-picture - or STREAM_ALL_IMPORTS to keep the old contents. A YouTube-only app saves ~5 kB gz.

Minor Changes

  • #3041 1f528bd Thanks @github-actions! - Accordion: add preventCloseLast to the group - the header can no longer collapse the last open
    panel, so paired with autoCloseOthers the group behaves like a radio set. close(), closeAll()
    and [(isOpen)] still collapse it.

  • #3041 c796f12 Thanks @github-actions! - Bracket: add density="compact" - narrower columns, and match cards that answer with a code and a
    score, for a full bracket inside an article column. Layout inputs are now overrides on top of it, so
    an unbound input resolves through the preset instead of a fixed default.

  • #3041 568e937 Thanks @github-actions! - Bracket: mirroredDoubleEliminationBracketLayout() draws double elimination as stacked winners and
    losers blocks, each folded around its own centre on a shared middle column, with the deciding rounds
    chained below. Also fixes hovering a card lighting the wrong participant's journey, and a mirrored
    bracket drawing its way-back connectors backwards.

  • #3041 35d4f03 Thanks @github-actions! - Bracket: journeys are now per participant. Hovering one side of a card lights that participant's path
    alone and marks where they went out, and [(focusedParticipantId)] pins a path for touch and keyboard

    • driven from a control of yours, cleared with Escape. Match cards mark each side with
      data-participant-id.
  • #3041 a8dd388 Thanks @github-actions! - Bracket: add <et-bracket-rounds-list>, the same source drawn as a vertical round-by-round list
    (sectioned for double elimination), plus bracketNaturalWidth() / bracketFitsWidth() to decide when
    to swap to it on a narrow screen.

  • #3041 fba7ed8 Thanks @github-actions! - Breadcrumb: add etBreadcrumbSeo (BREADCRUMB_SEO_IMPORTS) - opt-in schema.org BreadcrumbList
    JSON-LD, which is what earns a site the breadcrumb line in a search result. Crumbs state their own
    name and url through new inputs on etBreadcrumbItemTemplate; loading and unnamed crumbs are
    skipped, and the last crumb needs no url.

  • #3041 06a6ba2 Thanks @github-actions! - Calendar: comparisonStart / comparisonEnd band a compared period under the selection - the
    analytics "vs. the previous 30 days" pattern - and the date range input forwards them. It is
    presentation only, so picking never writes to it. Cells expose data-comparison-band, and
    comparisons band at the calendar's precision.

  • #3041 d97e71a Thanks @github-actions! - Calendar: the header is replaceable, and now moves with the grid it names.

    • ng-template etCalendarHeader projected into et-calendar renders instead of the default header,
      with the headless directive as its context; et-calendar also exposes it as headless.
    • The label travels with the rows, the caret no longer swings with the label's width, grids crossfade
      rather than cut, and the picker's bottom sheet keeps one height.
    • Fixed: the calendar warned NG0956 twice per navigation in dev.
  • #3041 8ff5062 Thanks @github-actions! - Calendar: monthsShown renders several months side by side - the classic two-month range picker,
    where a range spanning the turn of a month is one gesture. The span shares one keyboard scope, one
    selection and a band that runs through the seam, and stepping moves by a single month. Headless:
    monthPages(). The date inputs deliberately don't forward it.

  • #3041 8692c2c Thanks @github-actions! - Calendar: mode="multiple" selects a set of unrelated dates into its own multipleValue model
    (Date[], kept ascending). Picking a date again removes it, nothing bands or previews, and the grid
    is aria-multiselectable. It composes with precision. The date inputs have no equivalent - their
    value is one wire string.

  • #3041 35c463c Thanks @github-actions! - Calendar and date inputs: precision ('day' | 'month' | 'year') makes them month or year pickers -
    picking in that grid writes the value (the start of the unit) instead of drilling further, and ranges
    compare, band and complete at the same unit. On et-date-input / et-date-range-input it also
    derives the text format, so displayFormat now defaults to null.

  • #3041 c41beec Thanks @github-actions! - Calendar: rangeSelectionStrategy decides what a pick means in range mode, forwarded by the date
    range input. A strategy is two pure functions of (date, currentRange) - select, and the optional
    preview for what to band on hover. createWeekRangeStrategy({ weekStartsOn }) snaps to whole weeks
    and createFixedLengthRangeStrategy({ days }) makes every pick a complete span.

  • #3041 d5012e1 Thanks @github-actions! - Add startAt to the calendar: where an empty calendar opens and which day takes the
    initial roving focus (e.g. next month for a booking form). A selection or an explicit
    activeMonth still wins over it, and without any of the three the calendar opens on
    today. et-date-input, et-date-range-input and et-date-time-input forward it to
    their picker calendar.

  • #3041 d9b05fc Thanks @github-actions! - Calendar: the header label is a button that zooms the day grid out to months and then years, and
    picking one drills back in; startView decides where it opens, forwarded by the three date inputs. A
    coarse pick only navigates, reported as monthSelect / yearSelect. min/max/dateFilter and the
    keyboard model reach every view, and the new dateClass puts classes of your own on any cell.

  • #3041 cbd68e0 Thanks @github-actions! - Calendar: weekNumbers renders a leading week-number column on the day grid, forwarded by the date,
    date-range and date-time inputs. The numbering is localized rather than always ISO, so it names the
    rows actually on screen. Each number is its row's rowheader, and --et-calendar-week-number-size
    sizes the column.

  • #3041 62b03f9 Thanks @github-actions! - Carousel & Scrollable: much smoother swiping on a phone - 85% less style recalculation and 88% less
    paint with transition="wipe", and no observer work during a scroll. Snapping is native CSS scroll
    snap (ScrollableDirective.suspendSnap() holds it off while something writes an offset itself), and
    the built-in transitions run as composited keyframes. New transition="custom" fills
    --et-carousel-slide-progress without applying an effect, for CSS of your own; new
    --et-carousel-wipe-dim-color; signalElementChildren / signalElementScrollState take a
    mutations option to narrow their observers.

  • #3041 cb1c5b0 Thanks @github-actions! - Bracket: the placeholder cards are now real - compact et-match-card cells, a hero final card with a
    champion line, heading round headers (roundHeaderLevel) and a labelled continue cell. They need
    provideBracketConfig({ matchNormalizer }) to read your match data (normalizeEthleteBracketMatch ships
    for Ethlete feeds), and finalColumnWidth / finalMatchHeight now default to 360 / 200 to fit them.

  • #3041 9057738 Thanks @github-actions! - Add the match domain behind MATCH_CARD_IMPORTS: <et-match-card> (one card, three container-query layouts -
    dense row, featured card, wide row; size pins one; put it on an <a> to make the whole card the link),
    <et-match-participant>, the headless etMatchCard directive with its score/meta/game-score parts,
    provideMatchLabels(), and normalizeEthleteMatch() - cards take a NormalizedMatch, so any backend maps in
    with a plain adapter.

  • #3041 0d30c38 Thanks @github-actions! - Match card: live scores now roll when they change - old value out, new value in, with a flash on the side
    that scored - plus a scoreChange output carrying the side and delta for your own effects. Only while the
    match is live, never on first render, instant under reduced motion; animateScoreChanges turns it off.

  • #3041 fd8ac2f Thanks @github-actions! - Add the standings table behind STANDINGS_IMPORTS: <et-standings> draws a real <table> from
    NormalizedStandingRows (any backend maps in; normalizeEthletePlacement ships for Ethlete feeds), bands
    position zones in your own color themes and draws their legend from the same config, drops columns rather
    than scrolling on narrow widths, and can single out one row.

  • #3041 26a987f Thanks @github-actions! - Form field: an [etIcon] projected into [etInputPrefix] / [etInputSuffix] is now sized by the
    shell (--et-form-field-affix-icon-size, 16px) - no size class needed, matching the other
    in-field icons.

  • #3041 d97e71a Thanks @github-actions! - Icon: add a label input. An icon stays aria-hidden by default - it usually repeats the text beside
    it - but a lone status glyph is the content, and label turns the host into a named role="img" so
    the meaning survives for a screen reader.

  • #3041 d97e71a Thanks @github-actions! - Menu: add loop (default true, the current behaviour). Turn it off and the arrow keys stop at the
    ends instead of wrapping, which reads better in a long menu. A menu with a search field is
    unaffected - its ends hand focus back to the field either way.

  • #3041 f0082cd Thanks @github-actions! - Notification upgrades:

    • manager.promise(work, { loading, success, error }) follows a promise, an observable or an @ethlete/query query in one toast.
    • id in the config replaces a live notification instead of stacking a duplicate.
    • Status icons (overridable per notification via icon), plus secondaryAction for an action pair.
    • Swipe/flick a notification away; opt out with swipeToDismiss: false.
  • #3041 0e08bc2 Thanks @github-actions! - Pagination: add <et-page-size-select> (PAGE_SIZE_SELECT_IMPORTS) - the "Items per page" control
    that completes the Material-style controls row beside a compact paginator. A native <select>, so it
    pulls in nothing; a separate component, because page size is the app's state rather than the
    paginator's. Changing the size deliberately does not reset the page. Two new label keys, pageSize
    and pageSizeOption.

  • #3041 38b3c2b Thanks @github-actions! - Rich text editor: undo/redo over the Markdown value, replacing the browser's native
    contenteditable history (which could restore states the value never had). Ctrl/Cmd+Z, Ctrl+Y and
    the platform's own undo all route into it, plus new 'undo' / 'redo' toolbar tools that lead the
    default toolbar. Typing goes back word by word; a paste, autoformat or tool rewrite in one step.

  • #3041 1c7ad03 Thanks @github-actions! - Rich text editor: provideRichTextEditorImageTool({ upload }) embeds images as ![alt](url) - pick,
    paste or drop a file, uploaded by your handler (a promise, an observable, or a createDropzoneUpload
    config for real progress), with a placeholder that never touches the value and a popover for alt text.
    Tool definitions gained paste, drop and click content hooks; without the tool, pasted image
    files are refused rather than becoming blob: URLs in the value.

  • #3041 48fbe62 Thanks @github-actions! - Rich text editor: pasted text that spells a token out - #First name, the trigger char plus an
    item's label or id - comes back as a real chip, for HTML and plain-text clipboards alike (opt out with
    parsePastedTokens="false"). A trigger with a static items list no longer needs resolveItem to
    render chip labels.

  • #3041 7e444d6 Thanks @github-actions! - Rich text editor: block quote and fenced code block tools ('blockquote' / 'codeBlock', also
    typed as > / ```), both in the default toolbar. Quotes nest with Tab/Shift+Tab; a code block
    holds literal text, so the marks that can't serialize inside one disable themselves. htmlToMarkdown
    / markdownToHtml now round-trip nested quotes (>>).

  • #3041 b3673f3 Thanks @github-actions! - Selection lists: add <et-checkbox-group-select-all>, the prebuilt tri-state select-all row that had
    to be hand-rolled until now - a real role="checkbox" with aria-checked="mixed", taking its text
    from the new shared selectAll form label. Also orientation="horizontal" on et-checkbox-group and
    et-radio-group, flowing the options in a wrapping row.

  • #3041 84a8d00 Thanks @github-actions! - Sliders: orientation="vertical" turns et-slider / et-range-slider (and the headless etSlider /
    etRangeSlider) into a bottom→up slider, its length set by --et-slider-vertical-size. marks
    renders ticks on the track - true for one per step, or an array of { value, label? } stops - and
    snapToMarks moves commits and keyboard steps mark to mark instead of along the step grid.

  • #3041 41c2683 Thanks @github-actions! - Table: add CSV export - TABLE_CSV_EXPORT_IMPORTS / etTableCsvExport for a button of your own, or
    injectTableCsvExport() / tableToCsv() from TypeScript. It writes the visible columns and the
    table's own rows by default (exportValue gives a column its text form), rows also takes a provider
    function, tableCsvRowsFromPages({ fetchPage }) walks a paginated endpoint, and file saves a CSV the
    server built instead. A server-paginated table that would silently export a single page is a dev-mode
    error (ET3506) unless you pass partial: true.

  • #3041 e5ffd4d Thanks @github-actions! - Table: add etTableInlineEdit (TABLE_INLINE_EDIT_IMPORTS) - inline cell editing. Mark a column
    editable and give it an etTableCellEdit template, whose context is the draft as a signal-forms
    field, so any of the library's controls is an editor with a plain [formField] binding. Double-click
    or Enter starts, Enter saves, Escape restores, Tab saves and moves on; cellCommit reports
    { row, column, previous, next } and the mutation stays yours.

  • #3041 040bbb3 Thanks @github-actions! - Table: add etTableKeyboardNav (TABLE_KEYBOARD_NAV_IMPORTS) - arrow-key navigation over the body's
    cells following the ARIA grid pattern, with Home/End, Ctrl+Home/End and PageUp/PageDown. The body
    becomes a single tab stop; Enter drills into a cell's own control and Escape comes back out.
    Composes with virtual scrolling.

  • #3041 255bebc Thanks @github-actions! - Time picker: etTimePicker / et-time-picker take min, max and timeFilter, matching the
    calendar's bounds, and et-time-input / et-date-time-input forward them as minTime / maxTime /
    timeFilter. Availability is per column - an hour is disabled only when no minute inside it is
    selectable - unselectable options stay in place and the keyboard steps over them, and picking a part
    moves the finer ones to the first value that works, including the hour behind an AM/PM pick.

Patch Changes

  • #3041 6c9d38d Thanks @github-actions! - Overlay runtime: build anchored strategies with anchoredOverlayPosition({ referenceElement, … })
    instead of a { kind: 'anchored', … } literal - it is what pulls @floating-ui/dom in, so apps
    that only center dialogs no longer bundle it (~7 kB gz). autoResize, autoHide,
    autoCloseIfReferenceHidden and arrows additionally need enableAnchoredOverlayPositionExtras().

  • #3041 d97e71a Thanks @github-actions! - Fix <et-carousel> autoplaying by default: autoplay is the component's own input now and defaults
    to false, which is what it always documented. Add autoplay to a carousel that should play. On the
    headless directive, read the new isEnabled() for what is in effect.

  • #3041 833b579 Thanks @github-actions! - et-match-participant now takes an attribute form (<a et-match-participant> / <button …>), so a player or
    team card can be the click target itself. On an interactive host it names itself after the participant - the
    link would otherwise read "FC Berlin emblem FC Berlin" - takes the shared focus ring, and drops the button
    chrome. et-match-card already worked this way.

  • #3041 8609171 Thanks @github-actions! - Docs: add a Sport UI recipes guide - the today's-matches rail (built on et-scrollable, which is why
    et-match-list was never shipped as a component) plus competition, team, player and nation cards, each with
    a live story to copy from.

  • #3041 8f0e42a Thanks @github-actions! - Form field: the text-field shell, rich-text, textarea, hint and counter CSS now ships with the
    control that uses it, so a field holding only a checkbox, switch or slider no longer pulls the
    whole form-field stylesheet. No API change; chrome renders as before.

  • #3041 2c0d3c9 Thanks @github-actions! - Choice field's card variant, the carousel autoplay chrome and the cascader's bottom-sheet
    presentation now inject their CSS only once that feature is actually used.

  • #3041 353777b Thanks @github-actions! - Mark build-tooling peer dependencies (vite, typescript, ts-morph, @nx/devkit, @analogjs/*) and feature-scoped runtime peers (date-fns in components) as optional via peerDependenciesMeta. They are only needed when running the Nx generators or using the date/time components - consumers no longer have to install them just to use the libraries.

  • #3041 95c3d2f Thanks @github-actions! - Overlay: --et-overlay-body-padding-block now reserves real space at the end of a scrolling body. Its end value used to be swallowed by the scroll container, leaving the last child's border and focus ring clipped against the divider once scrolled to the bottom.

  • #3041 f59128f Thanks @github-actions! - createOverlayUnsavedChangesGuard stops vetoing closes once its tracker was abandoned (a logout), so the overlay closes instead of prompting over a page the user is being redirected away from. It also inherits the tracker's tab guard - the beforeunload lock is on by default, with the title marker / blink / favicon / badge extras available through the tab option.

  • #3041 2c0d3c9 Thanks @github-actions! - Overlay: the default enter/leave animation CSS now ships with the strategy that uses it
    (stylesComponent on the breakpoint config), so an app only bundles the animations for the overlay
    kinds it opens. Overlays that hand-roll a layout containerClass instead of using a built-in
    strategy must now provide their own animation CSS.

  • #3041 8b13854 Thanks @github-actions! - Query client: multi-tab sync and response persistence are opt-in features instead of defaults - the
    multiTabSync / persistence client options are gone and a client without the features ships neither
    engine. Migrate with nx g @ethlete/query:migrate-query-client-features.

    • withMultiTabSync() shares reads, polls a cache key in one tab for all of them and refreshes the
      others after a mutation; per-query multiTabSync: false keeps a query tab-local.
    • withQueryPersistence() keeps public reads in IndexedDB, so a reload renders the last known data
      while it revalidates. Secure responses need an explicit opt-in and are removed on logout.
    • refreshQueriesInUse() also refreshes GraphQL queries transported over POST; devtools gain Sync
      and Disk columns.
  • #3041 8422cf0 Thanks @github-actions! - Rich text editor: fix escaping a code block that sits flush against the start or end of the content,
    where there is no line to move to. ArrowUp off the first line and ArrowDown off the last now create
    the paragraph they would move to, and a second Enter on the empty last line leaves the block.

  • #3041 1c7ad03 Thanks @github-actions! - Rich text editor: the docked (touch) toolbar no longer leaves a gap between itself and the on-screen
    keyboard, however much the browser over-reports the keyboard's height, and it re-checks while the
    keyboard is up in case a viewport event never arrives. A page that opted into the VirtualKeyboard API
    gets env(keyboard-inset-height) instead of the measurement.

  • #3041 42ec970 Thanks @github-actions! - DI: createProvider / createRootProvider / createStaticProvider / createStaticRootProvider /
    createLabels are replaced by defineProvider & co., which return a definition you read with
    toProvideFn / toInjectFn / toToken; createQueryClient, createBearerAuthProvider and
    createWebSocketClient return that definition instead of a tuple. Every provideX / injectX /
    token export keeps its name - run nx g @ethlete/core:migrate-provider-shape for your own call sites.
    Cuts the @ethlete/components import floor from 89.9 to 2.4 kB gz.

@ethlete/contentful@4.0.0-next.7

Major Changes

  • #3041 9c71ed3 Thanks @github-actions! - The built-in embedded components now only exist when provideContentfulConfig() is in scope - without it embedded assets are skipped and hyperlinks render as plain <a href>. Apps that render embedded content must add the provider (no arguments is enough). In exchange, ContentfulLinkComponent and text-only rich text no longer bundle the image/video/audio/file components.

  • #3041 9c71ed3 Thanks @github-actions! - Rich text: marks now render as semantic elements (<strong>, <em>, <u>, <code>, <s>, <sub>, <sup>) instead of Tailwind classes; marks inside hyperlinks become et-contentful-rich-text-mark-* classes on the link's textClass. marksToClass changed accordingly, marksToTags is new.

  • #3041 0817cc8 Thanks @github-actions! - Contentful v5: the package peers on @ethlete/components instead of @ethlete/cdk (and drops
    @angular/cdk and rxjs). et-contentful-image renames hasPriority to priority and loses its
    *Class inputs - style the static et-picture-* classes instead. The rich text renderer now diffs
    keyed, so element DOM and embedded component instances survive updates and reorders; the
    useTailwindClasses option is gone. Run nx g @ethlete/contentful:migrate-to-contentful-v5.

Patch Changes

  • #3041 9c71ed3 Thanks @github-actions! - Smaller bundles: the rich-text renderer no longer pulls the @contentful/rich-text-types runtime enums (~2.4 kB gz), and the renderer error codes plus GQL_FRAGMENT_CONTENTFUL_ASSET are now droppable literals. @contentful/rich-text-types stays a peer dependency for its types.

  • #3041 353777b Thanks @github-actions! - Mark build-tooling peer dependencies (vite, typescript, ts-morph, @nx/devkit, @analogjs/*) and feature-scoped runtime peers (date-fns in components) as optional via peerDependenciesMeta. They are only needed when running the Nx generators or using the date/time components - consumers no longer have to install them just to use the libraries.

  • #3041 353777b Thanks @github-actions! - Adopt the @ethlete/eslint-plugin styleguide flat configs in core, query, contentful and
    types, and apply the resulting auto-fixes. Runtime behavior is unchanged; three fixes are visible to
    TypeScript consumers: exported types shapes are type aliases rather than interface declarations
    (so they can no longer be extended by declaration merging), core's PropsDirective.destroyRef and
    SeoDirective.parent are private, and ConsentHandler is a type. The theme name registries stay
    interfaces so consumers can keep augmenting them.

@ethlete/core@5.0.0-next.37

Major Changes

  • #3041 6c9d38d Thanks @github-actions! - Overlay runtime: build anchored strategies with anchoredOverlayPosition({ referenceElement, … })
    instead of a { kind: 'anchored', … } literal - it is what pulls @floating-ui/dom in, so apps
    that only center dialogs no longer bundle it (~7 kB gz). autoResize, autoHide,
    autoCloseIfReferenceHidden and arrows additionally need enableAnchoredOverlayPositionExtras().

  • #3041 6c9d38d Thanks @github-actions! - @ethlete/core no longer depends on @angular/cdk: injectBreakpointObserver() is a plain
    matchMedia implementation (same API), and AnimatedOverlayDirective moved to @ethlete/cdk -
    import it from there.

  • #3041 42ec970 Thanks @github-actions! - DI: createProvider / createRootProvider / createStaticProvider / createStaticRootProvider /
    createLabels are replaced by defineProvider & co., which return a definition you read with
    toProvideFn / toInjectFn / toToken; createQueryClient, createBearerAuthProvider and
    createWebSocketClient return that definition instead of a tuple. Every provideX / injectX /
    token export keeps its name - run nx g @ethlete/core:migrate-provider-shape for your own call sites.
    Cuts the @ethlete/components import floor from 89.9 to 2.4 kB gz.

Minor Changes

  • #3041 62b03f9 Thanks @github-actions! - Carousel & Scrollable: much smoother swiping on a phone - 85% less style recalculation and 88% less
    paint with transition="wipe", and no observer work during a scroll. Snapping is native CSS scroll
    snap (ScrollableDirective.suspendSnap() holds it off while something writes an offset itself), and
    the built-in transitions run as composited keyframes. New transition="custom" fills
    --et-carousel-slide-progress without applying an effect, for CSS of your own; new
    --et-carousel-wipe-dim-color; signalElementChildren / signalElementScrollState take a
    mutations option to narrow their observers.

  • #3041 7e444d6 Thanks @github-actions! - Rich text editor: block quote and fenced code block tools ('blockquote' / 'codeBlock', also
    typed as > / ```), both in the default toolbar. Quotes nest with Tab/Shift+Tab; a code block
    holds literal text, so the marks that can't serialize inside one disable themselves. htmlToMarkdown
    / markdownToHtml now round-trip nested quotes (>>).

  • #3041 30d3dfb Thanks @github-actions! - unsavedChanges: a tracker now locks the browser tab while the value differs from its baseline - a
    beforeunload listener attached only while changes exist - through the new tab option (false opts
    out), with opt-in titleMarker, flash, favicon and badge extras.
    createUnsavedChangesTabLock() is the same guard standalone, for state that isn't a form.

    • New injectUnsavedChangesCoordinator(): one confirm on screen at a time app-wide, plus
      abandonAll(reason?) for a session that ends underneath a guard. confirm now receives a
      { signal } argument so a dialog can close itself instead of being stranded.
    • New favicon store and applyFaviconOverlay(binding), plus title-store addMarker / removeMarker
      behind the public applyHeadTitleMarker(binding).

Patch Changes

  • #3041 c622e2c Thanks @github-actions! - Breakpoint inputs: warn in dev mode when a breakpoint map mixes valid and unknown keys. One bad key (a
    default entry, say) makes the whole map inert - it becomes a plain value, which for an attribute binding
    renders as [object Object] and does nothing - and that failed silently until now.

  • #3041 fba7ed8 Thanks @github-actions! - Fix applyStructuredDataBinding writing its JSON into a text attribute on the <script> instead
    of into the script's content - the tag was emitted, but empty, so no crawler ever read the structured
    data. (StructuredDataComponent was unaffected.)

  • #3041 353777b Thanks @github-actions! - Mark build-tooling peer dependencies (vite, typescript, ts-morph, @nx/devkit, @analogjs/*) and feature-scoped runtime peers (date-fns in components) as optional via peerDependenciesMeta. They are only needed when running the Nx generators or using the date/time components - consumers no longer have to install them just to use the libraries.

  • #3041 6c9d38d Thanks @github-actions! - RuntimeError logs its data directly instead of deep-cloning it first, which keeps the clone
    helper out of every package's baseline bundle.

  • #3041 353777b Thanks @github-actions! - Adopt the @ethlete/eslint-plugin styleguide flat configs in core, query, contentful and
    types, and apply the resulting auto-fixes. Runtime behavior is unchanged; three fixes are visible to
    TypeScript consumers: exported types shapes are type aliases rather than interface declarations
    (so they can no longer be extended by declaration merging), core's PropsDirective.destroyRef and
    SeoDirective.parent are private, and ConsentHandler is a type. The theme name registries stay
    interfaces so consumers can keep augmenting them.

@ethlete/query@6.0.0-next.23

Major Changes

  • #3041 53fcc97 Thanks @github-actions! - Bearer auth multi-tab sync and leader election are opt-in: createBearerAuthProvider's multiTabSync
    option is replaced by withBearerAuthMultiTabSync() in features (~1.4 kB gz off the secure entry
    without it), read back as provider.features.multiTabSync.isLeader(). Election runs on the Web Locks
    API now rather than a localStorage heartbeat, so a tab that closes or crashes hands over at once.
    setupAuthTest() lost its multiTabSync option. Migrate with
    npx nx g @ethlete/query:migrate-query-opt-in-features.

  • #3041 8b13854 Thanks @github-actions! - Query client: multi-tab sync and response persistence are opt-in features instead of defaults - the
    multiTabSync / persistence client options are gone and a client without the features ships neither
    engine. Migrate with nx g @ethlete/query:migrate-query-client-features.

    • withMultiTabSync() shares reads, polls a cache key in one tab for all of them and refreshes the
      others after a mutation; per-query multiTabSync: false keeps a query tab-local.
    • withQueryPersistence() keeps public reads in IndexedDB, so a reload renders the last known data
      while it revalidates. Secure responses need an explicit opt-in and are removed on logout.
    • refreshQueriesInUse() also refreshes GraphQL queries transported over POST; devtools gain Sync
      and Disk columns.
  • #3041 53fcc97 Thanks @github-actions! - Error-response parsing and the default retry policy are opt-in query client features - without them a
    client reads the plain string / { message } / { detail } / string[] ladder and retries
    nothing, which takes ~1.4 kB gz out of an app that needs neither. Pick from withHtmlErrorParsing(),
    withSymfonyErrors(), withDefaultRetry(), withEthleteApiErrors() (all three, the previous
    behavior) and registerQueryErrorParser() for a body shape the SDK does not know. Run
    npx nx g @ethlete/query:migrate-query-opt-in-features to keep the old behavior.

  • #3041 42ec970 Thanks @github-actions! - DI: createProvider / createRootProvider / createStaticProvider / createStaticRootProvider /
    createLabels are replaced by defineProvider & co., which return a definition you read with
    toProvideFn / toInjectFn / toToken; createQueryClient, createBearerAuthProvider and
    createWebSocketClient return that definition instead of a tuple. Every provideX / injectX /
    token export keeps its name - run nx g @ethlete/core:migrate-provider-shape for your own call sites.
    Cuts the @ethlete/components import floor from 89.9 to 2.4 kB gz.

Minor Changes

  • #3041 e040432 Thanks @github-actions! - New client.invalidateQueries() re-runs the queries this client has on screen whose data went stale -
    after a mutation, or a push message saying something changed server-side - and tells the user's other
    tabs to do the same. Narrow it with url (resolved against baseUrl, matched on path boundaries) and
    filter, or keep it local with otherTabs: false; reaching other tabs needs withMultiTabSync().
    See Invalidating after a change.

Patch Changes

  • #3041 a935328 Thanks @github-actions! - logout() now abandons every unsaved-changes guard (injectUnsavedChangesCoordinator().abandonAll('logout')). Pressing logout with a dirty form used to leave a "discard your changes?" dialog floating over the login page the app had already redirected to, plus a tab still locked against closing - over edits that can no longer be saved. Guards created after a re-login work normally again.

  • #3041 353777b Thanks @github-actions! - Mark build-tooling peer dependencies (vite, typescript, ts-morph, @nx/devkit, @analogjs/*) and feature-scoped runtime peers (date-fns in components) as optional via peerDependenciesMeta. They are only needed when running the Nx generators or using the date/time components - consumers no longer have to install them just to use the libraries.

  • #3041 53fcc97 Thanks @github-actions! - Devtools instrumentation is now registered through a hook that provideQueryDevtools() installs, so
    an app without it drops the entry registry, the route stringifier and the client-name derivation
    entirely - ~0.5 kB gz off every entry. No API change; queryDevtoolsEntries and the
    <et-query-devtools> contract are unchanged.

  • #3041 42ec970 Thanks @github-actions! - Internal: the current generation no longer imports anything from the legacy V2 tree - buildRoute,
    buildQueryString, buildTimestampFromSeconds, decryptBearer, QueryError and the query-string
    types now live in http/internal/request-route, and legacy re-exports them. Every public name is
    unchanged. Also closes the http ↔ gql cycle.

  • #3041 53fcc97 Thanks @github-actions! - socket.io-client is an optional peer dependency. It is only imported by createWebSocketClient,
    and no non-ws public type surfaces it, so an app that does not use the realtime client no longer
    has to install it.

  • #3041 353777b Thanks @github-actions! - Adopt the @ethlete/eslint-plugin styleguide flat configs in core, query, contentful and
    types, and apply the resulting auto-fixes. Runtime behavior is unchanged; three fixes are visible to
    TypeScript consumers: exported types shapes are type aliases rather than interface declarations
    (so they can no longer be extended by declaration merging), core's PropsDirective.destroyRef and
    SeoDirective.parent are private, and ConsentHandler is a type. The theme name registries stay
    interfaces so consumers can keep augmenting them.

@ethlete/agent-rules@0.1.0-next.0

Minor Changes

  • #3041 9808192 Thanks @github-actions! - Add @ethlete/agent-rules: the portable Ethlete coding guidance - styleguide, Angular
    patterns, signals vs RxJS, theming, query, commits, Storybook verification - packaged
    for consumer repos and compiled into Claude Code, Codex (AGENTS.md), Cursor and
    Copilot formats from one canonical source. npx ethlete-agents sync writes the
    generated files, check fails CI on drift, and init scaffolds the config. Content is
    filtered per repo by installed packages (requires), profile (scope) and configured
    template variables.

  • c6ebe63 Thanks @TomTomB! - Add the sdk-docs guide: where the @ethlete docs site and Storybook live, how page URLs
    map to libraries and component domains, and the rule that an API is read rather than
    inferred from a component's name. Aimed at repos that consume the SDK without its source.

Patch Changes

  • c6ebe63 Thanks @TomTomB! - Render a {% skill:… %} cross-reference as a bare name when the guide it points at was
    filtered out of the target repo, instead of emitting a path to a file that was never
    written. sync now reports each such reference.

@ethlete/eslint-plugin@1.0.0-next.17

Minor Changes

  • #3041 ae18442 Thanks @github-actions! - New rule no-impure-top-level-provider: bans destructuring a factory call at module scope, and - with
    { requirePureAnnotation: true }, for publishable library source - requires /* @__PURE__ */ on
    module-scope calls. Both shapes are undroppable, so one of them puts everything the call touches into
    every consumer's bundle. Fixable.

@ethlete/cdk@5.0.0-next.24

Patch Changes

  • #3041 6c9d38d Thanks @github-actions! - @ethlete/core no longer depends on @angular/cdk: injectBreakpointObserver() is a plain
    matchMedia implementation (same API), and AnimatedOverlayDirective moved to @ethlete/cdk -
    import it from there.

  • #3041 353777b Thanks @github-actions! - Mark build-tooling peer dependencies (vite, typescript, ts-morph, @nx/devkit, @analogjs/*) and feature-scoped runtime peers (date-fns in components) as optional via peerDependenciesMeta. They are only needed when running the Nx generators or using the date/time components - consumers no longer have to install them just to use the libraries.

  • #3041 42ec970 Thanks @github-actions! - DI: createProvider / createRootProvider / createStaticProvider / createStaticRootProvider /
    createLabels are replaced by defineProvider & co., which return a definition you read with
    toProvideFn / toInjectFn / toToken; createQueryClient, createBearerAuthProvider and
    createWebSocketClient return that definition instead of a tuple. Every provideX / injectX /
    token export keeps its name - run nx g @ethlete/core:migrate-provider-shape for your own call sites.
    Cuts the @ethlete/components import floor from 89.9 to 2.4 kB gz.

@ethlete/types@2.0.0-next.7

Patch Changes

  • #3041 353777b Thanks @github-actions! - Adopt the @ethlete/eslint-plugin styleguide flat configs in core, query, contentful and
    types, and apply the resulting auto-fixes. Runtime behavior is unchanged; three fixes are visible to
    TypeScript consumers: exported types shapes are type aliases rather than interface declarations
    (so they can no longer be extended by declaration merging), core's PropsDirective.destroyRef and
    SeoDirective.parent are private, and ConsentHandler is a type. The theme name registries stay
    interfaces so consumers can keep augmenting them.

@mergify

mergify Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@github-actions
github-actions Bot force-pushed the changeset-release/next branch 8 times, most recently from 1c088bd to 46c1b40 Compare August 2, 2026 22:04
@github-actions
github-actions Bot force-pushed the changeset-release/next branch from 46c1b40 to 91ce99e Compare August 2, 2026 22:19
@TomTomB
TomTomB merged commit 39d48b5 into next Aug 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant