Skip to content

Commit 195fb79

Browse files
Merge pull request #496 from airbnb/f/text-style-props
add text style proptypes
2 parents 59a8b6a + 75b26ad commit 195fb79

File tree

12 files changed

+149
-165
lines changed

12 files changed

+149
-165
lines changed

src/components/TextStylePropTypes.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
1-
import ViewStylePropTypes from './ViewStylePropTypes';
1+
import * as PropTypes from 'prop-types';
2+
import ViewStylePropTypes, { Color } from './ViewStylePropTypes';
23

34
export default {
45
...ViewStylePropTypes,
6+
fontFamily: PropTypes.string,
7+
fontSize: PropTypes.number,
8+
fontStyle: PropTypes.oneOf<'normal' | 'italic'>(['normal', 'italic']),
9+
fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
10+
textDecoration: PropTypes.oneOf<'none' | 'underline' | 'double' | 'line-through'>([
11+
'none',
12+
'underline',
13+
'double',
14+
'line-through',
15+
]),
16+
textShadowOpacity: PropTypes.number,
17+
textShadowSpread: PropTypes.number,
18+
textShadowOffset: PropTypes.shape({ width: PropTypes.number, height: PropTypes.number }),
19+
textShadowRadius: PropTypes.number,
20+
textShadowColor: Color,
21+
textTransform: PropTypes.oneOf<'uppercase' | 'lowercase'>(['uppercase', 'lowercase']),
22+
letterSpacing: PropTypes.number,
23+
lineHeight: PropTypes.number,
24+
textAlign: PropTypes.oneOf<'auto' | 'left' | 'right' | 'center' | 'justify'>([
25+
'auto',
26+
'left',
27+
'right',
28+
'center',
29+
'justify',
30+
]),
31+
paragraphSpacing: PropTypes.number,
32+
writingDirection: PropTypes.oneOf<'auto' | 'ltr' | 'rtl'>(['auto', 'ltr', 'rtl']),
533
};

src/components/ViewStylePropTypes.ts

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import * as PropTypes from 'prop-types';
22

3-
const BorderStyle = PropTypes.oneOf(['solid', 'dotted', 'dashed']);
4-
const Color = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
5-
const Overflow = PropTypes.oneOf(['visible', 'hidden', 'scroll']);
3+
export const BorderStyle = PropTypes.oneOf<'solid' | 'dotted' | 'dashed'>([
4+
'solid',
5+
'dotted',
6+
'dashed',
7+
]);
8+
export const Color = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
9+
export const Overflow = PropTypes.oneOf<'visible' | 'hidden' | 'scroll'>([
10+
'visible',
11+
'hidden',
12+
'scroll',
13+
]);
614

