-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' into feature/thumb-no-click
- Loading branch information
Showing
8 changed files
with
441 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
...n/components/mock-components/front-rich-components/tabsbar/business/balance-space.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { describe, it, expect } from 'vitest'; | ||
import { balanceSpacePerItem } from './balance-space'; | ||
|
||
const _sum = (resultado: number[]) => | ||
resultado.reduce((acc, current) => acc + current, 0); | ||
|
||
describe('balanceSpacePerItem tests', () => { | ||
it('should return an array which sums 150 when apply [10, 20, 30, 40, 50]', () => { | ||
// Arrange | ||
const theArray = [10, 20, 30, 40, 50]; | ||
const availableWidth = 150; | ||
|
||
// Act | ||
const result = balanceSpacePerItem(theArray, availableWidth); | ||
const totalSum = _sum(result); | ||
|
||
// Assert | ||
expect(totalSum).toBeGreaterThan(0); | ||
expect(totalSum).toBeLessThanOrEqual(availableWidth); | ||
}); | ||
|
||
it('should return an array which sums equal or less than 100 when apply [10, 20, 30, 40, 50]', () => { | ||
// Arrange | ||
const theArray = [10, 20, 30, 40, 50]; | ||
const availableWidth = 100; | ||
|
||
// Act | ||
const result = balanceSpacePerItem(theArray, availableWidth); | ||
const totalSum = _sum(result); | ||
|
||
// Assert | ||
expect(totalSum).toBeGreaterThan(0); | ||
expect(totalSum).toBeLessThanOrEqual(availableWidth); | ||
}); | ||
|
||
it('should return an array which sums less or equal than 150 when apply [10, 20, 31, 41, 50]', () => { | ||
// Arrange | ||
const theArray = [10, 20, 31, 41, 50]; | ||
const availableWidth = 150; | ||
|
||
// Act | ||
const result = balanceSpacePerItem(theArray, availableWidth); | ||
const totalSum = _sum(result); | ||
|
||
// Assert | ||
expect(totalSum).toBeGreaterThan(0); | ||
expect(totalSum).toBeLessThanOrEqual(availableWidth); | ||
}); | ||
|
||
it('should return an array which sums 10 when apply [10]', () => { | ||
// Arrange | ||
const theArray = [100]; | ||
const availableWidth = 10; | ||
|
||
// Act | ||
const result = balanceSpacePerItem(theArray, availableWidth); | ||
const totalSum = _sum(result); | ||
|
||
// Assert | ||
expect(totalSum).toBeGreaterThan(0); | ||
expect(totalSum).toBeLessThanOrEqual(availableWidth); | ||
}); | ||
|
||
it('should return an array which sums 18 when apply [10, 10]', () => { | ||
// Arrange | ||
const theArray = [10, 10]; | ||
const availableWidth = 18; | ||
|
||
// Act | ||
const result = balanceSpacePerItem(theArray, availableWidth); | ||
const totalSum = _sum(result); | ||
|
||
// Assert | ||
expect(totalSum).toBeGreaterThan(0); | ||
expect(totalSum).toBeLessThanOrEqual(availableWidth); | ||
}); | ||
}); |
75 changes: 75 additions & 0 deletions
75
...common/components/mock-components/front-rich-components/tabsbar/business/balance-space.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/** | ||
* This calc is made "layer by layer", distributing a larger chunk of width in each iteration | ||
* @param {Array} itemList - List of spaces to balance (Must be provided in ascendent order to work) | ||
* @param {Number} availableSpace - The amount of space to be distributed | ||
*/ | ||
export const balanceSpacePerItem = ( | ||
itemList: number[], | ||
availableSpace: number | ||
) => { | ||
const totalSpaceUsed = _spacesFactory(); | ||
const maxItemSize = _spacesFactory(); | ||
|
||
return itemList.reduce((newList: number[], current, index, arr) => { | ||
// Check if the array provided is properly ordered | ||
if (index > 0) _checkListOrder(arr[index - 1], current); | ||
|
||
const lastItemSize: number = index > 0 ? newList[index - 1] : 0; | ||
|
||
// A) Once the maximum possible size of the item is reached, apply this size directly. | ||
if (maxItemSize.value) { | ||
totalSpaceUsed.add(maxItemSize.value); | ||
return [...newList, lastItemSize]; | ||
} | ||
|
||
/** Precalculate "existingSum + spaceSum" taking into account | ||
* all next items supposing all they use current size */ | ||
const timesToApply = arr.length - index; | ||
const virtualTotalsSum = totalSpaceUsed.value + current * timesToApply; | ||
|
||
/** B) First "Bigger" tab behaviour: If the virtual-sum of next items using this size | ||
* doesn't fit within available space, calc maxItemSize */ | ||
if (virtualTotalsSum >= availableSpace) { | ||
const remainder = | ||
availableSpace - (totalSpaceUsed.value + lastItemSize * timesToApply); | ||
const remainderPortionPerItem = Math.floor(remainder / timesToApply); | ||
maxItemSize.set(lastItemSize + remainderPortionPerItem); | ||
|
||
totalSpaceUsed.add(maxItemSize.value); | ||
|
||
return [...newList, maxItemSize.value]; | ||
} | ||
|
||
// C) "Normal" behaviour: Apply proposed new size to current | ||
totalSpaceUsed.add(current); | ||
return [...newList, current]; | ||
}, []); | ||
}; | ||
|
||
/* Balance helper functions: */ | ||
|
||
function _checkListOrder(prev: number, current: number) { | ||
if (prev > current) { | ||
throw new Error( | ||
'Disordered list. Please provide an ascendent ordered list as param *itemlist*' | ||
); | ||
} | ||
} | ||
|
||
function _spacesFactory() { | ||
let _size = 0; | ||
//Assure we are setting natural num w/o decimals | ||
const _adjustNum = (num: number) => { | ||
if (typeof num !== 'number') throw new Error('Number must be provided'); | ||
return Math.max(0, Math.floor(num)); | ||
}; | ||
const add = (qty: number) => (_size += _adjustNum(qty)); | ||
const set = (qty: number) => (_size = _adjustNum(qty)); | ||
return { | ||
get value() { | ||
return _size; | ||
}, | ||
add, | ||
set, | ||
}; | ||
} |
50 changes: 50 additions & 0 deletions
50
...mmon/components/mock-components/front-rich-components/tabsbar/business/calc-text-width.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Layer } from 'konva/lib/Layer'; | ||
|
||
/** | ||
* Virtually calculates the width that a text will occupy, by using a canvas. | ||
* If a Konva Layer is provided, it will reuse the already existing canvas. | ||
* Otherwise, it will create a canvas within the document, on the fly, to perform the measurement. | ||
* Finaly, as a safety net, a very generic calculation is provided in case the other options are not available. | ||
*/ | ||
export const calcTextWidth = ( | ||
inputText: string, | ||
fontSize: number, | ||
fontfamily: string, | ||
konvaLayer?: Layer | ||
) => { | ||
if (konvaLayer) | ||
return _getTextWidthByKonvaMethod( | ||
konvaLayer, | ||
inputText, | ||
fontSize, | ||
fontfamily | ||
); | ||
|
||
return _getTextCreatingNewCanvas(inputText, fontSize, fontfamily); | ||
}; | ||
|
||
const _getTextWidthByKonvaMethod = ( | ||
konvaLayer: Layer, | ||
text: string, | ||
fontSize: number, | ||
fontfamily: string | ||
) => { | ||
const context = konvaLayer.getContext(); | ||
context.font = `${fontSize}px ${fontfamily}`; | ||
return context.measureText(text).width; | ||
}; | ||
|
||
const _getTextCreatingNewCanvas = ( | ||
text: string, | ||
fontSize: number, | ||
fontfamily: string | ||
) => { | ||
let canvas = document.createElement('canvas'); | ||
const context = canvas.getContext('2d'); | ||
if (context) { | ||
context.font = `${fontSize}px ${fontfamily}`; | ||
return context.measureText(text).width; | ||
} | ||
const charAverageWidth = fontSize * 0.7; | ||
return text.length * charAverageWidth + charAverageWidth * 0.8; | ||
}; |
42 changes: 42 additions & 0 deletions
42
...omponents/mock-components/front-rich-components/tabsbar/business/tabsbar.business.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { describe, it, expect } from 'vitest'; | ||
import { adjustTabWidths } from './tabsbar.business'; | ||
|
||
const _sum = (resultado: number[]) => | ||
resultado.reduce((acc, current) => acc + current, 0); | ||
|
||
describe('tabsbar.business tests', () => { | ||
it('should return a new array of numbers, which sum is less than or equal to totalWidth', () => { | ||
// Arrange | ||
const tabs = [ | ||
'Text', | ||
'Normal text for tab', | ||
'Extra large text for a tab', | ||
'Really really large text for a tab', | ||
'xs', | ||
]; | ||
const containerWidth = 1000; | ||
const minTabWidth = 100; | ||
const tabsGap = 10; | ||
|
||
// Act | ||
const result = adjustTabWidths({ | ||
tabs, | ||
containerWidth, | ||
minTabWidth, | ||
tabXPadding: 20, | ||
tabsGap, | ||
font: { fontSize: 14, fontFamily: 'Arial' }, | ||
}); | ||
|
||
console.log({ tabs }, { containerWidth }, { minTabWidth }); | ||
console.log({ result }); | ||
|
||
const totalSum = _sum(result.widthList) + (tabs.length - 1) * tabsGap; | ||
console.log('totalSum: ', totalSum); | ||
|
||
// Assert | ||
expect(result.widthList[0]).not.toBe(0); | ||
expect(result.widthList.length).toBe(tabs.length); | ||
expect(totalSum).toBeLessThanOrEqual(containerWidth); | ||
}); | ||
}); |
87 changes: 87 additions & 0 deletions
87
...mon/components/mock-components/front-rich-components/tabsbar/business/tabsbar.business.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { Layer } from 'konva/lib/Layer'; | ||
import { balanceSpacePerItem } from './balance-space'; | ||
import { calcTextWidth } from './calc-text-width'; | ||
|
||
export const adjustTabWidths = (args: { | ||
tabs: string[]; | ||
containerWidth: number; | ||
minTabWidth: number; | ||
tabXPadding: number; | ||
tabsGap: number; | ||
font: { | ||
fontSize: number; | ||
fontFamily: string; | ||
}; | ||
konvaLayer?: Layer; | ||
}) => { | ||
const { | ||
tabs, | ||
containerWidth, | ||
minTabWidth, | ||
tabXPadding, | ||
tabsGap, | ||
font, | ||
konvaLayer, | ||
} = args; | ||
const totalInnerXPadding = tabXPadding * 2; | ||
const totalMinTabSpace = minTabWidth + totalInnerXPadding; | ||
const containerWidthWithoutTabGaps = | ||
containerWidth - (tabs.length - 1) * tabsGap; | ||
|
||
//Create info List with originalPositions and desired width | ||
interface OriginalTabInfo { | ||
originalTabPosition: number; | ||
desiredWidth: number; | ||
} | ||
const arrangeTabsInfo = tabs.reduce( | ||
(acc: OriginalTabInfo[], tab, index): OriginalTabInfo[] => { | ||
const tabFullTextWidth = | ||
calcTextWidth(tab, font.fontSize, font.fontFamily, konvaLayer) + | ||
totalInnerXPadding; | ||
const desiredWidth = Math.max(totalMinTabSpace, tabFullTextWidth); | ||
return [ | ||
...acc, | ||
{ | ||
originalTabPosition: index, | ||
desiredWidth, | ||
}, | ||
]; | ||
}, | ||
[] | ||
); | ||
|
||
// This order is necessary to build layer by layer the new sizes | ||
const ascendentTabList = arrangeTabsInfo.sort( | ||
(a, b) => a.desiredWidth - b.desiredWidth | ||
); | ||
|
||
const onlyWidthList = ascendentTabList.map(tab => tab.desiredWidth); | ||
// Apply adjustments | ||
const adjustedSizeList = balanceSpacePerItem( | ||
onlyWidthList, | ||
containerWidthWithoutTabGaps | ||
); | ||
|
||
// Reassemble new data with the original order | ||
const reassembledData = ascendentTabList.reduce( | ||
(accList: number[], current, index) => { | ||
const newList = [...accList]; | ||
newList[current.originalTabPosition] = adjustedSizeList[index]; | ||
return newList; | ||
}, | ||
[] | ||
); | ||
|
||
// Calc item offset position (mixed with external variable to avoid adding to reducer() extra complexity) | ||
let sumOfXposition = 0; | ||
const relativeTabPosition = reassembledData.reduce( | ||
(acc: number[], currentTab, index) => { | ||
const currentElementXPos = index ? sumOfXposition : 0; | ||
sumOfXposition += currentTab + tabsGap; | ||
return [...acc, currentElementXPos]; | ||
}, | ||
[] | ||
); | ||
|
||
return { widthList: reassembledData, relativeTabPosition }; | ||
}; |
Oops, something went wrong.