diff --git a/src/addons/qtype/calculated/component/addon-qtype-calculated.html b/src/addons/qtype/calculated/component/addon-qtype-calculated.html index 9767e13cc..d8910df93 100644 --- a/src/addons/qtype/calculated/component/addon-qtype-calculated.html +++ b/src/addons/qtype/calculated/component/addon-qtype-calculated.html @@ -55,7 +55,7 @@ - + {{ option.text }} diff --git a/src/addons/qtype/multichoice/component/addon-qtype-multichoice.html b/src/addons/qtype/multichoice/component/addon-qtype-multichoice.html index bd1b653ad..ec262e32c 100644 --- a/src/addons/qtype/multichoice/component/addon-qtype-multichoice.html +++ b/src/addons/qtype/multichoice/component/addon-qtype-multichoice.html @@ -41,7 +41,7 @@ - +
diff --git a/src/theme/components/ion-action-sheet.scss b/src/theme/components/ion-action-sheet.scss index c76df351e..d89728cd3 100644 --- a/src/theme/components/ion-action-sheet.scss +++ b/src/theme/components/ion-action-sheet.scss @@ -35,3 +35,16 @@ ion-action-sheet { } } } + +// File uploader. +.action-sheet-button input.core-fileuploader-file-handler-input { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + min-width: 100%; + opacity: 0; + z-index: 100; + cursor: pointer; +} diff --git a/src/theme/components/ion-alert.scss b/src/theme/components/ion-alert.scss index fef0eec00..74c255a07 100644 --- a/src/theme/components/ion-alert.scss +++ b/src/theme/components/ion-alert.scss @@ -1,12 +1,75 @@ +@keyframes scaleFrom0 { + from { + /* More performant than animating `width` */ + transform: scaleX(0); + } +} + ion-alert { + --border-radius: var(--modal-radius); + + &.md, &.ios { + --max-width: 80%; + + @include media-breakpoint-up(md) { + --max-width: 384px; + } + } + + .alert-wrapper { + overflow: auto; + border-radius: var(--border-radius) !important; + + button.alert-button.alert-button-role-destructive { + color: var(--danger); + } + + } + + .alert-message { + user-select: text; + flex-shrink: 0; + + ion-card { + margin: 0; + margin-top: 10px; + } + + } + &.md .alert-button { // Remove padding from alert buttons, they already have min accessibility height. padding-top: 0px; padding-bottom: 0px; } + .alert-button.timed-button{ + position: relative; + + &::before { + content: ''; + position: absolute; + width: 100%; + left: 0; + right: 0; + bottom: 0; + top: 0; + background-color: var(--primary-tint); + animation: scaleFrom0 10s forwards linear; + transform-origin: left; + @include rtl() { + transform-origin: right; + } + z-index: -1; + } + } + &.core-alert-force-on-top { z-index: 100000 !important; } + &.core-nohead .alert-head, + .alert-head:empty { + padding-bottom: 0; + } } diff --git a/src/theme/components/ion-button.scss b/src/theme/components/ion-button.scss index 0ff8ee7fa..6a6f7ab71 100644 --- a/src/theme/components/ion-button.scss +++ b/src/theme/components/ion-button.scss @@ -17,6 +17,10 @@ ion-button { color: inherit; } + &.button-disabled { + opacity: var(--mdl-button-disabled-opacity) !important; + } + &.button-outline { --border-width: var(--core-input-border-width); --border-color: var(--core-input-stroke); diff --git a/src/theme/components/ion-checkbox.scss b/src/theme/components/ion-checkbox.scss index bff03e79d..f43b45807 100644 --- a/src/theme/components/ion-checkbox.scss +++ b/src/theme/components/ion-checkbox.scss @@ -1,5 +1,26 @@ -ion-checkbox { - &.checkbox-disabled::part(label) { - opacity: 0.8; + +// Checkbox. +ion-checkbox, +input[type=checkbox] { + --border-radius: 2px; + --border-width: 2px; + --outer-border-width: 2px; + --border-style: solid; + --size: 20px; + + &:not(.ion-color) { + --border-color-checked: var(--text-color); + --checkbox-background-checked: var(--text-color); + --checkmark-color: var(--contrast-background); } } + +ion-checkbox { + &.checkbox-disabled::part(label) { + opacity: var(--mdl-input-disabled-opacity); + } +} + +.ios input[type=checkbox] { + --outer-border-width: 1px; +} diff --git a/src/theme/components/ion-datetime.scss b/src/theme/components/ion-datetime.scss new file mode 100644 index 000000000..c91d916f7 --- /dev/null +++ b/src/theme/components/ion-datetime.scss @@ -0,0 +1,14 @@ +ion-item.item-label-stacked ion-datetime-button { + margin-top: 8px; + margin-bottom: 8px; + align-self: self-end; +} + +ion-datetime-button p { + margin-top: 4px; + margin-bottom: 4px; +} + +ion-datetime.datetime-disabled { + opacity: var(--mdl-input-disabled-opacity) !important; +} diff --git a/src/theme/components/ion-fab.scss b/src/theme/components/ion-fab.scss new file mode 100644 index 000000000..f6eee8464 --- /dev/null +++ b/src/theme/components/ion-fab.scss @@ -0,0 +1,35 @@ + +// Hide close button because when present is read on voice over. +ion-fab[core-fab] { + ion-fab-button::part(close-icon) { + display: none; + } +} + +// The following 4 selectors can probably be removed after Ionic migration to 7+ +ion-fab.fab-horizontal-start { + left: calc(10px + var(--ion-safe-area-right, 0px)); +} + +&[dir=rtl] ion-fab.fab-horizontal-start { + right: calc(10px + var(--ion-safe-area-right, 0px)); + left: unset +} + +ion-fab.fab-horizontal-end { + right: calc(10px + var(--ion-safe-area-right, 0px)); +} + +&[dir=rtl] ion-fab.fab-horizontal-end { + left: calc(10px + var(--ion-safe-area-right, 0px)); + right: unset +} + +ion-content.has-collapsible-footer ion-fab { + bottom: calc(var(--core-collapsible-footer-height, 0px) + 10px); + @include core-transition(all, 200ms); +} + +ion-fab-button { + --box-shadow: 0 3px 5px -1px rgb(0 0 0 / 20%), 0 6px 10px 0 rgb(0 0 0 / 14%), 0 1px 18px 0 rgb(0 0 0 / 12%); +} diff --git a/src/theme/components/ion-input.scss b/src/theme/components/ion-input.scss index da82c4ec4..6675453f4 100644 --- a/src/theme/components/ion-input.scss +++ b/src/theme/components/ion-input.scss @@ -1,5 +1,5 @@ ion-input { &.input-disabled.md, &.input-disabled.ios { - opacity: 0.8; + opacity: var(--mdl-input-disabled-opacity); } } diff --git a/src/theme/components/ion-item.scss b/src/theme/components/ion-item.scss index 26c0c28bc..a6c4a2ce4 100644 --- a/src/theme/components/ion-item.scss +++ b/src/theme/components/ion-item.scss @@ -19,7 +19,8 @@ ion-item.item { } &.ion-valid, - &.ion-invalid { + &.ion-invalid, + &.item-has-interactive-control { &.item-lines-default { --border-width: 0 0 1px 0; } diff --git a/src/theme/components/ion-radio.scss b/src/theme/components/ion-radio.scss index ef14fe5aa..80a361faa 100644 --- a/src/theme/components/ion-radio.scss +++ b/src/theme/components/ion-radio.scss @@ -1,5 +1,63 @@ -ion-radio { - &.radio-disabled::part(label) { - opacity: 0.8; + +// Radio. +ion-radio, +input[type=radio], +.select-alert .alert-radio-icon { + --border-radius: 50%; + --border-width: 2px; + --outer-border-width: 2px; + --border-style: solid; + --size: 20px; + + &:not(.ion-color) { + --color: var(--text-color); + --color-checked: var(--color); + } +} + +.ios ion-radio, +.ios input[type=radio], +.select-alert.ios .alert-radio-icon { + --border-width: 1px; + --outer-border-width: 1px; +} + +.ios ion-radio { + &::part(container) { + width: var(--size); + height: var(--size); + + margin: 0px; + border-radius: var(--border-radius); + border-width: var(--outer-border-width); + border-style: var(--border-style); + border-color: var(--color); + } + + &::part(mark) { + border-radius: var(--inner-border-radius); + width: calc(50% + var(--outer-border-width)); + height: calc(50% + var(--outer-border-width)); + transform: scale3d(0, 0, 0); + transition: transform 280ms cubic-bezier(.4, 0, .2, 1); + background: var(--contrast-background); + border: 0 !important; + } + + &.radio-checked { + &::part(container) { + border-color: var(--color); + background: var(--color); + } + + &::part(mark) { + transform: scale3d(1, 1, 1); + } + } +} + +ion-radio { + &.radio-disabled::part(label) { + opacity: var(--mdl-input-disabled-opacity); } } diff --git a/src/theme/components/ion-select.scss b/src/theme/components/ion-select.scss index 43a07803c..597e47f11 100644 --- a/src/theme/components/ion-select.scss +++ b/src/theme/components/ion-select.scss @@ -7,7 +7,7 @@ ion-select { opacity: 1; } &.select-disabled { - opacity: 0.8; + opacity: var(--mdl-input-disabled-opacity); } } diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index 7063ca260..43e6b0cae 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -111,10 +111,6 @@ button, } } -ion-fab-button { - --box-shadow: 0 3px 5px -1px rgb(0 0 0 / 20%), 0 6px 10px 0 rgb(0 0 0 / 14%), 0 1px 18px 0 rgb(0 0 0 / 12%); -} - [role="button"], .clickable { cursor: pointer; @@ -123,14 +119,14 @@ ion-fab-button { [disabled], [aria-disabled="true"] { cursor: default; - opacity: .4; + opacity: var(--mdl-button-disabled-opacity); pointer-events: none; } } button[disabled] { cursor: default; - opacity: .4; + opacity: var(--mdl-button-disabled-opacity); pointer-events: none; } @@ -188,72 +184,6 @@ div.core-iframe-network-error { left: -15%; } -ion-alert.core-nohead .alert-head, -ion-alert .alert-head:empty { - padding-bottom: 0; -} - -@keyframes scaleFrom0 { - from { - /* More performant than animating `width` */ - transform: scaleX(0); - } -} - -ion-alert .alert-button.timed-button{ - position: relative; - - &::before { - content: ''; - position: absolute; - width: 100%; - left: 0; - right: 0; - bottom: 0; - top: 0; - background-color: var(--primary-tint); - animation: scaleFrom0 10s forwards linear; - transform-origin: left; - @include rtl() { - transform-origin: right; - } - z-index: -1; - } -} - -ion-alert { - --border-radius: var(--modal-radius); - - &.md, &.ios { - --max-width: 80%; - - @include media-breakpoint-up(md) { - --max-width: 384px; - } - } - - .alert-wrapper { - overflow: auto; - border-radius: var(--border-radius) !important; - - button.alert-button.alert-button-role-destructive { - color: var(--danger); - } - - } - - .alert-message { - user-select: text; - flex-shrink: 0; - - ion-card { - margin: 0; - margin-top: 10px; - } - - } -} - // Ionic list. ion-list { padding: 0 !important; @@ -545,103 +475,12 @@ ion-content.limited-width > :not([slot]) { min-height: 100%; } -// Radio. -ion-radio, -input[type=radio], -.select-alert .alert-radio-icon { - --border-radius: 50%; - --border-width: 2px; - --outer-border-width: 2px; - --border-style: solid; - --size: 20px; - - &:not(.ion-color) { - --color: var(--text-color); - --color-checked: var(--color); - } -} - -.ios ion-radio, -.ios input[type=radio], -.select-alert.ios .alert-radio-icon { - --border-width: 1px; - --outer-border-width: 1px; -} - -.ios ion-radio { - &::part(container) { - width: var(--size); - height: var(--size); - - margin: 0px; - border-radius: var(--border-radius); - border-width: var(--outer-border-width); - border-style: var(--border-style); - border-color: var(--color); - } - - &::part(mark) { - border-radius: var(--inner-border-radius); - width: calc(50% + var(--outer-border-width)); - height: calc(50% + var(--outer-border-width)); - transform: scale3d(0, 0, 0); - transition: transform 280ms cubic-bezier(.4, 0, .2, 1); - background: var(--contrast-background); - border: 0 !important; - } - - &.radio-checked { - &::part(container) { - border-color: var(--color); - background: var(--color); - } - - &::part(mark) { - transform: scale3d(1, 1, 1); - } - } -} - - -// Checkbox. -ion-checkbox, -input[type=checkbox] { - --border-radius: 2px; - --border-width: 2px; - --outer-border-width: 2px; - --border-style: solid; - --size: 20px; - - &:not(.ion-color) { - --border-color-checked: var(--text-color); - --checkbox-background-checked: var(--text-color); - --checkmark-color: var(--contrast-background); - } -} - -.ios input[type=checkbox] { - --outer-border-width: 1px; -} - ion-badge { line-height: 1.1; padding: 2px 8px; border-radius: var(--mdl-shape-borderRadius-lg); } -// File uploader. -.action-sheet-button input.core-fileuploader-file-handler-input { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - min-width: 100%; - opacity: 0; - z-index: 100; - cursor: pointer; -} - .core-anchor, core-format-text a { color: var(--core-link-color); cursor: pointer; @@ -721,37 +560,6 @@ textarea:not([core-auto-rows]) { height: 200px; } -// Hide close button because when present is read on voice over. -ion-fab[core-fab] { - ion-fab-button::part(close-icon) { - display: none; - } -} - -// The following 4 selectors can probably be removed after Ionic migration to 7+ -ion-fab.fab-horizontal-start { - left: calc(10px + var(--ion-safe-area-right, 0px)); -} - -[dir=rtl] ion-fab.fab-horizontal-start { - right: calc(10px + var(--ion-safe-area-right, 0px)); - left: unset -} - -ion-fab.fab-horizontal-end { - right: calc(10px + var(--ion-safe-area-right, 0px)); -} - -[dir=rtl] ion-fab.fab-horizontal-end { - left: calc(10px + var(--ion-safe-area-right, 0px)); - right: unset -} - -ion-content.has-collapsible-footer ion-fab { - bottom: calc(var(--core-collapsible-footer-height, 0px) + 10px); - @include core-transition(all, 200ms); -} - .core-media-adapt-width { max-width: 100%; } @@ -766,10 +574,8 @@ audio.core-media-adapt-width { // Disabled items. ion-item.item-disabled, -ion-button.button-disabled, -ion-item.item-interactive-disabled:not(.item-multiple-inputs) ion-label, -ion-datetime.datetime-disabled { - opacity: .65 !important; +ion-item.item-interactive-disabled:not(.item-multiple-inputs) ion-label { + opacity: var(--mdl-item-disabled-opacity) !important; } ion-item-divider.item, @@ -803,7 +609,7 @@ ion-input input, ion-textarea, core-rich-text-editor { --placeholder-color: var(--ion-placeholder-color); - --placeholder-opacity: .65; + --placeholder-opacity: var(--mdl-placeholder-opacity); } // Disable scroll on parent ion contents to enabled PTR on the ones inside the splitview. See split-view component for more info. @@ -992,18 +798,6 @@ video::-webkit-media-text-track-display { display: none !important; } -// Ion Datetime -ion-item.item-label-stacked ion-datetime-button { - margin-top: 8px; - margin-bottom: 8px; - align-self: self-end; -} - -ion-datetime-button p { - margin-top: 4px; - margin-bottom: 4px; -} - .x-scrollable { overflow-x: auto; display: block; diff --git a/src/theme/theme.design-system.scss b/src/theme/theme.design-system.scss index 0d10bf1a6..efc3323fa 100644 --- a/src/theme/theme.design-system.scss +++ b/src/theme/theme.design-system.scss @@ -140,6 +140,12 @@ html { --mdl-shadow-boxShadow-16: 0px 7px 8px 0px rgb(var(--mdl-shadow-boxShadowColor) / 20%),0px 5px 22px 0px rgb(var(--mdl-shadow-boxShadowColor) / 12%),0px 12px 17px 0px rgb(var(--mdl-shadow-boxShadowColor) / 14%); --mdl-shadow-boxShadow-24: 0px 11px 15px 0px rgb(var(--mdl-shadow-boxShadowColor) / 20%), 0px 9px 46px 0px rgb(var(--mdl-shadow-boxShadowColor) / 12%), 0px 24px 38px 0px rgb(var(--mdl-shadow-boxShadowColor) / 14%); + // ***** OPACITY category ***** // + --mdl-button-disabled-opacity: 0.6; + --mdl-input-disabled-opacity: 0.6; + --mdl-item-disabled-opacity: 0.4; + --mdl-placeholder-opacity: 0.6; + // ***** ACCESSIBILITY ***** // --a11y-sizing-minTargetSize: 44px; --a11y-shadow-focus-borderWidth: 2px; diff --git a/src/theme/theme.scss b/src/theme/theme.scss index eee5ac6f5..11ccfb456 100644 --- a/src/theme/theme.scss +++ b/src/theme/theme.scss @@ -36,6 +36,8 @@ html { @import "components/ion-checkbox.scss"; @import "components/ion-chip.scss"; @import "components/ion-content.scss"; + @import "components/ion-datetime.scss"; + @import "components/ion-fab.scss"; @import "components/ion-header.scss"; @import "components/ion-icon.scss"; @import "components/ion-input.scss";