Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(module:typography): add typography component #3119

Merged
merged 10 commits into from
Jun 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/components.less
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
@import "./timeline/style/entry.less";
@import "./tooltip/style/entry.less";
@import "./transfer/style/entry.less";
@import "./typography/style/entry.less";
@import "./upload/style/entry.less";
@import "./auto-complete/style/entry.less";
@import "./cascader/style/entry.less";
Expand Down
1 change: 1 addition & 0 deletions components/core/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './wave/public-api';
export * from './dropdown/public-api';
export * from './logger/public-api';
export * from './responsive/public-api';
export * from './trans-button/public-api';
52 changes: 52 additions & 0 deletions components/core/services/nz-copy-to-clipboard.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class NzCopyToClipboardService {
// tslint:disable-next-line:no-any
constructor(@Inject(DOCUMENT) private document: any) {}

copy(text: string): Promise<string> {
return new Promise<string>(
(resolve, reject): void => {
let copyTextArea = null;
try {
// tslint:disable-next-line no-any
copyTextArea = this.document.createElement('textarea') as any;
copyTextArea.style!.all = 'unset';
copyTextArea.style.position = 'fixed';
copyTextArea.style.top = '0';
copyTextArea.style.clip = 'rect(0, 0, 0, 0)';
copyTextArea.style.whiteSpace = 'pre';
copyTextArea.style.webkitUserSelect = 'text';
copyTextArea.style!.MozUserSelect = 'text';
copyTextArea.style.msUserSelect = 'text';
copyTextArea.style.userSelect = 'text';
this.document.body.appendChild(copyTextArea);
copyTextArea.value = text;
copyTextArea.select();

const successful = this.document.execCommand('copy');
if (!successful) {
reject(text);
}
resolve(text);
} finally {
if (copyTextArea) {
this.document.body.removeChild(copyTextArea);
}
}
}
);
}
}
1 change: 1 addition & 0 deletions components/core/services/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@

export * from './nz-measure-scrollbar.service';
export * from './update-host-class.service';
export * from './nz-copy-to-clipboard.service';
9 changes: 9 additions & 0 deletions components/core/trans-button/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

export * from './public-api';
20 changes: 20 additions & 0 deletions components/core/trans-button/nz-trans-button.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { Directive } from '@angular/core';

@Directive({
selector: 'button[nz-trans-button]',
host: {
'[style.border]': '"0"',
'[style.background]': '"transparent"',
'[style.padding]': '"0"',
'[style.line-height]': '"inherit"'
}
})
export class NzTransButtonDirective {}
9 changes: 9 additions & 0 deletions components/core/trans-button/public-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

export { NzTransButtonDirective } from './nz-trans-button.directive';
2 changes: 2 additions & 0 deletions components/core/util/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ export * from './scroll-into-view-if-needed';
export * from './textarea-caret-position';
export * from './throttleByAnimationFrame';
export * from './time';
export * from './style-checke';
export * from './text-measure';
17 changes: 17 additions & 0 deletions components/core/util/style-checke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

export function isStyleSupport(styleName: string | string[]): boolean {
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
const { documentElement } = window.document;

return styleNameList.some(name => name in documentElement.style);
}
return false;
}
244 changes: 244 additions & 0 deletions components/core/util/text-measure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

export interface MeasureResult {
finished: boolean;
node: Node | null;
}

// We only handle element & text node.
const ELEMENT_NODE = 1;
const TEXT_NODE = 3;
const COMMENT_NODE = 8;

let ellipsisContainer: HTMLParagraphElement;

const wrapperStyle = {
padding: '0',
margin: '0',
display: 'inline',
lineHeight: 'inherit'
};

function pxToNumber(value: string | null): number {
if (!value) {
return 0;
}

const match = value.match(/^\d*(\.\d*)?/);

return match ? Number(match[0]) : 0;
}

function styleToString(style: CSSStyleDeclaration): string {
// There are some different behavior between Firefox & Chrome.
// We have to handle this ourself.
const styleNames: string[] = Array.prototype.slice.apply(style);
return styleNames.map(name => `${name}: ${style.getPropertyValue(name)};`).join('');
}

function mergeChildren(children: Node[]): Node[] {
const childList: Node[] = [];

children.forEach((child: Node) => {
const prevChild = childList[childList.length - 1];
if (prevChild && child.nodeType === TEXT_NODE && prevChild.nodeType === TEXT_NODE) {
(prevChild as Text).data += (child as Text).data;
} else {
childList.push(child);
}
});

return childList;
}

