mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
fix(all): accesibility and global styles for hidden nodes
This commit is contained in:
@ -65,7 +65,6 @@
|
||||
"lint.ts": "tslint --project .",
|
||||
"lint.ts.fix": "tslint --project . --fix",
|
||||
"prerelease": "npm run validate && np prerelease --yolo --any-branch --tag next",
|
||||
"set.version": "node scripts/set-version.js",
|
||||
"snapshot": "node ./scripts/e2e --snapshot",
|
||||
"test": "jest",
|
||||
"test.watch": "jest --watch --no-cache",
|
||||
|
@ -26,13 +26,11 @@ ion-app,
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hide-page {
|
||||
.ion-page-invisible {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
// TODO can we remove important here or remove this entirely
|
||||
// since it is also in structure.scss
|
||||
.ion-page-hidden {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -6,11 +6,11 @@
|
||||
:host {
|
||||
--ion-color-base: #{$background-color};
|
||||
--ion-color-contrast: #{$text-color};
|
||||
--padding-top: 0;
|
||||
--padding-bottom: 0;
|
||||
--padding-start: 0;
|
||||
--padding-end: 0;
|
||||
--keyboard-offset: 0;
|
||||
--padding-top: 0px;
|
||||
--padding-bottom: 0px;
|
||||
--padding-start: 0px;
|
||||
--padding-end: 0px;
|
||||
--keyboard-offset: 0px;
|
||||
|
||||
display: block;
|
||||
position: relative;
|
||||
|
4
core/src/components/menu-toggle/menu-toggle.scss
Normal file
4
core/src/components/menu-toggle/menu-toggle.scss
Normal file
@ -0,0 +1,4 @@
|
||||
:host(.menu-toggle-hidden) {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none;
|
||||
}
|
@ -2,6 +2,8 @@ import { Component, Listen, Prop, State } from '@stencil/core';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-menu-toggle',
|
||||
styleUrl: 'menu-toggle.scss',
|
||||
shadow: true
|
||||
})
|
||||
export class MenuToggle {
|
||||
@Prop({ context: 'document' })
|
||||
@ -54,9 +56,16 @@ export class MenuToggle {
|
||||
hostData() {
|
||||
const hidden = this.autoHide && !this.visible;
|
||||
return {
|
||||
'hidden': hidden
|
||||
'aria-hidden': hidden ? 'true' : null,
|
||||
class: {
|
||||
'menu-toggle-hidden': hidden,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <slot></slot>;
|
||||
}
|
||||
}
|
||||
|
||||
function getMenuController(doc: Document): Promise<HTMLIonMenuControllerElement|undefined> {
|
||||
|
@ -2,7 +2,7 @@ import { Build, Component, Element, Event, EventEmitter, Method, Prop, QueueApi,
|
||||
import { ViewLifecycle } from '../..';
|
||||
import { Animation, ComponentProps, Config, FrameworkDelegate, GestureDetail, Mode, NavComponent, NavOptions, NavOutlet, NavResult, RouteID, RouteWrite, TransitionDoneFn, TransitionInstruction, ViewController } from '../../interface';
|
||||
import { assert } from '../../utils/helpers';
|
||||
import { TransitionOptions, lifecycle, transition } from '../../utils/transition';
|
||||
import { TransitionOptions, lifecycle, setPageHidden, transition } from '../../utils/transition';
|
||||
import { ViewState, convertToViews, matches } from './view-controller';
|
||||
|
||||
@Component({
|
||||
@ -850,15 +850,16 @@ export class Nav implements NavOutlet {
|
||||
|
||||
for (let i = views.length - 1; i >= 0; i--) {
|
||||
const view = views[i];
|
||||
const element = view.element;
|
||||
if (i > activeViewIndex) {
|
||||
// this view comes after the active view
|
||||
// let's unload it
|
||||
lifecycle(this.win, view.element, ViewLifecycle.WillUnload);
|
||||
lifecycle(this.win, element, ViewLifecycle.WillUnload);
|
||||
this.destroyView(view);
|
||||
} else if (i < activeViewIndex) {
|
||||
// this view comes before the active view
|
||||
// and it is not a portal then ensure it is hidden
|
||||
view.element!.hidden = true;
|
||||
setPageHidden(element!, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ export class ViewController {
|
||||
|
||||
if (!this.element) {
|
||||
const component = this.component;
|
||||
this.element = await attachComponent(this.delegate, container, component, ['ion-page', 'hide-page'], this.params);
|
||||
this.element = await attachComponent(this.delegate, container, component, ['ion-page', 'ion-page-invisible'], this.params);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ export class RouterOutlet implements NavOutlet {
|
||||
this.activeComponent = component;
|
||||
|
||||
// attach entering view to DOM
|
||||
const enteringEl = await attachComponent(this.delegate, this.el, component, ['ion-page', 'hide-page'], params);
|
||||
const enteringEl = await attachComponent(this.delegate, this.el, component, ['ion-page', 'ion-page-invisible'], params);
|
||||
const leavingEl = this.activeEl;
|
||||
|
||||
// commit animation
|
||||
|
@ -36,7 +36,8 @@
|
||||
}
|
||||
|
||||
:host(.tab-hidden) {
|
||||
display: none;
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
a {
|
||||
|
4
core/src/components/tab/tab.scss
Normal file
4
core/src/components/tab/tab.scss
Normal file
@ -0,0 +1,4 @@
|
||||
:host(.tab-hidden) {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
@ -3,7 +3,9 @@ import { Color, ComponentRef, FrameworkDelegate } from '../../interface';
|
||||
import { attachComponent } from '../../utils/framework-delegate';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-tab'
|
||||
tag: 'ion-tab',
|
||||
styleUrl: 'tab.scss',
|
||||
shadow: true
|
||||
})
|
||||
export class Tab {
|
||||
|
||||
@ -136,13 +138,19 @@ export class Tab {
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const { btnId, active, component } = this;
|
||||
return {
|
||||
'aria-labelledby': this.btnId,
|
||||
'aria-labelledby': btnId,
|
||||
'aria-hidden': !active ? 'true' : null,
|
||||
'role': 'tabpanel',
|
||||
'hidden': !this.active,
|
||||
'class': {
|
||||
'ion-page': !this.component
|
||||
'ion-page': !component,
|
||||
'tab-hidden': !active
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <slot></slot>;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,8 @@
|
||||
}
|
||||
|
||||
:host(.tabbar-hidden) {
|
||||
display: none;
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host(.placement-top) {
|
||||
|
@ -24,7 +24,7 @@ export class Tabbar {
|
||||
|
||||
@State() canScrollLeft = false;
|
||||
@State() canScrollRight = false;
|
||||
@State() hidden = false;
|
||||
@State() keyboardVisible = false;
|
||||
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar. Available options: `"icon-top"`, `"icon-start"`, `"icon-end"`, `"icon-bottom"`, `"icon-hide"`, `"label-hide"`.
|
||||
@ -68,13 +68,13 @@ export class Tabbar {
|
||||
|
||||
@Listen('body:keyboardWillHide')
|
||||
protected onKeyboardWillHide() {
|
||||
setTimeout(() => this.hidden = false, 50);
|
||||
setTimeout(() => this.keyboardVisible = false, 50);
|
||||
}
|
||||
|
||||
@Listen('body:keyboardWillShow')
|
||||
protected onKeyboardWillShow() {
|
||||
if (this.placement === 'bottom') {
|
||||
this.hidden = true;
|
||||
this.keyboardVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,15 +182,17 @@ export class Tabbar {
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const { color, translucent, layout, placement, keyboardVisible, scrollable } = this;
|
||||
return {
|
||||
role: 'tablist',
|
||||
'aria-hidden': keyboardVisible ? 'true' : null,
|
||||
class: {
|
||||
...createColorClasses(this.color),
|
||||
'tabbar-translucent': this.translucent,
|
||||
[`layout-${this.layout}`]: true,
|
||||
[`placement-${this.placement}`]: true,
|
||||
'tabbar-hidden': this.hidden,
|
||||
'scrollable': this.scrollable
|
||||
...createColorClasses(color),
|
||||
'tabbar-translucent': translucent,
|
||||
[`layout-${layout}`]: true,
|
||||
[`placement-${placement}`]: true,
|
||||
'tabbar-hidden': keyboardVisible,
|
||||
'scrollable': scrollable
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -209,6 +211,7 @@ export class Tabbar {
|
||||
selected={selectedTab === tab}
|
||||
mode={this.mode}
|
||||
color={this.color}
|
||||
aria-hidden={ !tab.show ? 'true' : null }
|
||||
class={{ 'tab-hidden': !tab.show }}
|
||||
onClick={(ev) => {
|
||||
if (!tab.disabled) {
|
||||
|
@ -50,8 +50,3 @@ body {
|
||||
|
||||
text-size-adjust: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ export function iosTransitionAnimation(Animation: Animation, navEl: HTMLElement,
|
||||
.addElement(enteringEl)
|
||||
.duration(opts.duration || DURATION)
|
||||
.easing(opts.easing || EASING)
|
||||
.beforeRemoveClass('hide-page');
|
||||
.beforeRemoveClass('ion-page-invisible');
|
||||
|
||||
if (leavingEl && navEl) {
|
||||
const navDecor = new Animation();
|
||||
|
@ -14,7 +14,7 @@ export function mdTransitionAnimation(Animation: Animation, _: HTMLElement, opts
|
||||
const rootTransition = new Animation();
|
||||
rootTransition
|
||||
.addElement(ionPageElement)
|
||||
.beforeRemoveClass('hide-page');
|
||||
.beforeRemoveClass('ion-page-invisible');
|
||||
|
||||
const backDirection = (opts.direction === 'back');
|
||||
if (enteringEl) {
|
||||
|
@ -45,9 +45,19 @@ function beforeTransition(opts: TransitionOptions) {
|
||||
} else {
|
||||
enteringEl.classList.remove('can-go-back');
|
||||
}
|
||||
enteringEl.hidden = false;
|
||||
setPageHidden(enteringEl, false);
|
||||
if (leavingEl) {
|
||||
leavingEl.hidden = false;
|
||||
setPageHidden(leavingEl, false);
|
||||
}
|
||||
}
|
||||
|
||||
export function setPageHidden(el: HTMLElement, hidden: boolean) {
|
||||
if (hidden) {
|
||||
el.setAttribute('aria-hidden', 'true');
|
||||
el.classList.add('ion-page-hidden');
|
||||
} else {
|
||||
el.removeAttribute('aria-hidden');
|
||||
el.classList.remove('ion-page-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,10 +78,10 @@ async function noAnimation(opts: TransitionOptions): Promise<null> {
|
||||
const enteringEl = opts.enteringEl;
|
||||
const leavingEl = opts.leavingEl;
|
||||
if (enteringEl) {
|
||||
enteringEl.classList.remove('hide-page');
|
||||
enteringEl.classList.remove('ion-page-invisible');
|
||||
}
|
||||
if (leavingEl) {
|
||||
leavingEl.classList.remove('hide-page');
|
||||
leavingEl.classList.remove('ion-page-invisible');
|
||||
}
|
||||
await waitForReady(opts, false);
|
||||
|
||||
|
Reference in New Issue
Block a user