fix(item-sliding): options display on rtl (#27203)

Issue URL: resolves #26103, resolves #25285

---------

<!-- Please refer to our contributing documentation for any questions on
submitting a pull request, or let us know here if you need any help:
https://ionicframework.com/docs/building/contributing -->

<!-- Some docs updates need to be made in the `ionic-docs` repo, in a
separate PR. See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#modifying-documentation
for details. -->

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Options in `item-sliding` will not display when using RTL with Firefox
and Safari.

<!-- Issues are required for both bug fixes and features. -->


## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

Issue was coming from `:host-context`. Firefox would keep [removing the
entire](https://www.w3.org/TR/selectors-3/#grouping) compiled style when
using this unsupported style. This would led to the RTL styles to not
being applied to the component.

- Split the CSS group from `add-root-selector()`
- Added comments to make it easier to navigate through
`add-root-selector()`
- Added `:dir()`

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Co-authored-by: brandyscarney <brandyscarney@users.noreply.github.com>

- Updating `add-root-selector()` would also fix another
[issue](https://github.com/ionic-team/ionic-framework/issues/25285)
unintentionally

---------

Co-authored-by: ionitron <hi@ionicframework.com>
Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
This commit is contained in:
Maria Hutt
2023-05-09 10:05:18 -07:00
committed by GitHub
parent 2bec25ef01
commit b16fd1d6f9
4 changed files with 113 additions and 29 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -84,23 +84,7 @@
// Add Root Selector
// --------------------------------------------------------------------------------
// Adds a root selector using host-context based on the selector passed
//
// Examples
// --------------------------------------------------------------------------------
// @include add-root-selector("[dir=rtl]", ":host")
// --> :host-context([dir=rtl])
//
// @include add-root-selector("[dir=rtl]", ":host(.fixed)")
// --> :host-context([dir=rtl]):host(.fixed)
// --> :host-context([dir=rtl]).fixed
//
// @include add-root-selector("[dir=rtl]", ":host(.tab-layout-icon-hide) ::slotted(ion-badge)")
// --> :host-context([dir=rtl]).tab-layout-icon-hide ::slotted(ion-badge)
//
// @include add-root-selector("[dir=rtl]", ".shadow")
// --> [dir=rtl] .shadow
// --> :host-context([dir=rtl]) .shadow
// Adds a root selector using host based on the selector passed
// --------------------------------------------------------------------------------
@function add-root-selector($root, $addHostSelector) {
@ -110,8 +94,13 @@
@each $selector in $selectors {
// If the selector contains :host( it means it is targeting a class on the host
// element so we need to change how we target it
// element so we need to change how we target it:
// @include add-root-selector(":host(.fixed)", "[dir=rtl]")
// --> :host-context([dir=rtl]):host(.fixed)
// --> :host-context([dir=rtl]).fixed
@if str-contains($selector, ":host(") {
// @include add-root-selector(":host(.fixed)", "[dir=rtl]")
// --> :host-context([dir=rtl]):host(.fixed)
$shadow-element: str-replace($selector, ":host(", ":host-context(#{$addHostSelector}):host(");
$list: append($list, $shadow-element, comma);
@ -122,26 +111,63 @@
@if str-contains($element, ":host(") {
$scoped-element: $element;
@if str-contains($element, "))") {
$scoped-element: str-replace($scoped-element, "))", ")");
} @else {
$scoped-element: str-replace($scoped-element, ")", "");
}
$scoped-element: str-replace($scoped-element, ":host(", ":host-context(#{$addHostSelector})");
// Replace the :host( and ) so all we have left is the class
// inside of it:
// :host(.fixed) -> .fixed
$scoped-element: str-replace($scoped-element, ")", "");
$scoped-element: str-replace($scoped-element, ":host(", "");
// Add the class back inside of host with the rtl selector:
// .fixed -> :host-context([dir=rtl]).fixed
$scoped-element: str-replace($scoped-element, $scoped-element, ":host-context(#{$addHostSelector})#{$scoped-element}");
// @include add-root-selector(":host(.fixed)", "[dir=rtl]")
// --> :host-context([dir=rtl]).fixed
$new-element: append($new-element, $scoped-element, space);
} @else {
// Add back any selectors that followed the host after transforming the
// first selector:
// :host(.fixed) ::slotted(ion-icon)
// --> :host-context([dir=rtl]):host(.fixed) ::slotted(ion-icon)
// --> :host-context([dir=rtl]).fixed ::slotted(ion-icon)
$new-element: append($new-element, $element, space);
}
}
$list: append($list, $new-element, comma);
// If the selector contains :host it means it is targeting just the host
// If the selector contains :host without a parantheses
// it means it is targeting just the host
// element so we can change it to look for host-context
// @include add-root-selector(":host", "[dir=rtl]")
// --> :host-context([dir=rtl])
// --> :host:dir(rtl)
} @else if str-contains($selector, ":host") {
$list: append($list, ":host-context(#{$addHostSelector})", comma);
$new-element: ();
$elements: str-split($selector, " ");
@each $element in $elements {
@if str-contains($element, ":host") {
// Replace the :host with the addHostSelector:
// :host -> :host-context([dir=rtl])
$updated-element: str-replace($element, ":host", ":host-context(#{$addHostSelector})");
// Add the final selector after all transformations:
// :host -> :host-context([dir=rtl])
$new-element: append($new-element, $updated-element, space);
} @else {
// Add back any selectors that followed the host after transforming the
// first selector:
// :host ::slotted(ion-icon) -> :host-context([dir=rtl]) ::slotted(ion-icon)
$new-element: append($new-element, $element, space);
}
}
$list: append($list, $new-element, comma);
// If the selector does not contain host at all it is either a shadow
// or normal element so append both the dir check and host-context
// or normal element so append both the addHostSelector and host-context
// @include add-root-selector("ion-component", "[dir=rtl]")
// --> :host-context([dir=rtl]) ion-component
// --> [dir=rtl] ion-component
} @else {
$list: append($list, "#{$addHostSelector} #{$selector}", comma);
$list: append($list, ":host-context(#{$addHostSelector}) #{$selector}", comma);

View File

@ -194,8 +194,66 @@
@mixin rtl() {
$root: #{&};
@at-root #{add-root-selector($root, "[dir=rtl]")} {
@content;
$rootSplit: str-split($root, ",");
$selectors: #{add-root-selector($root, "[dir=rtl]")};
$selectorsSplit: str-split($selectors, ",");
$hostContextSelectors: ();
$restSelectors: ();
$dirSelectors: ();
// Selectors must be split into individual selectors in case the browser
// doesn't support a specific selector.
// For example, Firefox and Safari doesn't support `:host-context()`.
// If an invalid selector is used, then the entire group of selectors
// will be ignored.
// @link https://www.w3.org/TR/selectors-3/#grouping
@each $selector in $selectorsSplit {
// Group the selectors back into a single selector to optimize the output.
@if str-index($selector, ":host-context") {
$hostContextSelectors: append($hostContextSelectors, $selector, comma);
} @else {
// Group the selectors back into a single selector to optimize the output.
$restSelectors: append($restSelectors, $selector, comma);
}
}
// Supported by Chrome.
@if length($hostContextSelectors) > 0 {
@at-root #{$hostContextSelectors} {
@content;
}
}
// Supported by all browsers.
@if length($restSelectors) > 0 {
@at-root #{$restSelectors} {
@content;
}
}
// If browser can support `:dir()`, then add the `:dir()` selectors.
@supports selector(:dir(rtl)) {
// Adding :dir() in case the browser doesn't support `:host-context()` and does support `:dir()`.
// `:host-context()` is added:
// - through the `add-root-selector()` function.
// - first so that it takes precedence over `:dir()`.
// For example,
// - Firefox doesn't support `:host-context()`, but does support `:dir()`.
// - Safari doesn't support `:host-context()`, but Safari 16.4+ supports `:dir()`
// @link https://webkit.org/blog/13966/webkit-features-in-safari-16-4/
@each $selector in $rootSplit {
$dirSelector: "#{$selector}:dir(rtl)";
// Group the selectors back into a single selector to optimize the output.
$dirSelectors: append($dirSelectors, $dirSelector, comma);
}
// Supported by Firefox.
@if length($dirSelectors) > 0 {
@at-root #{$dirSelectors} {
@content;
}
}
}
}