715
export default {
16+
display: PropTypes.oneOf(['flex', 'none']),
817
color: Color,
918
shadowColor: Color,
1019
shadowInner: PropTypes.bool,
@@ -39,18 +48,46 @@ export default {
3948
paddingBottom: PropTypes.number,
4049
paddingLeft: PropTypes.number,
4150
paddingRight: PropTypes.number,
42-
position: PropTypes.oneOf(['absolute', 'relative']),
43-
flexDirection: PropTypes.oneOf(['row', 'row-reverse', 'column', 'column-reverse']),
44-
flexWrap: PropTypes.oneOf(['wrap', 'nowrap']),
45-
justifyContent: PropTypes.oneOf([
51+
position: PropTypes.oneOf<'absolute' | 'relative'>(['absolute', 'relative']),
52+
flexDirection: PropTypes.oneOf<'row' | 'row-reverse' | 'column' | 'column-reverse'>([
53+
'row',
54+
'row-reverse',
55+
'column',
56+
'column-reverse',
57+
]),
58+
flexWrap: PropTypes.oneOf<'wrap' | 'nowrap' | 'wrap-reverse'>(['wrap', 'nowrap', 'wrap-reverse']),
59+
justifyContent: PropTypes.oneOf<
60+
'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around'
61+
>(['flex-start', 'flex-end', 'center', 'space-between', 'space-around']),
62+
alignContent: PropTypes.oneOf<
63+
| 'flex-start'
64+
| 'flex-end'
65+
| 'center'
66+
| 'space-between'
67+
| 'space-around'
68+
| 'stretch'
69+
| 'baseline'
70+
| 'auto'
71+
>([
4672
'flex-start',
4773
'flex-end',
4874
'center',
4975
'space-between',
5076
'space-around',
77+
'stretch',
78+
'baseline',
79+
'auto',
80+
]),
81+
alignItems: PropTypes.oneOf<'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'>([
82+
'flex-start',
83+
'flex-end',
84+
'center',
85+
'stretch',
86+
'baseline',
5187
]),
52-
alignItems: PropTypes.oneOf(['flex-start', 'flex-end', 'center', 'stretch']),
53-
alignSelf: PropTypes.oneOf(['auto', 'flex-start', 'flex-end', 'center', 'stretch']),
88+
alignSelf: PropTypes.oneOf<
89+
'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'
90+
>(['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline']),
5491
overflow: Overflow,
5592
overflowX: Overflow,
5693
overflowY: Overflow,
@@ -60,7 +97,7 @@ export default {
6097
flexBasis: PropTypes.number,
6198
aspectRatio: PropTypes.number,
6299
zIndex: PropTypes.number,
63-
backfaceVisibility: PropTypes.oneOf(['visible', 'hidden']),
100+
backfaceVisibility: PropTypes.oneOf<'visible' | 'hidden'>(['visible', 'hidden']),
64101
backgroundColor: Color,
65102
borderColor: Color,
66103
borderTopColor: Color,

src/jsonUtils/borders.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';
22
import { makeColorFromCSS, emptyGradient } from './models';
3-
import { ViewStyle, LayoutInfo, BorderStyle } from '../types';
3+
import { ViewStyle, LayoutInfo, BorderStyle, Color } from '../types';
44
import same from '../utils/same';
55
import { makeVerticalBorder, makeHorizontalBorder } from './shapeLayers';
66
import { makeBorderOptions } from './style';
77

88
const DEFAULT_BORDER_COLOR = 'transparent';
9-
const DEFAULT_BORDER_STYLE = 'solid';
9+
export const DEFAULT_BORDER_STYLE = 'solid';
1010

1111
export const createUniformBorder = (
1212
width: number,
13-
color: string,
14-
style: BorderStyle = 'solid',
13+
color: Color,
14+
style: BorderStyle = DEFAULT_BORDER_STYLE,
1515
position: FileFormat.BorderPosition = FileFormat.BorderPosition.Center,
1616
lineCapStyle: FileFormat.LineCapStyle = FileFormat.LineCapStyle.Butt,
1717
lineJoinStyle: FileFormat.LineJoinStyle = FileFormat.LineJoinStyle.Miter,
@@ -71,14 +71,14 @@ export const createBorders = (
7171
) {
7272
// all sides have same border width
7373
// in this case, we can do everything with just a single shape.
74-
if (borderTopStyle !== undefined) {
74+
if (borderTopStyle !== undefined && borderTopWidth !== null) {
7575
const borderOptions = makeBorderOptions(borderTopStyle, borderTopWidth);
7676
if (borderOptions && content.style) {
7777
content.style.borderOptions = borderOptions;
7878
}
7979
}
8080

81-
if (borderTopWidth > 0 && content.style) {
81+
if (borderTopWidth && borderTopWidth > 0 && content.style) {
8282
content.style.borders = createUniformBorder(
8383
borderTopWidth,
8484
borderTopColor,
@@ -101,7 +101,7 @@ export const createBorders = (
101101

102102
const layers = [content];
103103

104-
if (borderTopWidth > 0) {
104+
if (borderTopWidth && borderTopWidth > 0) {
105105
const topBorder = makeHorizontalBorder(0, 0, layout.width, borderTopWidth, borderTopColor);
106106
topBorder.name = 'Border (top)';
107107

@@ -113,7 +113,7 @@ export const createBorders = (
113113
layers.push(topBorder);
114114
}
115115

116-
if (borderRightWidth > 0) {
116+
if (borderRightWidth && borderRightWidth > 0) {
117117
const rightBorder = makeVerticalBorder(
118118
layout.width - borderRightWidth,
119119
0,
@@ -131,7 +131,7 @@ export const createBorders = (
131131
layers.push(rightBorder);
132132
}
133133

134-
if (borderBottomWidth > 0) {
134+
if (borderBottomWidth && borderBottomWidth > 0) {
135135
const bottomBorder = makeHorizontalBorder(
136136
0,
137137
layout.height - borderBottomWidth,
@@ -149,7 +149,7 @@ export const createBorders = (
149149
layers.push(bottomBorder);
150150
}
151151

152-
if (borderLeftWidth > 0) {
152+
if (borderLeftWidth && borderLeftWidth > 0) {
153153
const leftBorder = makeVerticalBorder(0, 0, layout.height, borderLeftWidth, borderLeftColor);
154154
leftBorder.name = 'Border (left)';
155155

src/jsonUtils/nodeImpl/makeSvgLayer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function makeLayerFromPathElement(pathElement: any, _parentFrame: FileFormat.Rec
4141
const borderStyle = createUniformBorder(
4242
style.strokeWidth * scale,
4343
style.stroke,
44-
'solid',
44+
undefined,
4545
FileFormat.BorderPosition.Center,
4646
lineCap,
4747
lineCap,

src/jsonUtils/shapeLayers.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { generateID, makeRect, makeColorFromCSS, emptyGradient } from './models'
44
import { makeStyle } from './style';
55
import { Color, ResizeConstraints, ViewStyle } from '../types';
66

7-
type Radii = number[];
7+
type Radii = (number | null)[];
88

99
export const makeHorizontalPath = (): Pick<FileFormat.ShapePath, 'isClosed' | 'points'> => ({
1010
isClosed: false,
@@ -67,7 +67,7 @@ export const makeRectPath = (
6767
points: [
6868
{
6969
_class: 'curvePoint',
70-
cornerRadius: r0,
70+
cornerRadius: r0 || 0,
7171
curveFrom: '{0, 0}',
7272
curveMode: FileFormat.CurveMode.Straight,
7373
curveTo: '{0, 0}',
@@ -77,7 +77,7 @@ export const makeRectPath = (
7777
},
7878
{
7979
_class: 'curvePoint',
80-
cornerRadius: r1,
80+
cornerRadius: r1 || 0,
8181
curveFrom: '{1, 0}',
8282
curveMode: FileFormat.CurveMode.Straight,
8383
curveTo: '{1, 0}',
@@ -87,7 +87,7 @@ export const makeRectPath = (
8787
},
8888
{
8989
_class: 'curvePoint',
90-
cornerRadius: r2,
90+
cornerRadius: r2 || 0,
9191
curveFrom: '{1, 1}',
9292
curveMode: FileFormat.CurveMode.Straight,
9393
curveTo: '{1, 1}',
@@ -97,7 +97,7 @@ export const makeRectPath = (
9797
},
9898
{
9999
_class: 'curvePoint',
100-
cornerRadius: r3,
100+
cornerRadius: r3 || 0,
101101
curveFrom: '{0, 1}',
102102
curveMode: FileFormat.CurveMode.Straight,
103103
curveTo: '{0, 1}',

src/jsonUtils/sketchImpl/createStringMeasurer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ function createStringAttributes(textStyles: TextStyle): Object {
5050
const color = makeColorFromCSS(textStyles.color || 'black');
5151
attribs.MSAttributedStringColorAttribute = color;
5252

53-
if (textStyles.letterSpacing !== undefined) {
53+
if (textStyles.letterSpacing !== undefined && textStyles.letterSpacing !== null) {
5454
attribs.NSKern = textStyles.letterSpacing;
5555
}
5656

57-
if (textStyles.textTransform !== undefined) {
57+
if (textStyles.textTransform !== undefined && textStyles.textTransform !== null) {
5858
attribs.MSAttributedStringTextTransformAttribute = TEXT_TRANSFORM[textStyles.textTransform] * 1;
5959
}
6060

src/jsonUtils/style.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts';
22
import { makeColorFromCSS, makeColorFill } from './models';
3-
import { ViewStyle, TextStyle } from '../types';
3+
import { ViewStyle, TextStyle, BorderStyle } from '../types';
44
import hasAnyDefined from '../utils/hasAnyDefined';
5+
import { DEFAULT_BORDER_STYLE } from './borders';
56

67
const DEFAULT_SHADOW_COLOR = '#000';
78

@@ -18,7 +19,7 @@ const SHADOW_STYLES = [
1819
'textShadowSpread',
1920
];
2021

21-
const makeDashPattern = (style: 'dashed' | 'dotted' | 'solid', width: number): number[] => {
22+
const makeDashPattern = (style: BorderStyle, width: number): number[] => {
2223
switch (style) {
2324
case 'dashed':
2425
return [width * 3, width * 3];
@@ -32,7 +33,7 @@ const makeDashPattern = (style: 'dashed' | 'dotted' | 'solid', width: number): n
3233
};
3334

3435
export const makeBorderOptions = (
35-
style: 'dashed' | 'dotted' | 'solid',
36+
style: BorderStyle,
3637
width: number,
3738
lineCapStyle: FileFormat.LineCapStyle = FileFormat.LineCapStyle.Butt,
3839
lineJoinStyle: FileFormat.LineJoinStyle = FileFormat.LineJoinStyle.Miter,
@@ -48,30 +49,43 @@ export const makeShadow = (
4849
style: ViewStyle | TextStyle,
4950
): FileFormat.Shadow | FileFormat.InnerShadow => {
5051
const opacity =
51-
style.shadowOpacity !== undefined
52+
style.shadowOpacity !== undefined && style.shadowOpacity !== null
5253
? style.shadowOpacity
53-
: 'textShadowOpacity' in style && style.textShadowOpacity !== undefined
54+
: 'textShadowOpacity' in style &&
55+
style.textShadowOpacity !== undefined &&
56+
style.textShadowOpacity !== null
5457
? style.textShadowOpacity
5558
: 1;
5659
const color =
5760
style.shadowColor ||
5861
('textShadowColor' in style && style.textShadowColor) ||
5962
DEFAULT_SHADOW_COLOR;
6063
const radius =
61-
style.shadowRadius !== undefined
64+
style.shadowRadius !== undefined && style.shadowRadius !== null
6265
? style.shadowRadius
63-
: 'textShadowRadius' in style && style.textShadowRadius !== undefined
66+
: 'textShadowRadius' in style &&
67+
style.textShadowRadius !== undefined &&
68+
style.textShadowRadius !== null
6469
? style.textShadowRadius
6570
: 1;
6671
const spread =
67-
style.shadowSpread !== undefined
72+
style.shadowSpread !== undefined && style.shadowSpread !== null
6873
? style.shadowSpread
69-
: 'textShadowSpread' in style && style.textShadowSpread !== undefined
74+
: 'textShadowSpread' in style &&
75+
style.textShadowSpread !== undefined &&
76+
style.textShadowSpread !== null
7077
? style.textShadowSpread
7178
: 1;
72-
const { width: offsetX = 0, height: offsetY = 0 } =
79+
let { width: offsetX, height: offsetY } =
7380
style.shadowOffset || ('textShadowOffset' in style && style.textShadowOffset) || {};
7481

82+
if (!offsetX) {
83+
offsetX = 0;
84+
}
85+
if (!offsetY) {
86+
offsetY = 0;
87+
}
88+
7589
const commonProps = {
7690
isEnabled: true,
7791
blurRadius: radius,
@@ -110,7 +124,7 @@ export const makeStyle = (
110124
miterLimit: 10,
111125
innerShadows: [],
112126
shadows: [],
113-
borderOptions: makeBorderOptions('solid', 0, 0, 0),
127+
borderOptions: makeBorderOptions(DEFAULT_BORDER_STYLE, 0, 0, 0),
114128
startMarkerType: FileFormat.MarkerType.OpenArrow,
115129
endMarkerType: FileFormat.MarkerType.OpenArrow,
116130
windingRule: FileFormat.WindingRule.EvenOdd,

0 commit comments

Comments
 (0)