Skip to content

Commit

Permalink
feat(react): add font style inherit
Browse files Browse the repository at this point in the history
  • Loading branch information
zealotchen0 committed Jun 20, 2024
1 parent 7ca089c commit f717db5
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 18 deletions.
16 changes: 13 additions & 3 deletions driver/js/examples/hippy-react-demo/src/components/Text/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export default class TextExpo extends React.Component {
x: 1,
y: 1,
},
scrollColor: 'gray',
numberOfLines: 2,
ellipsizeMode: undefined,
};
Expand All @@ -85,6 +86,7 @@ export default class TextExpo extends React.Component {
this.incrementLine = this.incrementLine.bind(this);
this.decrementLine = this.decrementLine.bind(this);
this.changeMode = this.changeMode.bind(this);
this.changeColor = this.changeColor.bind(this);
}

incrementFontSize() {
Expand Down Expand Up @@ -129,19 +131,24 @@ export default class TextExpo extends React.Component {
this.setState({ ellipsizeMode: mode });
}

changeColor() {
this.setState({ scrollColor: 'red' });
}

changeBreakStrategy(breakStrategy) {
this.setState({ breakStrategy });
}

render() {
const { fontSize, textShadowColor, textShadowOffset, numberOfLines, ellipsizeMode, breakStrategy } = this.state;
const { fontSize, textShadowColor, textShadowOffset, numberOfLines, ellipsizeMode, breakStrategy,
scrollColor } = this.state;
const renderTitle = title => (
<View style={styles.itemTitle}>
<Text style>{title}</Text>
</View>
);
return (
<ScrollView style={{ paddingHorizontal: 10 }}>
<ScrollView style={{ padding: 10, color: scrollColor, fontFamily: 'TTTGB' }}>
{renderTitle('shadow')}
<View style={[styles.itemContent, { height: 60 }]} onClick={() => {
let textShadowColor = 'red';
Expand Down Expand Up @@ -173,10 +180,13 @@ export default class TextExpo extends React.Component {
<Text style={[styles.normalText, { color: 'rgb(228,61,36)' }]}>This is red</Text>
</View>
{renderTitle('fontSize')}
<View style={[styles.itemContent, { height: 100 }]}>
<View style={[styles.itemContent, { height: 125, color: 'blue', fontFamily: 'not-support-fontstyle' }]}>
<Text style={[styles.normalText, { fontSize }]}>
{ `Text fontSize is ${fontSize}` }
</Text>
<View style={styles.button} onClick={this.changeColor}>
<Text style={styles.buttonText}>切换字体颜色</Text>
</View>
<View style={styles.button} onClick={this.incrementFontSize}>
<Text style={styles.buttonText}>放大字体</Text>
</View>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<template>
<div class="p-demo">
<div
class="p-demo"
:style="{color: topColor}"
>
<div>
<label>不带样式:</label>
<p
Expand Down Expand Up @@ -65,6 +68,13 @@
>
这里是文字灰色阴影,点击可改变颜色
</p>
<p
class="p-demo-7 p-demo-content"
:style="textShadow"
@click="changeTextColor"
>
验证属性继承更改效果,点击可改变整体颜色
</p>
<label>文本字符间距</label>
<p
class="p-demo-8 p-demo-content"
Expand Down Expand Up @@ -376,6 +386,7 @@ import Vue from 'vue';
export default {
data() {
return {
topColor: 'grey',
Platform: Vue.Native.Platform,
textShadowIndex: 0,
isClicked: false,
Expand Down Expand Up @@ -418,6 +429,10 @@ export default {
};
this.textShadowIndex += 1;
},
changeTextColor() {
this.topColor = this.textShadowIndex % 2 === 1 ? 'red' : 'grey',
this.textShadowIndex += 1;
},
// text/span/label/p/a element touch event is supported after hippy-vue 2.6.2
onTouchTextStart(evt) {
this.labelTouchStatus = 'touch start';
Expand Down
6 changes: 6 additions & 0 deletions driver/js/packages/hippy-react/src/dom/element-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ class ElementNode extends ViewNode {
public tagName: string;
public id = '';
public style: HippyTypes.Style = {};
public inheritStyle: HippyTypes.Style = {};
public attributes: Attributes = {};
public events: object = {};

Expand Down Expand Up @@ -488,6 +489,11 @@ class ElementNode extends ViewNode {
return true;
}
this.setStyleAttribute(value);
const inheritProperties = ['color', 'fontSize', 'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'lineHeight'];
const needInherit = inheritProperties.some(prop => Object.prototype.hasOwnProperty.call(value, prop));
if (needInherit) {
updateWithChildren(this);
}
return false;
},
},
Expand Down
22 changes: 20 additions & 2 deletions driver/js/packages/hippy-react/src/renderer/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ import {
translateToNativeEventName,
eventHandlerType,
nativeEventMap,
isTextNode,
} from '../utils/node';
import { deepCopy, isDev, isTraceEnabled, trace, warn } from '../utils';
import { deepCopy, isDev, isTraceEnabled, trace, warn, isStyleNotEmpty } from '../utils';

const componentName = ['%c[native]%c', 'color: red', 'color: auto'];

Expand Down Expand Up @@ -260,14 +261,31 @@ function renderToNative(
if (!targetNode.meta.component) {
throw new Error(`Specific tag is not supported yet: ${targetNode.tagName}`);
}
let resultStyle = targetNode.style;
if (targetNode.parentNode instanceof Element) {
// Implement attribute inheritance logic
// Only inherit color and font properties
const parentNodeStyle = Object.assign({}, targetNode.parentNode.inheritStyle, targetNode.parentNode.style);
const { style, inheritStyle } = targetNode;
const styleAttributes = ['color', 'fontSize', 'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'lineHeight'];

styleAttributes.forEach((attribute) => {
if (!isStyleNotEmpty(style[attribute]) && isStyleNotEmpty(parentNodeStyle[attribute])) {
inheritStyle[attribute] = parentNodeStyle[attribute];
}
});
if (isTextNode(targetNode)) {
resultStyle = Object.assign({}, inheritStyle, style);
}
}
// Translate to native node
const nativeNode: HippyTypes.NativeNode = {
id: targetNode.nodeId,
pId: (targetNode.parentNode?.nodeId) || rootViewId,
name: targetNode.nativeName,
props: {
...getNativeProps(targetNode),
style: targetNode.style,
style: resultStyle,
},
tagName: targetNode.tagName,
};
Expand Down
8 changes: 8 additions & 0 deletions driver/js/packages/hippy-react/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,13 @@ function deepCopy(data, hash = new WeakMap()) {
return newData;
}

function isStyleNotEmpty(style: string | number | null | undefined) {
if (typeof style === 'string') {
return style.trim() !== '';
}
return style !== null && style !== undefined;
}

export {
trace,
warn,
Expand All @@ -214,4 +221,5 @@ export {
convertImgUrl,
isHostComponent,
deepCopy,
isStyleNotEmpty,
};
5 changes: 5 additions & 0 deletions driver/js/packages/hippy-react/src/utils/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ function translateToNativeEventName(name) {
return name.replace(/^(on)?/g, '').toLocaleLowerCase();
}

function isTextNode(targetNode: ElementNode) {
return (targetNode && targetNode.nativeName === 'Text') || ['p', 'span'].indexOf(targetNode.tagName) !== -1;
}

export {
relativeToRefType,
NATIVE_EVENT_INDEX,
Expand All @@ -241,4 +245,5 @@ export {
getElementFromFiber,
unCacheFiberNodeOnIdle,
recursivelyUnCacheFiberNode,
isTextNode,
};
27 changes: 17 additions & 10 deletions driver/js/packages/hippy-vue/src/native/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import {
setCacheNodeStyle,
getCacheNodeStyle,
} from '../util/node-style';
import { isStyleMatched, preCacheNode } from '../util/node';
import { isHippyTextNode, isStyleMatched, preCacheNode } from '../util/node';
import { fromAstNodes, SelectorsMap } from '../style';
import { CallbackType, NeedToTyped } from '../types/native';
import ElementNode from '../renderer/element-node';
Expand Down Expand Up @@ -442,9 +442,11 @@ function renderToNative(rootViewId, targetNode, refInfo = {}, notUpdateStyle = f
}

let style;
let resultStyle;
if (notUpdateStyle) {
// No need to update CSS, use cache directly
style = getCacheNodeStyle(targetNode.nodeId);
resultStyle = style;
} else {
// Recalculate CSS styles style
style = getElemCss(targetNode);
Expand All @@ -453,9 +455,10 @@ function renderToNative(rootViewId, targetNode, refInfo = {}, notUpdateStyle = f
// CSS preprocessing
getBeforeRenderToNative()();

// style before merge inherit style
const originStyle = Object.assign({}, style);

if (targetNode.parentNode) {
// Implement attribute inheritance logic
// Only inherit color and font properties
const parentNodeStyle = getCacheNodeStyle(targetNode.parentNode.nodeId);
const styleAttributes = ['color', 'fontSize', 'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'lineHeight'];

Expand All @@ -465,14 +468,18 @@ function renderToNative(rootViewId, targetNode, refInfo = {}, notUpdateStyle = f
}
});
}

// Cache css result
setCacheNodeStyle(targetNode.nodeId, style);

// style after merge inherit style
resultStyle = isHippyTextNode(targetNode) ? style : originStyle;

// use defaultNativeStyle later to avoid incorrect compute style from inherit node
// in beforeRenderToNative hook
if (targetNode.meta.component.defaultNativeStyle) {
style = { ...targetNode.meta.component.defaultNativeStyle, ...style };
style = { ...targetNode.meta.component.defaultNativeStyle, ...resultStyle };
}

// Cache css result
setCacheNodeStyle(targetNode.nodeId, style);
}
// Translate to native node
const nativeNode: NeedToTyped = {
Expand All @@ -481,14 +488,14 @@ function renderToNative(rootViewId, targetNode, refInfo = {}, notUpdateStyle = f
name: targetNode.meta.component.name,
props: {
...getNativeProps(targetNode),
style,
style: resultStyle,
},
tagName: targetNode.tagName,
};

processModalView(nativeNode);
parseViewComponent(targetNode, nativeNode, style);
parseTextInputComponent(targetNode, style);
parseViewComponent(targetNode, nativeNode, resultStyle);
parseTextInputComponent(targetNode, resultStyle);
// Convert to real native event
const eventNode: NeedToTyped = getEventNode(targetNode);
let printedNode: NeedToTyped = undefined;
Expand Down
15 changes: 13 additions & 2 deletions driver/js/packages/hippy-vue/src/renderer/element-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ interface OptionMapType {
notUpdateStyle?: boolean;
}

const inheritProperties = ['color', 'fontSize', 'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'lineHeight'];

export class ElementNode extends ViewNode {
// id
public id = '';
Expand Down Expand Up @@ -493,7 +495,12 @@ export class ElementNode extends ViewNode {
const styleValue = batchStyles[styleKey];
this.setStyle(styleKey, styleValue, true);
});
updateChild(this);
const needInherit = inheritProperties.some(prop => Object.prototype.hasOwnProperty.call(batchStyles, prop));
if (needInherit) {
updateWithChildren(this);
} else {
updateChild(this);
}
}

public setStyle(rawKey: string, rawValue: NeedToTyped, notToNative = false) {
Expand Down Expand Up @@ -556,7 +563,11 @@ export class ElementNode extends ViewNode {
}
this.style[key] = value;
if (!notToNative) {
updateChild(this);
if (inheritProperties.indexOf(key) >= 0) {
updateWithChildren(this);
} else {
updateChild(this);
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions driver/js/packages/hippy-vue/src/util/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ const RelativeToRefType = {
AFTER: 1,
};

function isHippyTextNode(targetNode) {
return targetNode.meta?.component && targetNode.meta.component.name === 'Text';
}

export {
RelativeToRefType,
findNotToSkipNode,
Expand All @@ -148,4 +152,5 @@ export {
getNodeById,
unCacheNodeOnIdle,
isStyleMatched,
isHippyTextNode,
};

0 comments on commit f717db5

Please sign in to comment.