diff --git a/packages/ui/resolution/ResolutionDecorator.js b/packages/ui/resolution/ResolutionDecorator.js index ee2854e85a..461dc94ddf 100644 --- a/packages/ui/resolution/ResolutionDecorator.js +++ b/packages/ui/resolution/ResolutionDecorator.js @@ -9,7 +9,15 @@ import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import hoc from '@enact/core/hoc'; -import {init, config as riConfig, defineScreenTypes, getResolutionClasses} from './resolution'; +import { + init, + calculateFontSize, + config as riConfig, + defineScreenTypes, + getResolutionClasses, + updateBaseFontSize, + updateScreenScale +} from './resolution'; /** * Default config for `ResolutionDecorator`. @@ -97,13 +105,29 @@ const ResolutionDecorator = hoc(defaultConfig, (config, Wrapped) => { static displayName = 'ResolutionDecorator'; static propTypes = /** @lends ui/resolution.ResolutionDecorator.prototype */ { - className: PropTypes.string + className: PropTypes.string, + + /** + * Screen Scale value for the large screen mode. + * Use this value to set the scale of the base font. + * This is the value that will be multiplied by pxPerRem, which is determined by the resolution. + * + * @type {Number} + * @default 1 + * @public + */ + screenScale: PropTypes.number + }; + + static defaultProps = { + screenScale: 1 }; constructor (props) { super(props); riConfig.intermediateScreenHandling = config.intermediateScreenHandling; riConfig.matchSmallerScreenType = config.matchSmallerScreenType; + updateScreenScale(this.props.screenScale); init({measurementNode: (typeof window !== 'undefined' && window)}); this.state = { resolutionClasses: '' @@ -116,6 +140,10 @@ const ResolutionDecorator = hoc(defaultConfig, (config, Wrapped) => { this.rootNode = ReactDOM.findDOMNode(this); } + componentDidUpdate (prevProps) { + if (prevProps.screenScale !== this.props.screenScale) updateBaseFontSize(calculateFontSize()); + } + componentWillUnmount () { if (config.dynamic) window.removeEventListener('resize', this.handleResize); } @@ -145,11 +173,17 @@ const ResolutionDecorator = hoc(defaultConfig, (config, Wrapped) => { } render () { + const {...rest} = this.props; + + delete rest.screenScale; + + if (this.props.screenScale) updateScreenScale(this.props.screenScale); + // Check if the classes are different from our previous classes let classes = getResolutionClasses(); if (this.props.className) classes += (classes ? ' ' : '') + this.props.className; - return ; + return ; } }; }); diff --git a/packages/ui/resolution/resolution.js b/packages/ui/resolution/resolution.js index 4028498a1b..447ade288f 100644 --- a/packages/ui/resolution/resolution.js +++ b/packages/ui/resolution/resolution.js @@ -1,6 +1,7 @@ let baseScreen, orientation, riRatio, + screenScale = 1, screenType, workspaceBounds = { width: (typeof window === 'object') ? window.innerWidth : 1920, @@ -201,11 +202,11 @@ function calculateFontSize (type) { let size; if (orientation === 'portrait' && config.orientationHandling === 'scale') { - size = scrObj.height / scrObj.width * scrObj.pxPerRem; + size = scrObj.height / (scrObj.width * scrObj.pxPerRem * screenScale); } else { - size = scrObj.pxPerRem; + size = scrObj.pxPerRem * screenScale; if (orientation === 'landscape' && shouldScaleFontSize) { - size = parseInt(workspaceBounds.height * scrObj.pxPerRem / scrObj.height); + size = parseInt(workspaceBounds.height * scrObj.pxPerRem * screenScale / scrObj.height); } } return size + 'px'; @@ -224,6 +225,17 @@ function updateBaseFontSize (size) { } } +/** + * @function + * @memberof ui/resolution + * @param {Number} screenScaleValue A value that adjusts the screen scaling. + * @returns {undefined} + * @private + */ +function updateScreenScale (screenScaleValue) { + screenScale = screenScaleValue; +} + /** * Returns the CSS classes for the given `type`. * @@ -332,7 +344,7 @@ function getAspectRatioName (type) { * @public */ function scale (px) { - return (riRatio || getRiRatio()) * px; + return (riRatio || getRiRatio()) * px * screenScale; } /** @@ -366,7 +378,7 @@ function unit (pixels, toUnit) { if (typeof pixels === 'string' && pixels.substr(-2) === 'px') pixels = parseInt(pixels.substr(0, pixels.length - 2)); if (typeof pixels !== 'number') return; - return (pixels / unitToPixelFactors[toUnit]) + '' + toUnit; + return (pixels / (screenScale * unitToPixelFactors[toUnit])) + '' + toUnit; } /** @@ -494,5 +506,8 @@ export { scaleToRem, selectSrc, unit, - unitToPixelFactors + unitToPixelFactors, + updateBaseFontSize, + updateScreenScale, + updateWorkspaceBounds }; diff --git a/packages/ui/resolution/tests/ResolutionDecorator-specs.js b/packages/ui/resolution/tests/ResolutionDecorator-specs.js index 99e46d0284..8fa8fcb745 100644 --- a/packages/ui/resolution/tests/ResolutionDecorator-specs.js +++ b/packages/ui/resolution/tests/ResolutionDecorator-specs.js @@ -1,6 +1,7 @@ import '@testing-library/jest-dom'; import {render, screen} from '@testing-library/react'; +import {updateBaseFontSize, calculateFontSize} from '../resolution'; import ResolutionDecorator from '../ResolutionDecorator'; describe('ResolutionDecorator Specs', () => { @@ -28,6 +29,23 @@ describe('ResolutionDecorator Specs', () => { expect(div).toHaveClass('enact-res-mhd'); }); + test('should change the base font size when screenScale prop changed', () => { + const before = 1; + + const Component = ResolutionDecorator('div'); + const {rerender} = render(); + const after = 2; + rerender( + + ); + + updateBaseFontSize(calculateFontSize()); + const value = document.documentElement.style.fontSize; + const expected = '72px'; + + expect(value).toBe(expected); + }); + test.skip('should update the resolution when the screen is resized', function () { // TODO: write a test }); diff --git a/packages/ui/resolution/tests/resolution-specs.js b/packages/ui/resolution/tests/resolution-specs.js index 4ac795c450..4d5b90ddb2 100644 --- a/packages/ui/resolution/tests/resolution-specs.js +++ b/packages/ui/resolution/tests/resolution-specs.js @@ -3,8 +3,10 @@ import { config, defineScreenTypes, getScreenType, + getScreenTypeObject, scale, - unit + unit, + updateWorkspaceBounds } from '../resolution.js'; describe('Resolution Specs', () => { @@ -272,6 +274,41 @@ describe('Resolution Specs', () => { expect(actualHD).toBe(expectedHD); }); + test('should calculate font size when orientation is landscape and shouldScaleFontSize value is true', () => { + config.intermediateScreenHandling = 'scale'; + config.matchSmallerScreenType = true; + + window.innerWidth = 1920; + window.innerHeight = 1080; + + // update workspaceBounds + updateWorkspaceBounds(window); + // update orientation + getScreenType(); + const size = calculateFontSize(); + const expected = '18px'; + + expect(size).toBe(expected); + + // clear window inner size + window.innerWidth = 640; + window.innerHeight = 480; + }); + + test('should calculate font size when orientation is portrait and config.orientationHandling is scale', () => { + config.orientationHandling = 'scale'; + const fhdPortrait = {width: 1080, height: 1920}; + getScreenType(fhdPortrait); + + const size = calculateFontSize(); + const scrObj = getScreenTypeObject(); + const screenScale = 1; + const expected = scrObj.height / (scrObj.width * scrObj.pxPerRem * screenScale) + 'px'; + + expect(size).toBe(expected); + + }); + // NOTE: Currently tough to test selectSrc because it relies on a global variable for screenType test.skip('should select source for the current screen type', function () {