export function measure(
originEle: HTMLElement,
rows: number,
contentNodes: Node[],
fixedContent: HTMLElement[],
ellipsisStr: string
): { contentNodes: Node[]; text: string; ellipsis: boolean } {
if (!ellipsisContainer) {
ellipsisContainer = document.createElement('div');
ellipsisContainer.setAttribute('aria-hidden', 'true');
document.body.appendChild(ellipsisContainer);
}

// Get origin style
const originStyle = window.getComputedStyle(originEle);
const originCSS = styleToString(originStyle);
const lineHeight = pxToNumber(originStyle.lineHeight);
const maxHeight =
lineHeight * (rows + 1) + pxToNumber(originStyle.paddingTop) + pxToNumber(originStyle.paddingBottom);
// Set shadow
ellipsisContainer.setAttribute('style', originCSS);
ellipsisContainer.style.position = 'fixed';
ellipsisContainer.style.left = '0';
ellipsisContainer.style.height = 'auto';
ellipsisContainer.style.minHeight = 'auto';
ellipsisContainer.style.maxHeight = 'auto';
ellipsisContainer.style.top = '-999999px';
ellipsisContainer.style.zIndex = '-1000';

// clean up css overflow
ellipsisContainer.style.textOverflow = 'clip';
ellipsisContainer.style.whiteSpace = 'normal';
// tslint:disable-next-line no-any
(ellipsisContainer.style as any).webkitLineClamp = 'none';

const contentList = mergeChildren(contentNodes);
const container = document.createElement('div');
const contentContainer = document.createElement('span');
const fixedContainer = document.createElement('span');

// Add styles in container
Object.assign(container.style, wrapperStyle);
Object.assign(contentContainer.style, wrapperStyle);
Object.assign(fixedContainer.style, wrapperStyle);

contentList.forEach(n => {
contentContainer.appendChild(n);
});
fixedContent.forEach(node => {
fixedContainer.appendChild(node.cloneNode(true));
});
container.appendChild(contentContainer);
container.appendChild(fixedContainer);

// Render in the fake container
ellipsisContainer.appendChild(container);

// Check if ellipsis in measure div is height enough for content
function inRange(): boolean {
return ellipsisContainer.offsetHeight < maxHeight;
}

if (inRange()) {
const text = ellipsisContainer.innerHTML;
ellipsisContainer.removeChild(container);
return { contentNodes, text, ellipsis: false };
}

// We should clone the childNode since they're controlled by React and we can't reuse it without warning
const childNodes: ChildNode[] = Array.prototype.slice
.apply(ellipsisContainer.childNodes[0].childNodes[0].cloneNode(true).childNodes)
.filter(({ nodeType }: ChildNode) => nodeType !== COMMENT_NODE);
const fixedNodes: ChildNode[] = Array.prototype.slice.apply(
ellipsisContainer.childNodes[0].childNodes[1].cloneNode(true).childNodes
);
ellipsisContainer.removeChild(container);

// ========================= Find match ellipsis content =========================
ellipsisContainer.innerHTML = '';

// Create origin content holder
const ellipsisContentHolder = document.createElement('span');
ellipsisContainer.appendChild(ellipsisContentHolder);
const ellipsisTextNode = document.createTextNode(ellipsisStr);
ellipsisContentHolder.appendChild(ellipsisTextNode);

fixedNodes.forEach(childNode => {
ellipsisContainer.appendChild(childNode);
});

// Append before fixed nodes
function appendChildNode(node: ChildNode): void {
ellipsisContentHolder.insertBefore(node, ellipsisTextNode);
}

// Get maximum text
function measureText(
textNode: Text,
fullText: string,
startLoc: number = 0,
endLoc: number = fullText.length,
lastSuccessLoc: number = 0
): MeasureResult {
const midLoc = Math.floor((startLoc + endLoc) / 2);
const currentText = fullText.slice(0, midLoc);
textNode.textContent = currentText;

if (startLoc >= endLoc - 1) {
// Loop when step is small
for (let step = endLoc; step >= startLoc; step -= 1) {
const currentStepText = fullText.slice(0, step);
textNode.textContent = currentStepText;

if (inRange()) {
return step === fullText.length
? {
finished: false,
node: document.createTextNode(fullText)
}
: {
finished: true,
node: document.createTextNode(currentStepText)
};
}
}
}
if (inRange()) {
return measureText(textNode, fullText, midLoc, endLoc, midLoc);
} else {
return measureText(textNode, fullText, startLoc, midLoc, lastSuccessLoc);
}
}

function measureNode(childNode: ChildNode, index: number): MeasureResult {
const type = childNode.nodeType;

if (type === ELEMENT_NODE) {
// We don't split element, it will keep if whole element can be displayed.
// appendChildNode(childNode);
if (inRange()) {
return {
finished: false,
node: contentList[index]
};
}

// Clean up if can not pull in
ellipsisContentHolder.removeChild(childNode);
return {
finished: true,
node: null
};
} else if (type === TEXT_NODE) {
const fullText = childNode.textContent || '';
const textNode = document.createTextNode(fullText);
appendChildNode(textNode);
return measureText(textNode, fullText);
}

// Not handle other type of content
// PS: This code should not be attached after react 16
return {
finished: false,
node: null
};
}

const ellipsisNodes: Node[] = [];
childNodes.some((childNode, index) => {
const { finished, node } = measureNode(childNode, index);
if (node) {
ellipsisNodes.push(node);
}
return finished;
});
const result = {
contentNodes: ellipsisNodes,
text: ellipsisContainer.innerHTML,
ellipsis: true
};
while (ellipsisContainer.firstChild) {
ellipsisContainer.removeChild(ellipsisContainer.firstChild);
}
return result;
}
9 changes: 9 additions & 0 deletions components/i18n/languages/en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,14 @@ export default {
},
Empty: {
description: 'No Data'
},
Text: {
edit: 'edit',
copy: 'copy',
copied: 'copy success',
expand: 'expand'
},
PageHeader: {
back: 'back'
}
};
Loading