diff --git a/CHANGELOG.md b/CHANGELOG.md index 00d808d00..1d24582b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,182 +6,188 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added -- #### Tabs - - `header-background` theme token. It paints the whole tabs header strip, behind the tab items, and follows `item-background` unless set. Thus a translucent `item-background` composites over the header color instead of stacking on a copy of itself, and the header can be made transparent on its own. The matching `$header-background` parameter is available in the `tabs-theme` function of `igniteui-theming`. - #### Calendar, Date picker, Date range picker - - `DateRangeDescriptor` has an optional `label`. The calendar adds the labels of the matching `specialDates` and `disabledDates` descriptors to the accessible name of a date, for example "Thursday, October 8, 2026, Free delivery". Before, the special state was only visual, and assistive technologies did not announce it. -- #### Input, Mask input, Date time input, Textarea, Date picker - - Read-only `selectionStart` and `selectionEnd` properties report the text selection. Before, an application could set the selection with `setSelectionRange()`, but it could not read it. In the input, they are `null` for the `email` and `number` types, as on the native input. In the mask input and the date time input, they report the selection from `setRangeText()` when `updateComplete` resolves. + - `DateRangeDescriptor` has an optional `label`. The calendar adds the labels of the matching `specialDates` and `disabledDates` descriptors to the accessible name of a date, for example "Thursday, October 8, 2026, Free delivery". Before, the special state was only visual, and assistive technologies did not announce it. [#2423](https://github.com/IgniteUI/igniteui-webcomponents/pull/2423) +- #### Library + - The repository has new `SECURITY.md`, `PRIVACY.md`, `ACCESSIBILITY.md`, `THREAT-MODEL.md` and `.github/SUPPORT.md` documents. `SECURITY.md` gives the supported versions: 7.x gets all security fixes, and 6.5.x gets fixes for critical vulnerabilities only. Report a vulnerability through GitHub private vulnerability reporting, not in a public issue. [#2383](https://github.com/IgniteUI/igniteui-webcomponents/pull/2383) +- #### Tabs + - `header-background` theme token. It paints the full header strip behind the tab items, and it follows `item-background` until you set it. So a translucent `item-background` shows over the header color and does not stack on a copy of itself. You can also make only the header transparent. The `tabs-theme` function of `igniteui-theming` 29.1.0 has the matching `$header-background` parameter. [#2431](https://github.com/IgniteUI/igniteui-webcomponents/pull/2431) +- #### Text selection + - The date picker, the date time input, the input, the mask input and the textarea have read-only `selectionStart` and `selectionEnd` properties. Before, an application could set the selection with `setSelectionRange()`, but it could not read it. In the input, the two properties are `null` for the `email` and `number` types, as on the native input. In the mask input and the date time input, they report the selection from `setRangeText()` when `updateComplete` resolves. [#2451](https://github.com/IgniteUI/igniteui-webcomponents/pull/2451) [#2452](https://github.com/IgniteUI/igniteui-webcomponents/pull/2452) ### Changed +- #### Library + - The minimum versions of the optional peer dependencies are now `dompurify` 3.4.16, `marked` 18.1.0 and `shiki` 4.5.0. [#2450](https://github.com/IgniteUI/igniteui-webcomponents/pull/2450) +- #### Snackbar, Toast + - The display time now stops while the pointer is on the component or the keyboard focus is in it. It starts again in full when both leave. Before, the component closed under the pointer, and a keyboard user could lose the snackbar action before they got to it. A pointer click on the action does not keep the component open, also when the action has the keyboard focus. [#2447](https://github.com/IgniteUI/igniteui-webcomponents/pull/2447) + - `show()` on an open component now starts the display time again. It still resolves `false`. Before, a new message in an open component closed with the time that remained from the previous message. [#2447](https://github.com/IgniteUI/igniteui-webcomponents/pull/2447) - #### Tile manager - - The default actions of a tile now have names that tell what they do: "Maximize" or "Restore", and "Enter full screen" or "Exit full screen". Before, screen readers announced the icon names, such as "expand_content". The names are in English. To localize them, put your own buttons in the `maximize-action` and `fullscreen-action` slots. - - A tile is now a region that the content of its `title` slot names, so screen reader users can move from tile to tile. An `aria-label` or `aria-labelledby` on the tile replaces the title as the name. Before, a tile had no role. - - In Chromium, the Tab order and the reading order of screen readers now follow the layout: the `position` of the tiles and the gaps that later tiles fill. Other browsers do not support `reading-flow` yet and keep the DOM order. - - `igcTileDragEnd` and `igcTileDragCancel` now fire after the tiles have their new or restored positions, as `igcTileResizeEnd` does. A handler can now call `saveLayout()` and `loadLayout()`. The end or cancel event of a drag still comes before the `igcTileDragStart` of the next drag. Before, the events fired before the view transition applied the positions, so `saveLayout()` returned the old layout and the transition overwrote the layout from `loadLayout()`. -- #### Toast, Snackbar - - The display time now waits while the pointer is on the component or the keyboard focus is in it, and starts again in full when both leave. Before, the component closed under the pointer, and a keyboard user could lose the snackbar action before reaching it. A pointer click on the action does not hold the component open, also when the action has the keyboard focus. - - `show()` on an open component now starts the display time again. It still resolves `false`. Before, a new message in an open component closed with the time that was left from the earlier one. - -### Security -- #### Tile manager - - `loadLayout` now copies only the serialized tile properties: the spans, the positions, the flags and `id`. A layout from storage or a server can no longer set `innerHTML` on a tile or replace its prototype through `__proto__`. A value that is not an array, and an entry that is not an object, are ignored. + - The default actions of a tile now have names that tell what they do: "Maximize" or "Restore", and "Enter full screen" or "Exit full screen". Before, screen readers announced the icon names, such as "expand_content". The names are in English. To localize them, put your own buttons in the `maximize-action` and `fullscreen-action` slots. [#2456](https://github.com/IgniteUI/igniteui-webcomponents/pull/2456) + - A tile is now a region, and the content of its `title` slot gives its name. So screen reader users can move from tile to tile. An `aria-label` or `aria-labelledby` on the tile replaces the title as the name. Before, a tile had no role. [#2456](https://github.com/IgniteUI/igniteui-webcomponents/pull/2456) + - In Chromium, the Tab order and the reading order of screen readers now follow the layout: the `position` of the tiles and the gaps that later tiles fill. Other browsers do not support `reading-flow` yet and keep the DOM order. [#2456](https://github.com/IgniteUI/igniteui-webcomponents/pull/2456) + - `igcTileDragEnd` and `igcTileDragCancel` now fire after the tiles have their new or restored positions, as `igcTileResizeEnd` does. So a handler can call `saveLayout()` and `loadLayout()`. The end or cancel event of a drag still comes before the `igcTileDragStart` of the next drag. Before, the events fired before the view transition applied the positions. So `saveLayout()` returned the old layout, and the transition overwrote the layout from `loadLayout()`. [#2456](https://github.com/IgniteUI/igniteui-webcomponents/pull/2456) ### Fixed -- #### Tile manager - - Maximize and full screen now keep the focus on the action, also when resizing is on. Before, the tile rendered its content again, so the focus went to the page body. - - While a tile is maximized, the other tiles are hidden and their content is skipped. Before, Tab moved the focus into the tiles under the maximized tile. - - `fullscreen` now follows the browser. It turns `false` after Escape, also when a listener cancels `igcTileFullscreen`, and turns `true` when a custom `fullscreen-action` calls `requestFullscreen()` on the tile. The `igcTileFullscreen` event after such a change is not cancelable, because the change has already happened. Before, the tile could show the wrong actions and keep resizing off. - - In a right-to-left layout, the side and corner resize handles are on the left edge, and the tile and its preview both grow to the left. Before, the handles were on the right edge, and the preview grew to the right while the tile grew to the left. - - The divider under the tile header is hidden from assistive technologies. Before, screen readers found a separator in each tile. - - The tile manager keeps its background while a tile is maximized. Before, the background went away. - - A maximized or fullscreen tile now scrolls by touch while dragging is on. Before, the tile canceled each `touchstart`, although it cannot be dragged in that state. - - With `drag-mode="tile-header"`, the tile content now scrolls by touch, and an image or a link in it can be dragged natively. The actions and the resize handles also no longer cancel a touch. Before, the tile canceled every `touchstart` and `dragstart`, also where a drag cannot start. - - A drag no longer swaps with a tile that leaves the manager before the swap applies. Before, the dragged tile could take the position of the removed tile, so two tiles had the same position. - - A drag now swaps with a tile that the pointer reaches straight from another tile, as in a fast move. Before, the drag swapped only after the pointer passed through a gap between the tiles. - - The drag and resize styles of a tile now apply also when the tile has a `part` attribute of its own. - - A dragged tile keeps its size. Before, the line around its placeholder was a border, which made the tile 2 px larger in a grid that sizes to its content. - - Moving tiles in the DOM, as a framework does when it reorders a list, no longer changes the positions of the tiles. Before, a moved tile changed places with the tile before it. - - `loadLayout` now gives every tile a unique position, and `position` takes a whole number. A value that applies to no tile changes no position. Before, a layout with two equal positions gave two tiles the same place, and a fractional position left the CSS `order` unchanged. - - Escape after a drag that moved a tile back and forth now restores every tile, also when tiles leave the manager during the drag and when the next drag starts at once. A tile that moves to another manager during the drag keeps its place there, a start column that a smaller `columnCount` removed stays removed, and a layout from `loadLayout()` during the drag stays. Before, two tiles could get the same position, and a tile could get a width of 0. - - A drag or a resize now cancels, with `igcTileDragCancel` or `igcTileResizeCancel`, when the tile leaves the page, also from an `igcTileDragStart` or `igcTileResizeStart` listener, or the browser sends `pointercancel`. Before, the tile stayed invisible or half transparent and could not take clicks. The events of a second pointer no longer move or end the operation. - - Resizing now works for a tile whose `grid-column` or `grid-row` comes from author CSS, and the spans and the starts take whole numbers. A start from a negative line, such as `-1 / span 2`, now comes from the place of the tile. Before, the resize threw an error and left its preview in the page, and it took a negative line as a line from the start. - - A resize below the last row now reads `min-row-height` and `min-column-width` in any CSS length, such as `rem`. Before, `10rem` counted as 10 pixels, so the tile got too many new rows. - - In nested tile managers, a drag moves only the innermost tile, and it changes places only with the tiles of its own manager. Before, the outer tile started a drag too, and an inner tile could change places with the outer tile that held it. - - In nested tile managers, the tiles of an inner manager no longer take the spans and the starts of the tile that holds the manager. Before, a resize of the outer tile to two columns or two rows made each inner tile two columns wide or two rows tall. - - The swaps of a tile that holds a nested tile manager now animate. Before, the drag preview copied the view transition names of the inner tiles, so the browser skipped each swap transition and logged a duplicate name. - - The drag and resize previews now render in the closest modal dialog, fullscreen element or open popover that holds the manager, also in the dialog of `igc-dialog`. A preview there does not scroll or clip with its container, and it covers the tile also when the container has a translate or a scale, such as the one that centers a modal. A rotation is not supported. Before, the previews went into the document body and were hidden under it. - - The maximize, restore and resize animations keep the tile content sharp. The box of the tile grows or shrinks and shows the content at its real size, the new content fades in at the start, and the tiles that a maximized tile covers fade in place. The drag preview stays on the pointer during a swap. Before, the animation stretched the tile images, so the text was blurred and out of shape, and the covered tiles moved. The rules for these animations are in the theme style sheets, such as `themes/light/bootstrap.css`. The view transition classes of the author stay on the tile. Browsers without view transition classes keep the default animation. - - The drag and resize previews in the page body now cover the tile, also when the body is positioned or has a filter, and when the page scrolls during the operation. Before, the drag preview was off by the margin of the body, and in a positioned body both previews were. - - A fullscreen tile that is removed from the page and added again is no longer `fullscreen`. Before, the tile kept the state, and drag and resize stayed off. - - A tile that moves out of its manager no longer drags or resizes, and the tiles of a manager that the browser defines after them now connect to it. - - Two quick clicks on the maximize action now set the state that both `igcTileMaximize` events report. Before, the tile toggled twice, and a skipped view transition sent an unhandled error. - - When the browser rejects a fullscreen request, the tile now emits `igcTileFullscreen` with `state: false`, which is not cancelable. Before, the state rolled back without an event, after the event that announced `state: true`. A rejected exit from full screen works the same way, with `state: true`. Before, the tile showed the state that is not fullscreen while it stayed fullscreen. - - Removing a maximized tile now releases the grid height that the manager kept while the tile was maximized. Before, the grid kept that height. - - In a manager that is narrower than `minColumnWidth`, a responsive column now takes the width of the manager. Before, the column kept the minimum width, and the manager scrolled horizontally. -- #### Tabs - - `alignment` had no effect in the Material, Fluent and Indigo themes. `center`, `end` and `justify` rendered like `start`, because the header grid did not take the width of the strip outside the Bootstrap theme. - - `justify` now gives every tab the same width, as the Angular tabs do. Before, each tab got its content width plus an equal share of the free space. - - A tab selected through its `selected` property, from markup or by a framework binding, is now scrolled into view, the same as a tab selected by click, keyboard or `select()`. The scroll is confined to the header strip and never moves the page. [#2267](https://github.com/IgniteUI/igniteui-webcomponents/issues/2267) is thus still covered. - - A tab added as selected that makes the strip overflow is scrolled fully into view. Before, it stayed partly hidden behind the end scroll button that had just appeared. - - The scroll buttons now go away when removing tabs makes the strip fit again. Before, the buttons kept themselves displayed, because the overflow was measured with their own columns included. - - The Material and Fluent themes paint the whole header strip, as the Angular tabs do. Before, only the area under the tab items was painted, so the strip ended at the last tab. [IgniteUI/igniteui-angular#17421](https://github.com/IgniteUI/igniteui-angular/issues/17421) - - A tab added as selected now takes the selection also when the selected tab is deselected or removed at the same time, as a framework render or new `innerHTML` does, and a selected tab that moves keeps the selection. Before, the first tab got the selection in these cases. When several tabs become selected at once, the last one in document order now wins, as in the initial markup. -- #### Input, Mask input, Date time input, File input, Textarea, Select, Combo, Date picker, Date range picker, Color picker, Checkbox, Switch, Radio - - As for a native control, a failed form submit or `form.reportValidity()` now moves the focus to the first invalid control, also when an invalid native control comes after it. `reportValidity()` of an invalid control moves the focus to that control. Before, the focus stayed where it was, because the controls cancel the `invalid` event to hide the message of the browser, and only Select moved the focus on `reportValidity()`. `form.checkValidity()` does not move the focus. To tell a submit from `form.checkValidity()`, also when one runs inside the other, the library wraps `checkValidity()`, `reportValidity()` and `requestSubmit()` of `HTMLFormElement.prototype`. - - The controls no longer send an `invalid` event while the user edits an invalid field or leaves it. Before, each validation sent one, unlike a native control. Now the event comes only from `checkValidity()`, `reportValidity()`, the same methods of the form, and a failed submit. -- #### Rating, Slider, Range slider - - `focus()` now moves the focus to the slider element of the rating and to the thumb of the slider, and `blur()` removes it. The range slider focuses its lower thumb, unless one of its thumbs has the focus already. A disabled control does not take the focus. So a failed form submit, `form.reportValidity()` and `reportValidity()` of the control now move the focus to an invalid rating or slider, as for the other form controls. Before, `focus()` did nothing. -- #### Input, Mask input, Date time input, File input, Textarea, Select, Combo, Date picker, Date range picker, Color picker, Checkbox, Switch, Radio, Rating, Slider - - A host `aria-describedby` now describes the native control, after the helper text. In the two-input date range picker, the end editor gets only the host description. So an `igc-tooltip` on the control describes it too. Before, the description stayed on the host, where screen readers did not use it. -- #### Mask input, Date time input, Date picker, Date range picker - - `required` now sets `aria-required` on the native input of each editor, also in the two-input mode of the date range picker. Before, screen readers did not announce these fields as required. -- #### Chip, Tabs, Stepper, Expansion panel, Navigation drawer, Tree - - The host `aria-label`, `aria-labelledby` and `aria-describedby` now name and describe the element that has the focus or the role: the action button of a chip, the header of a tab or a step, the header of an expansion panel, and the drawer. A tree item that delegates its role to a link in its label copies them to that link, unless the link has its own. In the navigation drawer, `label` still wins over the host `aria-label`. Before, these attributes stayed on the host, where screen readers did not use them. -- #### Splitter - - The host `aria-labelledby` and `aria-label` now name the splitter bar, and a host `aria-describedby` describes it. Before, every bar was named "Resize panes", so the bars of nested splitters had the same name, and an application could not localize the name. "Resize panes" stays the name of a bar without a host name. - - The bar no longer has the English description "Start pane expanded and End pane expanded". Its value already tells a collapsed pane: 0% for the start pane and 100% for the end pane. -- #### List - - `igc-list-header` now has the `listitem` role. Before, it had the `separator` role. A list cannot contain a separator, and a separator hides its content from assistive technologies, so a screen reader could skip the text of the header. Screen readers now read the header and count it with the items. Put a heading in the header, so that users can move from group to group. - - The title and subtitle container of `igc-list-item` is now a `div`, not a `header` element. Before, Chromium exposed it as a `sectionheader` in each item. The `header` part is unchanged. -- #### Navigation drawer - - When a drawer with a `mini` variant closes, the focus now goes back to the element that had the focus when the drawer opened, such as a menu button in the rail. Before, the drawer closed its dialog while the rail was still hidden, so the focus went to the page body. - - When the platform closes the dialog of a drawer that stays open, for example after a second Escape when an `igcClosing` handler cancels the close, the drawer now opens the dialog again. When the drawer then closes, the focus goes back to the element that had it when the drawer first opened. Before, `open` stayed `true` with a closed dialog, and `show()` did nothing. -- #### Highlight - - A space in `searchText` now matches any run of whitespace in the content, such as a line break in the HTML source. Before, "cold brew" did not find the two words when a line break separated them. -- #### Input - - `setRangeText()` without `start` and `end` now replaces the selected text, as the native method does. Before, it inserted the text at the start of the value. - - `pattern` now has to match the whole value, as for a native input. Before, a match in a part of the value was enough, so `[0-9]{3}` accepted `1234`. The pattern also compiles with the `v` flag, and an invalid pattern sets no constraint. Before, an invalid pattern threw an error in `checkValidity()`. -- #### Textarea - - Whitespace in the default slot, such as the indentation around a slotted helper text, no longer clears the value. Before, it replaced the value from the `value` attribute or the property with an empty string, and whitespace added later cleared the text that the user typed. Projected text still sets the value, and removing it still clears the value. - - `setRangeText()` without `start` and `end` now replaces the selected text, as the native method does. Before, it inserted the text at the start of the value. - - The `spellcheck` attribute now reads as the native attribute: only `false` turns the spell check off. Before, an empty attribute, such as ``, and a removed attribute turned it off. -- #### Date picker - - The `start` and `end` parameters of `setRangeText()` are now optional, as in the date time input. Without them, the method replaces the selected text. Before, the TypeScript signature required them, although the method worked without them. -- #### Stepper - - A click in the content of a step no longer activates that step. Before, a button in the content that called `next()`, `prev()`, `navigateTo()` or `reset()` had its change undone by the same click, with an `igcActiveStepChanging` and `igcActiveStepChanged` pair. A click on a header of a nested stepper no longer changes the outer stepper. - - The content of the inactive steps is now `inert`. Before, it was only transparent, so Tab moved into the fields of hidden steps, and screen readers read every panel. - - The header of a disabled step, and of a step that linear mode locks, now has `aria-disabled`. Before, screen readers did not announce these steps as unavailable. -- #### Icon - - The SVG of an icon is now hidden from assistive technologies, because the host carries the name. Before, the SVG of an icon without a title was still an unnamed image. A change of `aria-label` or `aria-labelledby` now updates the role of the icon. -- #### Dialog - - An `aria-label` on the dialog is now its only accessible name. Before, the inner `` also got `aria-labelledby` with the text of the label, which is not a valid ID reference. - - A change of `aria-label` alone now updates the name of the dialog, and its removal gives the name back to the title. Before, the change applied only after the next change of a property, such as `open`. - - A host `aria-labelledby` now names the dialog, before `aria-label` and the title, and a host `aria-describedby` describes it. Before, the dialog forwarded only `aria-label`. - - When the platform closes the dialog while `open` stays `true`, for example after a second Escape when an `igcClosing` handler cancels the close, the dialog now opens again. Before, only `keepOpenOnEscape` did this. Otherwise `open` stayed `true` with a closed dialog, the backdrop still covered the page, and `show()` did nothing. +- #### Accordion + - The arrow keys, `Home` and `End` now skip a panel that does not render, such as a panel with the `hidden` attribute or `display: none`. Before, the focus stayed on the current panel. [#2418](https://github.com/IgniteUI/igniteui-webcomponents/pull/2418) +- #### AI-Assisted Development + - The `igniteui-wc-migrate-grid-lite-to-premium` skill now shows a correct custom sort strategy for the Premium Grid: an object with a `sort()` method that reads the cell values through `valueResolver`. Before, the example extended `DefaultSortingStrategy`, which the grid package does not export. [#2407](https://github.com/IgniteUI/igniteui-webcomponents/pull/2407) +- #### Button, Icon button + - A button with `href` now keeps the link role of its anchor. Before, the anchor had `role="button"`, so screen readers announced a link as a button. [#2421](https://github.com/IgniteUI/igniteui-webcomponents/pull/2421) + - A disabled link now renders a disabled native `