mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(css): text-stroke support (#10399)
closes https://github.com/NativeScript/NativeScript/issues/3597 closes https://github.com/NativeScript/NativeScript/issues/3972
This commit is contained in:
@@ -26,15 +26,11 @@ const LENGTH_RE = /^-?[0-9]+[a-zA-Z%]*?$/;
|
||||
*/
|
||||
const isLength = (v) => v === '0' || LENGTH_RE.test(v);
|
||||
|
||||
/**
|
||||
* Parse a string into ShadowCSSValues
|
||||
* Supports any valid css box/text shadow combination.
|
||||
*
|
||||
* inspired by https://github.com/jxnblk/css-box-shadow/blob/master/index.js (MIT License)
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
export function parseCSSShadow(value: string): ShadowCSSValues {
|
||||
export function parseCSSShorthand(value: string): {
|
||||
values: Array<CoreTypes.LengthType>;
|
||||
color: string;
|
||||
inset: boolean;
|
||||
} {
|
||||
const parts = value.trim().split(PARTS_RE);
|
||||
const inset = parts.includes('inset');
|
||||
const first = parts[0];
|
||||
@@ -44,15 +40,15 @@ export function parseCSSShadow(value: string): ShadowCSSValues {
|
||||
return null;
|
||||
}
|
||||
|
||||
let colorRaw = 'black';
|
||||
let color = 'black';
|
||||
if (first && !isLength(first) && first !== 'inset') {
|
||||
colorRaw = first;
|
||||
color = first;
|
||||
} else if (last && !isLength(last)) {
|
||||
colorRaw = last;
|
||||
color = last;
|
||||
}
|
||||
const nums = parts
|
||||
const values = parts
|
||||
.filter((n) => n !== 'inset')
|
||||
.filter((n) => n !== colorRaw)
|
||||
.filter((n) => n !== color)
|
||||
.map((val) => {
|
||||
try {
|
||||
return Length.parse(val);
|
||||
@@ -60,51 +56,30 @@ export function parseCSSShadow(value: string): ShadowCSSValues {
|
||||
return CoreTypes.zeroLength;
|
||||
}
|
||||
});
|
||||
const [offsetX, offsetY, blurRadius, spreadRadius] = nums;
|
||||
|
||||
return {
|
||||
inset,
|
||||
color,
|
||||
values,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Parse a string into ShadowCSSValues
|
||||
* Supports any valid css box/text shadow combination.
|
||||
*
|
||||
* inspired by https://github.com/jxnblk/css-box-shadow/blob/master/index.js (MIT License)
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
export function parseCSSShadow(value: string): ShadowCSSValues {
|
||||
const data = parseCSSShorthand(value);
|
||||
const [offsetX, offsetY, blurRadius, spreadRadius] = data.values;
|
||||
|
||||
return {
|
||||
inset: data.inset,
|
||||
offsetX: offsetX,
|
||||
offsetY: offsetY,
|
||||
blurRadius: blurRadius,
|
||||
spreadRadius: spreadRadius,
|
||||
color: new Color(colorRaw),
|
||||
color: new Color(data.color),
|
||||
};
|
||||
}
|
||||
|
||||
// if (value.indexOf('rgb') > -1) {
|
||||
// arr = value.split(' ');
|
||||
// colorRaw = arr.pop();
|
||||
// } else {
|
||||
// arr = value.split(/[ ,]+/);
|
||||
// colorRaw = arr.pop();
|
||||
// }
|
||||
|
||||
// let offsetX: number;
|
||||
// let offsetY: number;
|
||||
// let blurRadius: number; // not currently in use
|
||||
// let spreadRadius: number; // maybe rename this to just radius
|
||||
// let color: Color = new Color(colorRaw);
|
||||
|
||||
// if (arr.length === 2) {
|
||||
// offsetX = parseFloat(arr[0]);
|
||||
// offsetY = parseFloat(arr[1]);
|
||||
// } else if (arr.length === 3) {
|
||||
// offsetX = parseFloat(arr[0]);
|
||||
// offsetY = parseFloat(arr[1]);
|
||||
// blurRadius = parseFloat(arr[2]);
|
||||
// } else if (arr.length === 4) {
|
||||
// offsetX = parseFloat(arr[0]);
|
||||
// offsetY = parseFloat(arr[1]);
|
||||
// blurRadius = parseFloat(arr[2]);
|
||||
// spreadRadius = parseFloat(arr[3]);
|
||||
// } else {
|
||||
// throw new Error('Expected 3, 4 or 5 parameters. Actual: ' + value);
|
||||
// }
|
||||
// return {
|
||||
// offsetX: offsetX,
|
||||
// offsetY: offsetY,
|
||||
// blurRadius: blurRadius,
|
||||
// spreadRadius: spreadRadius,
|
||||
// color: color,
|
||||
// };
|
||||
|
||||
30
packages/core/ui/styling/css-stroke.spec.ts
Normal file
30
packages/core/ui/styling/css-stroke.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { parseCSSStroke } from './css-stroke';
|
||||
import { CoreTypes } from '../../core-types';
|
||||
import { Length } from './style-properties';
|
||||
import { Color } from '../../color';
|
||||
|
||||
describe('css-text-stroke', () => {
|
||||
it('empty', () => {
|
||||
const stroke = parseCSSStroke('');
|
||||
expect(stroke.width).toBe(CoreTypes.zeroLength);
|
||||
expect(stroke.color).toEqual(new Color('black'));
|
||||
});
|
||||
|
||||
it('1px navy', () => {
|
||||
const stroke = parseCSSStroke('1px navy');
|
||||
expect(stroke.width).toEqual(Length.parse('1px'));
|
||||
expect(stroke.color).toEqual(new Color('navy'));
|
||||
});
|
||||
|
||||
it('5 green', () => {
|
||||
const stroke = parseCSSStroke('5 green');
|
||||
expect(stroke.width).toEqual(Length.parse('5'));
|
||||
expect(stroke.color).toEqual(new Color('green'));
|
||||
});
|
||||
|
||||
it('2px #999', () => {
|
||||
const stroke = parseCSSStroke('2px #999');
|
||||
expect(stroke.width).toEqual(Length.parse('2px'));
|
||||
expect(stroke.color).toEqual(new Color('#999'));
|
||||
});
|
||||
});
|
||||
23
packages/core/ui/styling/css-stroke.ts
Normal file
23
packages/core/ui/styling/css-stroke.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { CoreTypes } from '../../core-types';
|
||||
import { Color } from '../../color';
|
||||
import { parseCSSShorthand } from './css-shadow';
|
||||
|
||||
export interface StrokeCSSValues {
|
||||
width: CoreTypes.LengthType;
|
||||
color: Color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string into StrokeCSSValues
|
||||
* https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-text-stroke
|
||||
* @param value
|
||||
*/
|
||||
export function parseCSSStroke(value: string): StrokeCSSValues {
|
||||
const data = parseCSSShorthand(value);
|
||||
const [width] = data.values;
|
||||
|
||||
return {
|
||||
width,
|
||||
color: new Color(data.color),
|
||||
};
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import { Trace } from '../../../trace';
|
||||
import { CoreTypes } from '../../../core-types';
|
||||
import { AccessibilityLiveRegion, AccessibilityRole, AccessibilityState } from '../../../accessibility/accessibility-types';
|
||||
import { ShadowCSSValues } from '../css-shadow';
|
||||
import { StrokeCSSValues } from '../css-stroke';
|
||||
|
||||
export interface CommonLayoutParams {
|
||||
width: number;
|
||||
@@ -171,6 +172,7 @@ export class Style extends Observable implements StyleDefinition {
|
||||
public textDecoration: CoreTypes.TextDecorationType;
|
||||
public textTransform: CoreTypes.TextTransformType;
|
||||
public textShadow: ShadowCSSValues;
|
||||
public textStroke: StrokeCSSValues;
|
||||
public whiteSpace: CoreTypes.WhiteSpaceType;
|
||||
public textOverflow: CoreTypes.TextOverflowType;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user