mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(skin): improved responsive design
This commit is contained in:
@@ -17,23 +17,22 @@ export function resolveCSSLength(el: Element, value: string): number {
|
||||
|
||||
const parsed = Number.parseFloat(trimmed);
|
||||
|
||||
if (Number.isNaN(parsed)) return 0;
|
||||
if (/^-?\d*\.?\d+$/.test(trimmed) || trimmed.endsWith('px')) return parsed;
|
||||
if (!Number.isNaN(parsed) && (/^-?\d*\.?\d+$/.test(trimmed) || trimmed.endsWith('px'))) return parsed;
|
||||
|
||||
const doc = el.ownerDocument;
|
||||
const root = doc?.documentElement;
|
||||
|
||||
if (trimmed.endsWith('rem')) {
|
||||
if (!Number.isNaN(parsed) && trimmed.endsWith('rem')) {
|
||||
const rootFontSize = root ? Number.parseFloat(getComputedStyle(root).fontSize) || 16 : 16;
|
||||
return parsed * rootFontSize;
|
||||
}
|
||||
|
||||
if (trimmed.endsWith('em')) {
|
||||
if (!Number.isNaN(parsed) && trimmed.endsWith('em')) {
|
||||
const fontSize = el instanceof HTMLElement ? Number.parseFloat(getComputedStyle(el).fontSize) || 16 : 16;
|
||||
return parsed * fontSize;
|
||||
}
|
||||
|
||||
if (!doc) return parsed;
|
||||
if (!doc) return Number.isNaN(parsed) ? 0 : parsed;
|
||||
|
||||
const measurementEl = doc.createElement('div');
|
||||
measurementEl.style.position = 'absolute';
|
||||
@@ -45,14 +44,27 @@ export function resolveCSSLength(el: Element, value: string): number {
|
||||
measurementEl.style.border = '0';
|
||||
measurementEl.style.inset = '0';
|
||||
|
||||
const computed = getComputedStyle(el);
|
||||
measurementEl.style.fontSize = computed.fontSize;
|
||||
|
||||
for (let i = 0; i < computed.length; i++) {
|
||||
const name = computed.item(i);
|
||||
|
||||
if (name.startsWith('--')) {
|
||||
measurementEl.style.setProperty(name, computed.getPropertyValue(name));
|
||||
}
|
||||
}
|
||||
|
||||
const parent = doc.body ?? doc.documentElement;
|
||||
|
||||
if (!parent) return parsed;
|
||||
if (!parent) return Number.isNaN(parsed) ? 0 : parsed;
|
||||
|
||||
parent.appendChild(measurementEl);
|
||||
|
||||
const pixels = measurementEl.getBoundingClientRect().width;
|
||||
measurementEl.remove();
|
||||
|
||||
return Number.isFinite(pixels) ? pixels : parsed;
|
||||
if (Number.isFinite(pixels)) return pixels;
|
||||
|
||||
return Number.isNaN(parsed) ? 0 : parsed;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { resolveCSSLength } from '../style';
|
||||
|
||||
describe('resolveCSSLength', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('Returns px values directly', () => {
|
||||
const el = document.createElement('div');
|
||||
|
||||
@@ -98,4 +102,75 @@ describe('resolveCSSLength', () => {
|
||||
|
||||
createElementSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('Falls back to measurement for calc values', () => {
|
||||
const el = document.createElement('div');
|
||||
const createElement = document.createElement.bind(document);
|
||||
const createElementSpy = vi.spyOn(document, 'createElement').mockImplementation((tagName: string) => {
|
||||
const node = createElement(tagName);
|
||||
|
||||
if (tagName === 'div') {
|
||||
vi.spyOn(node, 'getBoundingClientRect').mockImplementation(() => ({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: node.style.inlineSize.startsWith('calc(') ? 8 : 0,
|
||||
height: 0,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 8,
|
||||
bottom: 0,
|
||||
toJSON() {},
|
||||
}));
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
expect(resolveCSSLength(el, 'calc(0.5 * 16px)')).toBe(8);
|
||||
|
||||
createElementSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('Copies custom properties from the source element when measuring', () => {
|
||||
const el = document.createElement('div');
|
||||
|
||||
const createElement = document.createElement.bind(document);
|
||||
const getComputedStyleSpy = vi.spyOn(globalThis, 'getComputedStyle').mockImplementation(
|
||||
() =>
|
||||
({
|
||||
length: 1,
|
||||
fontSize: '14px',
|
||||
item(index: number) {
|
||||
return index === 0 ? '--size' : '';
|
||||
},
|
||||
getPropertyValue(name: string) {
|
||||
return name === '--size' ? '16px' : '';
|
||||
},
|
||||
}) as CSSStyleDeclaration
|
||||
);
|
||||
const createElementSpy = vi.spyOn(document, 'createElement').mockImplementation((tagName: string) => {
|
||||
const node = createElement(tagName);
|
||||
|
||||
if (tagName === 'div') {
|
||||
vi.spyOn(node, 'getBoundingClientRect').mockImplementation(() => ({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: node.style.getPropertyValue('--size') === '16px' ? 8 : 0,
|
||||
height: 0,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 8,
|
||||
bottom: 0,
|
||||
toJSON() {},
|
||||
}));
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
expect(resolveCSSLength(el, 'calc(0.5 * var(--size))')).toBe(8);
|
||||
|
||||
createElementSpy.mockRestore();
|
||||
getComputedStyleSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user