Skip to content

Commit b0e9692

Browse files
authored
Merge branch 'dev' into feature/thumb-no-click
2 parents 999a0e1 + 1aa807b commit b0e9692

File tree

8 files changed

+441
-39
lines changed

8 files changed

+441
-39
lines changed

src/common/components/mock-components/front-components/button-shape.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const ButtonShape = forwardRef<any, ShapeProps>((props, ref) => {
6868
/>
6969
<Text
7070
x={0}
71-
y={restrictedHeight / 2 - 5}
71+
y={(restrictedHeight - 15) / 2}
7272
width={restrictedWidth}
7373
height={restrictedHeight - restrictedHeight / 2 - 5}
7474
text={text}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { balanceSpacePerItem } from './balance-space';
3+
4+
const _sum = (resultado: number[]) =>
5+
resultado.reduce((acc, current) => acc + current, 0);
6+
7+
describe('balanceSpacePerItem tests', () => {
8+
it('should return an array which sums 150 when apply [10, 20, 30, 40, 50]', () => {
9+
// Arrange
10+
const theArray = [10, 20, 30, 40, 50];
11+
const availableWidth = 150;
12+
13+
// Act
14+
const result = balanceSpacePerItem(theArray, availableWidth);
15+
const totalSum = _sum(result);
16+
17+
// Assert
18+
expect(totalSum).toBeGreaterThan(0);
19+
expect(totalSum).toBeLessThanOrEqual(availableWidth);
20+
});
21+
22+
it('should return an array which sums equal or less than 100 when apply [10, 20, 30, 40, 50]', () => {
23+
// Arrange
24+
const theArray = [10, 20, 30, 40, 50];
25+
const availableWidth = 100;
26+
27+
// Act
28+
const result = balanceSpacePerItem(theArray, availableWidth);
29+
const totalSum = _sum(result);
30+
31+
// Assert
32+
expect(totalSum).toBeGreaterThan(0);
33+
expect(totalSum).toBeLessThanOrEqual(availableWidth);
34+
});
35+
36+
it('should return an array which sums less or equal than 150 when apply [10, 20, 31, 41, 50]', () => {
37+
// Arrange
38+
const theArray = [10, 20, 31, 41, 50];
39+
const availableWidth = 150;
40+
41+
// Act
42+
const result = balanceSpacePerItem(theArray, availableWidth);
43+
const totalSum = _sum(result);
44+
45+
// Assert
46+
expect(totalSum).toBeGreaterThan(0);
47+
expect(totalSum).toBeLessThanOrEqual(availableWidth);
48+
});
49+
50+
it('should return an array which sums 10 when apply [10]', () => {
51+
// Arrange
52+
const theArray = [100];
53+
const availableWidth = 10;
54+
55+
// Act
56+
const result = balanceSpacePerItem(theArray, availableWidth);
57+
const totalSum = _sum(result);
58+
59+
// Assert
60+
expect(totalSum).toBeGreaterThan(0);
61+
expect(totalSum).toBeLessThanOrEqual(availableWidth);
62+
});
63+
64+
it('should return an array which sums 18 when apply [10, 10]', () => {
65+
// Arrange
66+
const theArray = [10, 10];
67+
const availableWidth = 18;
68+
69+
// Act
70+
const result = balanceSpacePerItem(theArray, availableWidth);
71+
const totalSum = _sum(result);
72+
73+
// Assert
74+
expect(totalSum).toBeGreaterThan(0);
75+
expect(totalSum).toBeLessThanOrEqual(availableWidth);
76+
});
77+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* This calc is made "layer by layer", distributing a larger chunk of width in each iteration
3+
* @param {Array} itemList - List of spaces to balance (Must be provided in ascendent order to work)
4+
* @param {Number} availableSpace - The amount of space to be distributed
5+
*/
6+
export const balanceSpacePerItem = (
7+
itemList: number[],
8+
availableSpace: number
9+
) => {
10+
const totalSpaceUsed = _spacesFactory();
11+
const maxItemSize = _spacesFactory();
12+
13+
return itemList.reduce((newList: number[], current, index, arr) => {
14+
// Check if the array provided is properly ordered
15+
if (index > 0) _checkListOrder(arr[index - 1], current);
16+
17+
const lastItemSize: number = index > 0 ? newList[index - 1] : 0;
18+
19+
// A) Once the maximum possible size of the item is reached, apply this size directly.
20+
if (maxItemSize.value) {
21+
totalSpaceUsed.add(maxItemSize.value);
22+
return [...newList, lastItemSize];
23+
}
24+
25+
/** Precalculate "existingSum + spaceSum" taking into account
26+
* all next items supposing all they use current size */
27+
const timesToApply = arr.length - index;
28+
const virtualTotalsSum = totalSpaceUsed.value + current * timesToApply;
29+
30+
/** B) First "Bigger" tab behaviour: If the virtual-sum of next items using this size
31+
* doesn't fit within available space, calc maxItemSize */
32+
if (virtualTotalsSum >= availableSpace) {
33+
const remainder =
34+
availableSpace - (totalSpaceUsed.value + lastItemSize * timesToApply);
35+
const remainderPortionPerItem = Math.floor(remainder / timesToApply);
36+
maxItemSize.set(lastItemSize + remainderPortionPerItem);
37+
38+
totalSpaceUsed.add(maxItemSize.value);
39+
40+
return [...newList, maxItemSize.value];
41+
}
42+
43+
// C) "Normal" behaviour: Apply proposed new size to current
44+
totalSpaceUsed.add(current);
45+
return [...newList, current];
46+
}, []);
47+
};
48+
49+
/* Balance helper functions: */
50+
51+
function _checkListOrder(prev: number, current: number) {
52+
if (prev > current) {
53+
throw new Error(
54+
'Disordered list. Please provide an ascendent ordered list as param *itemlist*'
55+
);
56+
}
57+
}
58+
59+
function _spacesFactory() {
60+
let _size = 0;
61+
//Assure we are setting natural num w/o decimals
62+
const _adjustNum = (num: number) => {
63+
if (typeof num !== 'number') throw new Error('Number must be provided');
64+
return Math.max(0, Math.floor(num));
65+
};
66+
const add = (qty: number) => (_size += _adjustNum(qty));
67+
const set = (qty: number) => (_size = _adjustNum(qty));
68+
return {
69+
get value() {
70+
return _size;
71+
},
72+
add,
73+
set,
74+
};
75+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Layer } from 'konva/lib/Layer';
2+
3+
/**
4+
* Virtually calculates the width that a text will occupy, by using a canvas.
5+
* If a Konva Layer is provided, it will reuse the already existing canvas.
6+
* Otherwise, it will create a canvas within the document, on the fly, to perform the measurement.
7+
* Finaly, as a safety net, a very generic calculation is provided in case the other options are not available.
8+
*/
9+
export const calcTextWidth = (
10+
inputText: string,
11+
fontSize: number,
12+
fontfamily: string,
13+
konvaLayer?: Layer
14+
) => {
15+
if (konvaLayer)
16+
return _getTextWidthByKonvaMethod(
17+
konvaLayer,
18+
inputText,
19+
fontSize,
20+
fontfamily
21+
);
22+
23+
return _getTextCreatingNewCanvas(inputText, fontSize, fontfamily);
24+
};
25+
26+
const _getTextWidthByKonvaMethod = (
27+
konvaLayer: Layer,
28+
text: string,
29+
fontSize: number,
30+
fontfamily: string
31+
) => {
32+
const context = konvaLayer.getContext();
33+
context.font = `${fontSize}px ${fontfamily}`;
34+
return context.measureText(text).width;
35+
};
36+
37+
const _getTextCreatingNewCanvas = (
38+
text: string,
39+
fontSize: number,
40+
fontfamily: string
41+
) => {
42+
let canvas = document.createElement('canvas');
43+
const context = canvas.getContext('2d');
44+
if (context) {
45+
context.font = `${fontSize}px ${fontfamily}`;
46+
return context.measureText(text).width;
47+
}
48+
const charAverageWidth = fontSize * 0.7;
49+
return text.length * charAverageWidth + charAverageWidth * 0.8;
50+
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { adjustTabWidths } from './tabsbar.business';
3+
4+
const _sum = (resultado: number[]) =>
5+
resultado.reduce((acc, current) => acc + current, 0);
6+
7+
describe('tabsbar.business tests', () => {
8+
it('should return a new array of numbers, which sum is less than or equal to totalWidth', () => {
9+
// Arrange
10+
const tabs = [
11+
'Text',
12+
'Normal text for tab',
13+
'Extra large text for a tab',
14+
'Really really large text for a tab',
15+
'xs',
16+
];
17+
const containerWidth = 1000;
18+
const minTabWidth = 100;
19+
const tabsGap = 10;
20+
21+
// Act
22+
const result = adjustTabWidths({
23+
tabs,
24+
containerWidth,
25+
minTabWidth,
26+
tabXPadding: 20,
27+
tabsGap,
28+
font: { fontSize: 14, fontFamily: 'Arial' },
29+
});
30+
31+
console.log({ tabs }, { containerWidth }, { minTabWidth });
32+
console.log({ result });
33+
34+
const totalSum = _sum(result.widthList) + (tabs.length - 1) * tabsGap;
35+
console.log('totalSum: ', totalSum);
36+
37+
// Assert
38+
expect(result.widthList[0]).not.toBe(0);
39+
expect(result.widthList.length).toBe(tabs.length);
40+
expect(totalSum).toBeLessThanOrEqual(containerWidth);
41+
});
42+
});
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Layer } from 'konva/lib/Layer';
2+
import { balanceSpacePerItem } from './balance-space';
3+
import { calcTextWidth } from './calc-text-width';
4+
5+
export const adjustTabWidths = (args: {
6+
tabs: string[];
7+
containerWidth: number;
8+
minTabWidth: number;
9+
tabXPadding: number;
10+
tabsGap: number;
11+
font: {
12+
fontSize: number;
13+
fontFamily: string;
14+
};
15+
konvaLayer?: Layer;
16+
}) => {
17+
const {
18+
tabs,
19+
containerWidth,
20+
minTabWidth,
21+
tabXPadding,
22+
tabsGap,
23+
font,
24+
konvaLayer,
25+
} = args;
26+
const totalInnerXPadding = tabXPadding * 2;
27+
const totalMinTabSpace = minTabWidth + totalInnerXPadding;
28+
const containerWidthWithoutTabGaps =
29+
containerWidth - (tabs.length - 1) * tabsGap;
30+
31+
//Create info List with originalPositions and desired width
32+
interface OriginalTabInfo {
33+
originalTabPosition: number;
34+
desiredWidth: number;
35+
}
36+
const arrangeTabsInfo = tabs.reduce(
37+
(acc: OriginalTabInfo[], tab, index): OriginalTabInfo[] => {
38+
const tabFullTextWidth =
39+
calcTextWidth(tab, font.fontSize, font.fontFamily, konvaLayer) +
40+
totalInnerXPadding;
41+
const desiredWidth = Math.max(totalMinTabSpace, tabFullTextWidth);
42+
return [
43+
...acc,
44+
{
45+
originalTabPosition: index,
46+
desiredWidth,
47+
},
48+
];
49+
},
50+
[]
51+
);
52+
53+
// This order is necessary to build layer by layer the new sizes
54+
const ascendentTabList = arrangeTabsInfo.sort(
55+
(a, b) => a.desiredWidth - b.desiredWidth
56+
);
57+
58+
const onlyWidthList = ascendentTabList.map(tab => tab.desiredWidth);
59+
// Apply adjustments
60+
const adjustedSizeList = balanceSpacePerItem(
61+
onlyWidthList,
62+
containerWidthWithoutTabGaps
63+
);
64+
65+
// Reassemble new data with the original order
66+
const reassembledData = ascendentTabList.reduce(
67+
(accList: number[], current, index) => {
68+
const newList = [...accList];
69+
newList[current.originalTabPosition] = adjustedSizeList[index];
70+
return newList;
71+
},
72+
[]
73+
);
74+
75+
// Calc item offset position (mixed with external variable to avoid adding to reducer() extra complexity)
76+
let sumOfXposition = 0;
77+
const relativeTabPosition = reassembledData.reduce(
78+
(acc: number[], currentTab, index) => {
79+
const currentElementXPos = index ? sumOfXposition : 0;
80+
sumOfXposition += currentTab + tabsGap;
81+
return [...acc, currentElementXPos];
82+
},
83+
[]
84+
);
85+
86+
return { widthList: reassembledData, relativeTabPosition };
87+
};

0 commit comments

Comments
 (0)