diff --git a/.vscode/settings.json b/.vscode/settings.json index f7faf397e2..9090917732 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -30,7 +30,7 @@ "editor.defaultFormatter": "vscode.json-language-features" }, "sonarlint.connectedMode.project": { - "connectionId": "outsystems", + "connectionId": "outsystemsrd", "projectKey": "OutSystems_outsystems-ui" } } \ No newline at end of file diff --git a/src/scripts/OSFramework/OSUI/GlobalEnum.ts b/src/scripts/OSFramework/OSUI/GlobalEnum.ts index 79c0b3cdf9..eb55922144 100644 --- a/src/scripts/OSFramework/OSUI/GlobalEnum.ts +++ b/src/scripts/OSFramework/OSUI/GlobalEnum.ts @@ -16,6 +16,7 @@ namespace OSFramework.OSUI.GlobalEnum { AsideExpandable = 'aside-expandable', Container = 'screen-container', Content = 'content', + DarkMode = 'os-dark-mode', DeprecatedSubmenu = 'submenu', Footer = 'footer', Header = 'header', @@ -23,6 +24,7 @@ namespace OSFramework.OSUI.GlobalEnum { HeaderIsFixed = 'fixed-header', HeaderIsVisible = 'header-is--visible', HeaderTopContent = 'header-top-content', + HighContrast = 'os-high-contrast', InputNotValid = 'not-valid', IsTouch = 'is--touch', Layout = 'layout', @@ -208,6 +210,7 @@ namespace OSFramework.OSUI.GlobalEnum { AnimationEnd = 'animationend', AnimationStart = 'animationstart', Blur = 'blur', + Change = 'change', Click = 'click', Focus = 'focus', keyDown = 'keydown', diff --git a/src/scripts/OSFramework/OSUI/Pattern/AnimatedLabel/scss/_animated-label.scss b/src/scripts/OSFramework/OSUI/Pattern/AnimatedLabel/scss/_animated-label.scss index 3a85e8b053..759290a5ae 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/AnimatedLabel/scss/_animated-label.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/AnimatedLabel/scss/_animated-label.scss @@ -160,8 +160,6 @@ // Accessibility -------------------------------------------------------------------- /// - -/* Accessibility Styles */ .has-accessible-features { .animated-label-input { .form-control[data-input] { @@ -177,3 +175,28 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .animated-label-text { + font-weight: var(--font-semi-bold); + padding: var(--space-none) var(--space-s); + } + + .animated-label { + &.active { + .animated-label-text { + background-color: var(--color-neutral-8); + font-size: var(--font-size-s); + top: -16px; + } + } + } + + .animated-label-input { + .form-control[data-input] { + padding: var(--space-none) var(--space-s); + } + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/BottomSheet/scss/_bottomsheet.scss b/src/scripts/OSFramework/OSUI/Pattern/BottomSheet/scss/_bottomsheet.scss index f07c71c4bf..da42082b6a 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/BottomSheet/scss/_bottomsheet.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/BottomSheet/scss/_bottomsheet.scss @@ -197,3 +197,11 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-bottom-sheet { + border: var(--border-size-s) solid var(--color-neutral-0); + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/ButtonLoading/scss/_button-loading.scss b/src/scripts/OSFramework/OSUI/Pattern/ButtonLoading/scss/_button-loading.scss index 68eaca52c9..9a4bfa0438 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/ButtonLoading/scss/_button-loading.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/ButtonLoading/scss/_button-loading.scss @@ -61,7 +61,7 @@ animation: loadingSpinner 850ms cubic-bezier(0.7, 1.05, 0.78, 0.78) infinite; border: var(--border-size-m) solid currentColor; border-radius: var(--border-radius-circle); - border-top: var(--border-size-m) solid transparent; + border-top-color: transparent; height: 16px; margin-right: var(--space-s); width: 16px; @@ -111,3 +111,17 @@ width: 100%; } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-btn-loading { + .btn { + .osui-btn-loading__spinner-animation { + border-width: var(--border-size-l); + border-bottom: none; + border-top: none; + } + } + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/Carousel/scss/_carousel.scss b/src/scripts/OSFramework/OSUI/Pattern/Carousel/scss/_carousel.scss index b0e539588b..ac347aaab2 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Carousel/scss/_carousel.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Carousel/scss/_carousel.scss @@ -119,7 +119,6 @@ & { -servicestudio-position: relative; } - } .list:not([data-virtualization-disabled]), @@ -143,6 +142,7 @@ } } +// Accessibility ----------------------------------------------------------------- /// .has-accessible-features { .splide__slide { @@ -150,8 +150,22 @@ } } +// OS HighContrast Enabled ------------------------------------------------------- /// +.os-high-contrast { + .splide__pagination { + &__page { + @include a11y-high-contrast-outline; + } + + li { + margin: var(--space-none) var(--space-xs); + } + } +} + // RTL for dynamic changes of direction +/// .is-rtl { .splide.splide { &--ltr { @@ -174,4 +188,3 @@ } } } - diff --git a/src/scripts/OSFramework/OSUI/Pattern/Dropdown/ServerSide/scss/_dropdown-serverside.scss b/src/scripts/OSFramework/OSUI/Pattern/Dropdown/ServerSide/scss/_dropdown-serverside.scss index eb353cb2a4..6508a3ef10 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Dropdown/ServerSide/scss/_dropdown-serverside.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Dropdown/ServerSide/scss/_dropdown-serverside.scss @@ -352,6 +352,16 @@ $balloonMobileTopMargin: 5vh; } } +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .has-accessible-features .osui-dropdown-serverside__balloon-content:focus { + --osui-outline-size: 0; + + @include a11y-high-contrast-outline(true); + } +} + // IsRTL ------------------------------------------------------------------------- /// .is-rtl { diff --git a/src/scripts/OSFramework/OSUI/Pattern/DropdownServerSideItem/scss/_dropdownserversideitem.scss b/src/scripts/OSFramework/OSUI/Pattern/DropdownServerSideItem/scss/_dropdownserversideitem.scss index 157141b4c6..b7f681ed2f 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/DropdownServerSideItem/scss/_dropdownserversideitem.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/DropdownServerSideItem/scss/_dropdownserversideitem.scss @@ -61,6 +61,28 @@ } } +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-dropdown-serverside-item { + &:hover, + &:focus { + outline: none; + + &:before { + @include a11y-high-contrast-outline(true); + bottom: 0; + content: ''; + display: block; + left: 0; + position: absolute; + right: 0; + top: 0; + } + } + } +} + // Responsive -------------------------------------------------------------------- /// .tablet, diff --git a/src/scripts/OSFramework/OSUI/Pattern/OverflowMenu/scss/_overflowmenu.scss b/src/scripts/OSFramework/OSUI/Pattern/OverflowMenu/scss/_overflowmenu.scss index fc9c84fdd8..5c06fcd488 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/OverflowMenu/scss/_overflowmenu.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/OverflowMenu/scss/_overflowmenu.scss @@ -4,67 +4,81 @@ /// Patterns - Navigation - OverflowMenu .osui-overflow-menu { - display: inline-block; - --osui-overflow-menu-min-width: 170px; - --border-radius-rounded: 16px; + display: inline-block; + --osui-overflow-menu-min-width: 170px; + --border-radius-rounded: 16px; - &__trigger { - --osui-floating-offset: var(--space-s); + &__trigger { + --osui-floating-offset: var(--space-s); - border: var(--border-size-s) solid transparent; - border-radius: var(--osui-overflow-menu-shape); - color: var(--color-neutral-9); - width: 32px; + border: var(--border-size-s) solid transparent; + border-radius: var(--osui-overflow-menu-shape); + color: var(--color-neutral-9); + width: 32px; - * { - pointer-events: none; - } - } + * { + pointer-events: none; + } + } - &--is-open { - .osui-overflow-menu__trigger { - background-color: var(--color-neutral-4); - } - } - - &__balloon { - min-width: var(--osui-overflow-menu-min-width); - overflow: hidden; + &--is-open { + .osui-overflow-menu__trigger { + background-color: var(--color-neutral-4); + } + } - a { - color: var(--color-neutral-9); - - &:hover { - background: var(--color-neutral-4); - text-decoration: none; - } + &__balloon { + min-width: var(--osui-overflow-menu-min-width); + overflow: hidden; - // Service Studio Preview - & { - -servicestudio-align-items: center; - -servicestudio-display: inline-flex!important; - -servicestudio-color:var(--color-neutral-9); - -servicestudio-padding: var(--space-s) var(--space-base); - } - } - - // To make extensibility with ExtendedClass easier - a:not([class^='padding-']){ - padding:var(--space-s) var(--space-base); - } - } + a { + color: var(--color-neutral-9); + + &:hover { + background: var(--color-neutral-4); + text-decoration: none; + } + + // Service Studio Preview + & { + -servicestudio-align-items: center; + -servicestudio-display: inline-flex !important; + -servicestudio-color: var(--color-neutral-9); + -servicestudio-padding: var(--space-s) var(--space-base); + } + } + + // To make extensibility with ExtendedClass easier + a:not([class^='padding-']) { + padding: var(--space-s) var(--space-base); + } + } } .tablet, .phone { - .osui-overflow-menu { - --border-radius-rounded: 100%; + .osui-overflow-menu { + --border-radius-rounded: 100%; - .osui-overflow-menu__trigger { - &.btn { - // Longer specificity to be able to always override default responsive styles for buttons - width: 40px; - } - } - } -} \ No newline at end of file + .osui-overflow-menu__trigger { + &.btn { + // Longer specificity to be able to always override default responsive styles for buttons + width: 40px; + } + } + } +} + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-overflow-menu__balloon { + border: var(--border-size-s) solid var(--color-neutral-7); + + a { + &:hover { + @include a11y-high-contrast-outline; + } + } + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/Progress/Bar/scss/_progressbar.scss b/src/scripts/OSFramework/OSUI/Pattern/Progress/Bar/scss/_progressbar.scss index af891e9267..5a3cc4cd82 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Progress/Bar/scss/_progressbar.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Progress/Bar/scss/_progressbar.scss @@ -107,3 +107,27 @@ right: 0; } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-progress { + &-bar { + &__container { + min-height: calc(2 * var(--thickness)); + } + + &__value { + border: var(--border-size-m) solid var(--color-neutral-7); + height: calc(2 * var(--thickness)); + + &:before, + &:after { + border: var(--border-size-m) solid var(--color-neutral-7); + top: calc(-1 * var(--border-size-m)); + left: calc(-1 * var(--border-size-m)); + } + } + } + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/RangeSlider/scss/_rangeslider.scss b/src/scripts/OSFramework/OSUI/Pattern/RangeSlider/scss/_rangeslider.scss index dc7728b1b4..b32efc1a67 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/RangeSlider/scss/_rangeslider.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/RangeSlider/scss/_rangeslider.scss @@ -274,11 +274,34 @@ .noUi-handle:focus { border-color: var(--color-focus-inner); - box-shadow: 0 0 0 3px var(--color-focus-outer); + @include a11y-default-outline; } } } +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-range-slider { + .noUi-horizontal { + height: calc(2 * var(--range-slider-thickness)); + } + + .noUi-vertical { + width: calc(2 * var(--range-slider-thickness)); + } + + .noUi-connect, + .noUi-base { + border: var(--border-size-m) solid var(--color-neutral-7); + } + } + + .has-accessible-features .osui-range-slider { + border: 0; + } +} + // IsRTL ------------------------------------------------------------------------- /// .is-rtl { @@ -292,8 +315,7 @@ } /* Z-index overrides */ -.noUi-origin -.noUi-base, +.noUi-origin .noUi-base, .noUi-connect { z-index: var(--layer-local-tier-1); } diff --git a/src/scripts/OSFramework/OSUI/Pattern/Rating/scss/_rating.scss b/src/scripts/OSFramework/OSUI/Pattern/Rating/scss/_rating.scss index 77cf3fa8b5..41c8933913 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Rating/scss/_rating.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Rating/scss/_rating.scss @@ -109,6 +109,10 @@ &:last-of-type { padding-right: 0; } + + img { + max-width: none; + } } input { @@ -313,3 +317,19 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .has-accessible-features { + .rating { + &.is-half input:focus + .rating-item .rating-item-half, + &:not(.is-half) input:focus + .rating-item .rating-item-filled { + &, + * { + @include a11y-high-contrast-outline; + } + } + } + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/SectionIndex/scss/_sectionindex.scss b/src/scripts/OSFramework/OSUI/Pattern/SectionIndex/scss/_sectionindex.scss index e5d06d72f6..d81dd63ddc 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/SectionIndex/scss/_sectionindex.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/SectionIndex/scss/_sectionindex.scss @@ -67,7 +67,23 @@ .osui-section-index-item { &:focus { background-color: transparent; - box-shadow: 0 0 0 3px var(--color-focus-outer); + @include a11y-default-outline; + } + } +} + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-section-index::before { + @include a11y-high-contrast-outline(true, var(--border-size-s), left); + } + + .osui-section-index-item { + &--is-active { + &::before { + @include a11y-high-contrast-outline(true, var(--border-size-l), left); + } } } } diff --git a/src/scripts/OSFramework/OSUI/Pattern/Sidebar/scss/_sidebar.scss b/src/scripts/OSFramework/OSUI/Pattern/Sidebar/scss/_sidebar.scss index a0073af5bd..90fbdc01fb 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Sidebar/scss/_sidebar.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Sidebar/scss/_sidebar.scss @@ -207,3 +207,16 @@ max-width: 85vw; } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .active-screen { + .osui-sidebar { + &--is-open { + @include a11y-high-contrast-outline(true, var(--border-size-m), 'left'); + @include a11y-high-contrast-outline(true, var(--border-size-m), 'right'); + } + } + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/Submenu/scss/_submenu.scss b/src/scripts/OSFramework/OSUI/Pattern/Submenu/scss/_submenu.scss index 21516f9c7c..9a0fd1566e 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Submenu/scss/_submenu.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Submenu/scss/_submenu.scss @@ -228,26 +228,26 @@ .osui-submenu { flex-direction: column; width: 100%; - + &.active .osui-submenu__header { border-left: var(--border-size-m) solid var(--color-primary); } - + &--is-open > .osui-submenu__items { display: flex; } - + .osui-submenu__header { border-bottom: 0; border-left: var(--border-size-m) solid transparent; border-top: 0; padding: var(--space-s) var(--space-m); - + &__item { flex: 1; } } - + &__items { border: none; box-shadow: none; @@ -258,7 +258,7 @@ position: relative; top: 0; transform: translateY(0); - + a { padding: var(--space-s) var(--space-base); } @@ -431,3 +431,16 @@ margin-right: var(--space-s); } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .layout:not(.layout-side) .app-menu-links .osui-submenu a { + border-top: none; + border-bottom: none; + } + + .osui-submenu__header { + border-top: none; + } +} diff --git a/src/scripts/OSFramework/OSUI/Pattern/Tabs/scss/_tabs.scss b/src/scripts/OSFramework/OSUI/Pattern/Tabs/scss/_tabs.scss index 31a2641728..4e8ec2f161 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Tabs/scss/_tabs.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Tabs/scss/_tabs.scss @@ -363,6 +363,47 @@ } } +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-tabs__header__indicator { + display: none; + } + + .osui-tabs__content-item { + position: relative; + } + + .osui-tabs__header-item:focus, + .osui-tabs__content-item :focus { + outline: none; + } + + .osui-tabs__header-item:focus:before, + .osui-tabs__header-item.osui-tabs--is-active:before, + .osui-tabs__content-item:focus:before, + .osui-tabs__content-item.osui-tabs--is-active:before { + @include a11y-high-contrast-outline(true, var(--border-size-m)); + bottom: 0; + content: ''; + display: block; + left: 0; + pointer-events: none; + position: absolute; + right: 0; + top: 0; + } + + .osui-tabs__header-item:focus:before, + .osui-tabs__content-item:focus:before { + border-width: var(--border-size-l); + } + + .osui-tabs__content-item { + padding: var(--space-base); + } +} + // Issue on accordion in webkit .windows.chrome, .windows.edge, diff --git a/src/scripts/OSFramework/OSUI/Pattern/Tooltip/scss/_tooltip.scss b/src/scripts/OSFramework/OSUI/Pattern/Tooltip/scss/_tooltip.scss index b8aa321da0..341d573640 100644 --- a/src/scripts/OSFramework/OSUI/Pattern/Tooltip/scss/_tooltip.scss +++ b/src/scripts/OSFramework/OSUI/Pattern/Tooltip/scss/_tooltip.scss @@ -91,3 +91,19 @@ text-wrap: wrap; } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .osui-tooltip { + .osui-balloon { + border: var(--border-size-s) solid var(--osui-tooltip-background-color); + } + + &__balloon-arrow { + border: 0 solid var(--osui-tooltip-background-color); + border-right-width: var(--border-size-s); + border-bottom-width: var(--border-size-s); + } + } +} diff --git a/src/scripts/OutSystems/OSUI/Utils/LayoutPrivateBodyCssVars.ts b/src/scripts/OutSystems/OSUI/Utils/LayoutPrivateBodyCssVars.ts index 678c4ca6ad..eab67a8de2 100644 --- a/src/scripts/OutSystems/OSUI/Utils/LayoutPrivateBodyCssVars.ts +++ b/src/scripts/OutSystems/OSUI/Utils/LayoutPrivateBodyCssVars.ts @@ -1,9 +1,145 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars namespace OutSystems.OSUI.Utils.LayoutPrivate { export abstract class CssBodyVariables { - // Function that will set the css variables to body element + /** + * Method that will check if dark mode is active + * + * @private + * @static + * @param {(isDarkMode: boolean) => void} callback + * @memberof CssBodyVariables + */ + private static _checkDarkModeStatus(callback: (isDarkMode: boolean) => void): void { + if (typeof window !== 'undefined' && window.matchMedia) { + // Set the media query to check for dark mode + const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); + + // Initial check, that's passed through the callback function argument + callback(darkModeQuery.matches); + + // Listen for changes + const listener = (event: MediaQueryListEvent) => { + callback(event.matches); + }; + + // Add the event that will detect dark mode when it changes + darkModeQuery.addEventListener(OSFramework.OSUI.GlobalEnum.HTMLEvent.Change, listener); + } else { + console.warn('Dark mode detection is not supported at this context.'); + callback(false); + } + } + + /** + * Method that will check if highContrast mode is active + * + * @private + * @static + * @param {(isHighContrast: boolean) => void} callback + * @memberof CssBodyVariables + */ + private static _checkHighContrastStatus(callback: (isHighContrast: boolean) => void): void { + if (typeof window !== 'undefined' && window.matchMedia) { + // Set the media query to check for highContrast mode + const highContrastModeQuery = window.matchMedia('(forced-colors: active)'); + + // Initial check, that's passed through the callback function argument + callback(highContrastModeQuery.matches); + + // Listen for changes + const listener = (event: MediaQueryListEvent) => { + callback(event.matches); + }; + + // Add the event that will detect highContrast mode when it changes + highContrastModeQuery.addEventListener(OSFramework.OSUI.GlobalEnum.HTMLEvent.Change, listener); + } else { + console.warn('HighContrast mode detection is not supported at this context.'); + callback(false); + } + } + + /** + * Method to set body css variables for a phone or tablet app + * + * @private + * @static + * @memberof CssBodyVariables + */ + private static _isPhoneOrTablet(): void { + OSFramework.OSUI.Helper.Dom.Styles.SetStyleAttribute( + document.body, + OSFramework.OSUI.GlobalEnum.CSSVariables.ViewportHeight, + window.innerHeight + OSFramework.OSUI.GlobalEnum.Units.Pixel + ); + } + + /** + * Method that will set the css variables to body element + * + * @private + * @static + * @memberof CssBodyVariables + */ private static _setCssVars(): void { - const body = document.body; + // Ensure app is not a web app + if (OSUI.Utils.DeviceDetection.IsWebApp() === false) { + this._setNotWebApp(); + } + + // Check if app is running on a phone or tablet device + if ( + OSFramework.OSUI.Helper.Dom.Styles.ContainsClass( + document.body, + OSFramework.OSUI.GlobalEnum.DeviceType.phone + ) || + OSFramework.OSUI.Helper.Dom.Styles.ContainsClass( + document.body, + OSFramework.OSUI.GlobalEnum.DeviceType.tablet + ) + ) { + this._isPhoneOrTablet(); + } + + // Check if highContrast mode is active + this._checkHighContrastStatus((isHighContrast) => { + if (isHighContrast) { + OSFramework.OSUI.Helper.Dom.Styles.AddClass( + document.body, + OSFramework.OSUI.GlobalEnum.CssClassElements.HighContrast + ); + } else { + OSFramework.OSUI.Helper.Dom.Styles.RemoveClass( + document.body, + OSFramework.OSUI.GlobalEnum.CssClassElements.HighContrast + ); + } + }); + + // Check if dark mode is active + this._checkDarkModeStatus((isDarkMode) => { + if (isDarkMode) { + OSFramework.OSUI.Helper.Dom.Styles.AddClass( + document.body, + OSFramework.OSUI.GlobalEnum.CssClassElements.DarkMode + ); + } else { + OSFramework.OSUI.Helper.Dom.Styles.RemoveClass( + document.body, + OSFramework.OSUI.GlobalEnum.CssClassElements.DarkMode + ); + } + }); + } + + /** + * Method to set body css variables for non web app + * + * @private + * @static + * @memberof CssBodyVariables + */ + private static _setNotWebApp(): void { const headerContent = OSFramework.OSUI.Helper.Dom.ClassSelector( document, OSFramework.OSUI.GlobalEnum.CssClassElements.HeaderTopContent @@ -13,38 +149,28 @@ namespace OutSystems.OSUI.Utils.LayoutPrivate { OSFramework.OSUI.GlobalEnum.CssClassElements.Footer ); - if (OSUI.Utils.DeviceDetection.IsWebApp() === false) { - if (headerContent) { - OSFramework.OSUI.Helper.Dom.Styles.SetStyleAttribute( - body, - OSFramework.OSUI.GlobalEnum.CSSVariables.HeaderContentHeight, - headerContent.getBoundingClientRect().height + OSFramework.OSUI.GlobalEnum.Units.Pixel - ); - } - - if (footer) { - OSFramework.OSUI.Helper.Dom.Styles.SetStyleAttribute( - body, - OSFramework.OSUI.GlobalEnum.CSSVariables.FooterHeight, - footer.getBoundingClientRect().height + OSFramework.OSUI.GlobalEnum.Units.Pixel - ); - } + if (headerContent) { + OSFramework.OSUI.Helper.Dom.Styles.SetStyleAttribute( + document.body, + OSFramework.OSUI.GlobalEnum.CSSVariables.HeaderContentHeight, + headerContent.getBoundingClientRect().height + OSFramework.OSUI.GlobalEnum.Units.Pixel + ); } - if ( - OSFramework.OSUI.Helper.Dom.Styles.ContainsClass(body, OSFramework.OSUI.GlobalEnum.DeviceType.phone) || - OSFramework.OSUI.Helper.Dom.Styles.ContainsClass(body, OSFramework.OSUI.GlobalEnum.DeviceType.tablet) - ) { + if (footer) { OSFramework.OSUI.Helper.Dom.Styles.SetStyleAttribute( - body, - OSFramework.OSUI.GlobalEnum.CSSVariables.ViewportHeight, - window.innerHeight + OSFramework.OSUI.GlobalEnum.Units.Pixel + document.body, + OSFramework.OSUI.GlobalEnum.CSSVariables.FooterHeight, + footer.getBoundingClientRect().height + OSFramework.OSUI.GlobalEnum.Units.Pixel ); } } /** - * Function used to trigger the setCss inline variables to body + * Method that will trigger the setCss functionality + * + * @static + * @memberof CssBodyVariables */ public static Set(): void { this._setCssVars(); diff --git a/src/scripts/Providers/OSUI/Dropdown/VirtualSelect/scss/_virtualselect.scss b/src/scripts/Providers/OSUI/Dropdown/VirtualSelect/scss/_virtualselect.scss index 51ecf56034..76970ea08b 100644 --- a/src/scripts/Providers/OSUI/Dropdown/VirtualSelect/scss/_virtualselect.scss +++ b/src/scripts/Providers/OSUI/Dropdown/VirtualSelect/scss/_virtualselect.scss @@ -533,6 +533,61 @@ } } +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .vscomp-wrapper { + &.show-value-as-tags { + .vscomp-value-tag { + border: var(--border-size-s) solid var(--color-neutral-7); + } + } + + .vscomp-option { + &.focused { + &:before { + border: var(--border-size-m) solid var(--color-neutral-7); + bottom: 0; + content: ''; + display: block; + left: 0; + position: absolute; + right: 0; + top: 0; + } + } + } + + &.multiple .vscomp-option { + &.selected .checkbox-icon { + &:after { + border-top: none; + border-left: none; + } + } + } + } + + .pop-comp-content, + .vscomp-dropbox-container { + border: var(--border-size-m) solid var(--color-neutral-7); + } + + .vscomp-options-container { + &::-webkit-scrollbar { + width: 5px; + } + + &::-webkit-scrollbar-track { + border: var(--border-size-l) solid var(--color-neutral-4); + } + + &::-webkit-scrollbar-thumb { + border: var(--border-size-s) solid var(--color-neutral-4); + } + } +} + // Responsive -------------------------------------------------------------------- /// .phone, diff --git a/src/scripts/Providers/OSUI/SharedProviderResources/Flatpickr/scss/_flatpickr.scss b/src/scripts/Providers/OSUI/SharedProviderResources/Flatpickr/scss/_flatpickr.scss index 329c96bf0f..14b11adb34 100644 --- a/src/scripts/Providers/OSUI/SharedProviderResources/Flatpickr/scss/_flatpickr.scss +++ b/src/scripts/Providers/OSUI/SharedProviderResources/Flatpickr/scss/_flatpickr.scss @@ -5,6 +5,7 @@ .flatpickr-calendar { --osui-flatpickr-layer: var(--layer-global-elevated); + border-radius: var(--border-radius-soft); border: var(--border-size-s) solid var(--color-neutral-5); box-shadow: var(--shadow-none); @@ -658,3 +659,157 @@ body:has(.has-accessible-features) .osui-monthpicker__dropdown { } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .flatpickr-rContainer, + .flatpickr-days, + .flatpickr-monthSelect-months { + padding: var(--space-xs); + } + + .flatpickr-calendar { + &.arrowTop:before, + &.arrowTop:after, + &.arrowBottom:before, + &.arrowBottom:after { + display: none; + } + + .numInputWrapper { + span.arrowUp, + span.arrowDown { + display: none; + } + } + } + + .flatpickr-current-month { + .numInputWrapper input { + padding: var(--space-none) var(--space-xs); + } + + .flatpickr-monthDropdown-months { + appearance: revert; + + &:focus, + &:active { + @include a11y-high-contrast-outline; + } + } + } + + .flatpickr-months { + .flatpickr-prev-month, + .flatpickr-next-month { + &:focus, + &:active { + @include a11y-high-contrast-outline; + } + } + } + + .flatpickr-day, + .flatpickr-monthSelect-months .flatpickr-monthSelect-month { + --osui-flatpickr-calendar-elems-layer: 0; + + border: none; + position: relative; + z-index: var(--osui-flatpickr-calendar-elems-layer); + + &:hover, + &:focus, + &:focus-visible { + z-index: calc(var(--osui-flatpickr-calendar-elems-layer) + var(--layer-local-tier-2)); + } + + &.today { + @include a11y-high-contrast-outline(true, var(--border-size-s)); + z-index: calc(var(--osui-flatpickr-calendar-elems-layer) + var(--layer-local-tier-1)); + } + + &.selected, + &.selected:focus, + &.selected:focus-visible, + &.selected:hover, + &.selected.inRange, + &.selected.prevMonthDay, + &.selected.nextMonthDay { + @include a11y-high-contrast-outline(true, var(--border-size-s)); + font-size: var(--font-size-base); + font-weight: var(--font-semi-bold); + } + + &:hover, + &:focus, + &:focus-visible, + &.inRange, + &.inRange:hover, + &.inRange:focus, + &.inRange:focus-visible, + &.today.inRange, + &.today.inRange:hover, + &.today.inRange:focus, + &.today.inRange:focus-visible { + font-size: var(--font-size-base); + font-weight: var(--font-semi-bold); + @include a11y-high-contrast-outline; + } + + &.inRange { + outline: none; + + &:before { + border-left: none; + border-radius: var(--border-radius-none); + border-right: none; + @include a11y-high-contrast-outline(true, var(--border-size-s)); + bottom: -1px; + content: ''; + display: block; + left: -2px; + position: absolute; + right: -2px; + top: -1px; + } + } + + // InRange Styles + &.selected.startRange, + &.startRange, + &.endRange.startRange, + &.selected.endRange, + &.startRange.endRange, + &.endRange.endRange { + border: none; + border-radius: var(--border-radius-none); + + &:before { + right: initial; + } + } + + &.selected.startRange, + &.startRange { + &:before { + border-radius: 50px 0 0 50px; + border-right: none; + @include a11y-high-contrast-outline(true, var(--border-size-s)); + left: 0; + right: -2px; + } + } + + &.selected.endRange, + &.endRange.endRange { + &:before { + border-left: none; + border-radius: 0 50px 50px 0; + @include a11y-high-contrast-outline(true, var(--border-size-s)); + left: -2px; + right: 0; + } + } + } +} diff --git a/src/scss/00-abstract/_mixins.scss b/src/scss/00-abstract/_mixins.scss index e6ef43985b..f615560aba 100644 --- a/src/scss/00-abstract/_mixins.scss +++ b/src/scss/00-abstract/_mixins.scss @@ -1,6 +1,24 @@ //// /// @group global +/// default outline style +@mixin a11y-default-outline { + box-shadow: 0 0 0 var(--border-size-l) var(--color-focus-outer); +} + +/// outline style for high contrast mode +@mixin a11y-high-contrast-outline($isBorder: false, $size: var(--border-size-l), $borderType: 'all') { + @if $isBorder == false { + outline: $size solid var(--color-focus-outer); + } @else { + @if $borderType == 'all' { + border: $size solid var(--color-focus-outer); + } @else { + border-#{$borderType}: $size solid var(--color-focus-outer); + } + } +} + /// AppLogo @mixin app-logo { border-radius: var(--border-radius-soft); diff --git a/src/scss/00-abstract/_setup-global-vars.scss b/src/scss/00-abstract/_setup-global-vars.scss index 0054ba7f29..ff7ca89a49 100644 --- a/src/scss/00-abstract/_setup-global-vars.scss +++ b/src/scss/00-abstract/_setup-global-vars.scss @@ -40,12 +40,25 @@ $osui-box-corners: 'top-left', 'top-right', 'bottom-right', 'bottom-left'; /* Space / Sizes */ /* ---------------------------------------------------------------------------- */ /// Predefined spaces / sizes -$osui-sizes: 'none' 0, 'xs' 4px, 's' 8px, 'base' 16px, 'm' 24px, 'l' 32px, 'xl' 40px, 'xxl' 48px; +$osui-sizes: + 'none' 0, + 'xs' 4px, + 's' 8px, + 'base' 16px, + 'm' 24px, + 'l' 32px, + 'xl' 40px, + 'xxl' 48px; /* ---------------------------------------------------------------------------- */ /* SHADOWS */ /* ---------------------------------------------------------------------------- */ /// Shadow Types -$osui-shadow-types: 'none' 'none', 'xs' '0 1px 2px rgba(0, 0, 0, 0.1)', 's' '0 2px 4px rgba(0, 0, 0, 0.1)', - 'm' '0 4px 6px rgba(0, 0, 0, 0.1)', 'l' '0 6px 8px rgba(0, 0, 0, 0.1)', 'xl' '0 8px 10px rgba(0, 0, 0, 0.1)'; +$osui-shadow-types: + 'none' 'none', + 'xs' '0 1px 2px rgba(0, 0, 0, 0.1)', + 's' '0 2px 4px rgba(0, 0, 0, 0.1)', + 'm' '0 4px 6px rgba(0, 0, 0, 0.1)', + 'l' '0 6px 8px rgba(0, 0, 0, 0.1)', + 'xl' '0 8px 10px rgba(0, 0, 0, 0.1)'; diff --git a/src/scss/01-foundations/_resets.scss b/src/scss/01-foundations/_resets.scss index 173ea92b13..b8ec7af859 100644 --- a/src/scss/01-foundations/_resets.scss +++ b/src/scss/01-foundations/_resets.scss @@ -60,7 +60,14 @@ body { /// .has-accessible-features :focus { - box-shadow: 0 0 0 3px var(--color-focus-outer); + @include a11y-default-outline; +} + +/// +.os-high-contrast .has-accessible-features :focus { + box-shadow: none; + + @include a11y-high-contrast-outline; } /* ============================================================================ */ diff --git a/src/scss/03-widgets/_button-group.scss b/src/scss/03-widgets/_button-group.scss index 1aab6a079c..8dd3ba5a1e 100644 --- a/src/scss/03-widgets/_button-group.scss +++ b/src/scss/03-widgets/_button-group.scss @@ -149,3 +149,20 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .button-group-item { + &.button-group-selected-item:before { + content: ''; + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + border: var(--border-size-l) solid var(--color-primary); + } + } +} diff --git a/src/scss/03-widgets/_feedback-message.scss b/src/scss/03-widgets/_feedback-message.scss index da02d75258..890a1d43d1 100644 --- a/src/scss/03-widgets/_feedback-message.scss +++ b/src/scss/03-widgets/_feedback-message.scss @@ -93,3 +93,25 @@ div.feedback-message-warning { } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .feedback-message { + border-width: var(--border-size-l); + border-style: solid; + + &.feedback-message-error { + border-color: var(--color-error); + } + &.feedback-message-info { + border-color: var(--color-info); + } + &.feedback-message-success { + border-color: var(--color-success); + } + &.feedback-message-warning { + border-color: var(--color-warning); + } + } +} diff --git a/src/scss/03-widgets/_list-item.scss b/src/scss/03-widgets/_list-item.scss index e3f0edb274..83ea0a6235 100644 --- a/src/scss/03-widgets/_list-item.scss +++ b/src/scss/03-widgets/_list-item.scss @@ -87,3 +87,31 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + &.desktop, + &.tablet.landscape { + .list { + .list-item:hover, + .list-item-selected { + position: relative; + + &:before { + @include a11y-high-contrast-outline(true, var(--border-size-s)); + border-right-width: 0; + border-left-width: var(--border-size-l); + bottom: 0; + content: ''; + display: block; + left: 0; + pointer-events: none; + position: absolute; + right: 0; + top: 0; + } + } + } + } +} diff --git a/src/scss/03-widgets/_popup.scss b/src/scss/03-widgets/_popup.scss index ffae8775f4..fa86718b15 100644 --- a/src/scss/03-widgets/_popup.scss +++ b/src/scss/03-widgets/_popup.scss @@ -50,3 +50,12 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .popup-dialog { + border: var(--border-size-s) solid var(--color-neutral-0); + border-radius: var(--border-radius-soft); + } +} diff --git a/src/scss/03-widgets/_switch.scss b/src/scss/03-widgets/_switch.scss index e8fd305555..0e98ac8d43 100644 --- a/src/scss/03-widgets/_switch.scss +++ b/src/scss/03-widgets/_switch.scss @@ -105,3 +105,25 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + [data-switch] { + &:empty:after { + align-items: center; + border: var(--border-size-s) solid var(--color-neutral-6); + content: '0'; + display: flex; + font-family: monospace; + font-size: var(--font-size-xs); + justify-content: center; + left: -1px; + top: 3px; + } + + &:checked:after { + content: '1'; + } + } +} diff --git a/src/scss/04-patterns/02-content/_floating-content.scss b/src/scss/04-patterns/02-content/_floating-content.scss index 72c7a1c1a0..364f1a126d 100644 --- a/src/scss/04-patterns/02-content/_floating-content.scss +++ b/src/scss/04-patterns/02-content/_floating-content.scss @@ -324,3 +324,13 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .floating { + &-button { + border: var(--border-size-m) solid var(--color-neutral-7); + } + } +} diff --git a/src/scss/04-patterns/03-interaction/_action-sheet.scss b/src/scss/04-patterns/03-interaction/_action-sheet.scss index a2d17daa08..41f5fdb9fb 100644 --- a/src/scss/04-patterns/03-interaction/_action-sheet.scss +++ b/src/scss/04-patterns/03-interaction/_action-sheet.scss @@ -149,3 +149,27 @@ } } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .action-sheet-container--visible .action-sheet { + background-color: var(--color-neutral-0); + @include a11y-high-contrast-outline(true); + } + + .action-sheet-actions { + --osui-action-sheet-actions-layer: 0; + + position: relative; + z-index: var(--osui-action-sheet-actions-layer); + + &:has(.btn:focus) { + z-index: calc(var(--osui-action-sheet-actions-layer) + var(--layer-local-tier-1)); + } + } + + .action-sheet-buttons { + overflow: visible; + } +} diff --git a/src/scss/04-patterns/04-navigation/_pagination.scss b/src/scss/04-patterns/04-navigation/_pagination.scss index d1a0b10efa..2900990682 100644 --- a/src/scss/04-patterns/04-navigation/_pagination.scss +++ b/src/scss/04-patterns/04-navigation/_pagination.scss @@ -146,3 +146,11 @@ border-color: var(--color-focus-inner); } } + +// OS HighContrast Enabled ------------------------------------------------------- +/// +.os-high-contrast { + .pagination-button.is--active { + @include a11y-high-contrast-outline; + } +}