palt-typesetting 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -18
- package/bundle/typesetter.min.js +1 -6
- package/dist/apply-style.d.ts +3 -2
- package/dist/apply-style.d.ts.map +1 -1
- package/dist/apply-style.js +37 -34
- package/dist/html-processor.d.ts +1 -1
- package/dist/html-processor.d.ts.map +1 -1
- package/dist/html-processor.js +88 -55
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -61
- package/dist/insert-separators.d.ts +3 -3
- package/dist/insert-separators.d.ts.map +1 -1
- package/dist/insert-separators.js +40 -40
- package/dist/style/typesetting.css +27 -0
- package/dist/{utils-regex.d.ts → util-regex.d.ts} +3 -1
- package/dist/util-regex.d.ts.map +1 -0
- package/dist/util-regex.js +20 -0
- package/dist/util-tags.d.ts +9 -0
- package/dist/util-tags.d.ts.map +1 -0
- package/dist/util-tags.js +55 -0
- package/dist/{utils-text-classes.d.ts → util-text-classes.d.ts} +3 -2
- package/dist/util-text-classes.d.ts.map +1 -0
- package/dist/util-text-classes.js +98 -0
- package/dist/win-browser.js +4 -4
- package/dist/win.js +6 -6
- package/package.json +16 -11
- package/{dist/types → types}/index.d.ts +0 -5
- package/bundle/typesetter.min.js.map +0 -7
- package/dist/apply-style.js.map +0 -1
- package/dist/bundle.d.ts +0 -2
- package/dist/bundle.d.ts.map +0 -1
- package/dist/bundle.js.map +0 -1
- package/dist/html-processor.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/insert-separators.js.map +0 -1
- package/dist/utils-regex.d.ts.map +0 -1
- package/dist/utils-regex.js +0 -10
- package/dist/utils-regex.js.map +0 -1
- package/dist/utils-tags.d.ts +0 -8
- package/dist/utils-tags.d.ts.map +0 -1
- package/dist/utils-tags.js +0 -44
- package/dist/utils-tags.js.map +0 -1
- package/dist/utils-text-classes.d.ts.map +0 -1
- package/dist/utils-text-classes.js +0 -78
- package/dist/utils-text-classes.js.map +0 -1
- package/dist/win-browser.js.map +0 -1
- package/dist/win.js.map +0 -1
- /package/{dist/types → types}/linebreak.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,73 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import HTMLProcessor from "./html-processor";
|
|
2
|
+
import insertSeparatorsToText from "./insert-separators";
|
|
3
|
+
import { applyStyleToText, applyStyleToSegment, applyKerningToSegment } from "./apply-style";
|
|
4
|
+
import win from "./win";
|
|
5
|
+
class Typesetter extends HTMLProcessor {
|
|
6
|
+
/**
|
|
7
|
+
* Typesetter のデフォルトの設定を返します。
|
|
8
|
+
*/
|
|
9
|
+
static getDefaultOptions() {
|
|
10
|
+
return {
|
|
11
|
+
useWordBreak: true,
|
|
12
|
+
wrapLatin: true,
|
|
13
|
+
noSpaceBetweenNoBreaks: true,
|
|
14
|
+
insertThinSpaces: true,
|
|
15
|
+
thinSpaceWidth: "0.2em",
|
|
16
|
+
kerningRules: []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
const transformFunctions = [applyStyleToText, insertSeparatorsToText, applyStyleToSegment, applyKerningToSegment];
|
|
21
|
+
const validatedOptions = Typesetter.validateOptions(options);
|
|
22
|
+
super(transformFunctions, validatedOptions);
|
|
23
|
+
this.isIntlSegmenterSupported = typeof Intl.Segmenter !== "undefined";
|
|
24
|
+
if (!this.isIntlSegmenterSupported) {
|
|
25
|
+
console.warn(`
|
|
18
26
|
Intl.Segmenter is not supported in this environment.
|
|
19
27
|
The original HTML string will be returned.
|
|
20
28
|
For more information, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter
|
|
21
29
|
`);
|
|
22
|
-
}
|
|
23
30
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 与えられたオプションを検証し、修正されたオプションを返します。
|
|
34
|
+
*
|
|
35
|
+
* @param options - 検証するオプション。
|
|
36
|
+
* @return 修正されたオプション。
|
|
37
|
+
*/
|
|
38
|
+
static validateOptions(options) {
|
|
39
|
+
if (options.kerningRules) {
|
|
40
|
+
options.kerningRules = options.kerningRules.filter(Typesetter.isValidKerningRule);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
...Typesetter.getDefaultOptions(),
|
|
44
|
+
...options
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* カーニングルールが適切かどうかを検証します。
|
|
49
|
+
*
|
|
50
|
+
* @param kerningRule - 検証するカーニングルール。
|
|
51
|
+
* @return ルールが有効な場合はtrue、そうでない場合はfalse。
|
|
52
|
+
*/
|
|
53
|
+
static isValidKerningRule(kerningRule) {
|
|
54
|
+
if (kerningRule.between[0].length !== 1 || kerningRule.between[1].length !== 1) {
|
|
55
|
+
console.warn(
|
|
56
|
+
`Kerning rule between '${kerningRule.between[0]}' and '${kerningRule.between[1]}' must be single characters.`
|
|
57
|
+
);
|
|
58
|
+
return false;
|
|
29
59
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 与えられたHTML文字列を処理し、指定されたスタイルと区切り文字を適用した結果を返します。
|
|
64
|
+
*
|
|
65
|
+
* @param srcHtml - 処理するHTML文字列。
|
|
66
|
+
* @return 処理後のHTML文字列。
|
|
67
|
+
*/
|
|
68
|
+
render(srcHtml) {
|
|
69
|
+
if (!this.isIntlSegmenterSupported || !srcHtml) {
|
|
70
|
+
return srcHtml;
|
|
36
71
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
72
|
+
return this.processHtmlWithFunctions(srcHtml);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 与えられたElementまたはElementの配列に対して、スタイルと区切り文字を適用します。
|
|
76
|
+
* 各要素のinnerHTMLを取得し、変換処理を適用した後、変換されたHTMLで元の内容を置き換えます。
|
|
77
|
+
*
|
|
78
|
+
* @param elements - スタイルを適用するElementまたはHTMLElementの配列。
|
|
79
|
+
*/
|
|
80
|
+
renderToElements(elements) {
|
|
81
|
+
if (!this.isIntlSegmenterSupported || !elements) {
|
|
82
|
+
return;
|
|
42
83
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
if (!Array.isArray(elements)) {
|
|
48
|
-
elements = [elements];
|
|
49
|
-
}
|
|
50
|
-
elements.forEach(element => {
|
|
51
|
-
const processedHtml = this.render(element.innerHTML);
|
|
52
|
-
element.innerHTML = processedHtml;
|
|
53
|
-
});
|
|
84
|
+
if (!Array.isArray(elements)) {
|
|
85
|
+
elements = [elements];
|
|
54
86
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
87
|
+
elements.forEach((element) => {
|
|
88
|
+
const processedHtml = this.render(element.innerHTML);
|
|
89
|
+
element.innerHTML = processedHtml;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 指定されたCSSセレクタに一致するすべての要素にスタイルを適用します。
|
|
94
|
+
* document.querySelectorAllを使用して要素を取得し、それぞれに対してスタイル適用処理を行います。
|
|
95
|
+
*
|
|
96
|
+
* @param selector - スタイルを適用する要素を選択するCSSセレクタ。
|
|
97
|
+
*/
|
|
98
|
+
renderToSelector(selector) {
|
|
99
|
+
if (!this.isIntlSegmenterSupported || !selector) {
|
|
100
|
+
return;
|
|
61
101
|
}
|
|
102
|
+
const elements = win.document.querySelectorAll(selector);
|
|
103
|
+
this.renderToElements(Array.from(elements));
|
|
104
|
+
}
|
|
62
105
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
wrapLatin: true,
|
|
67
|
-
noSpaceBetweenNoBreaks: true,
|
|
68
|
-
insertThinSpaces: true,
|
|
69
|
-
thinSpaceWidth: '50%',
|
|
70
|
-
kerningRules: [],
|
|
106
|
+
var src_default = Typesetter;
|
|
107
|
+
export {
|
|
108
|
+
src_default as default
|
|
71
109
|
};
|
|
72
|
-
exports.default = Typesetter;
|
|
73
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { TypesettingOptions } from '
|
|
1
|
+
import { TypesettingOptions } from '../types';
|
|
2
2
|
declare const insertSeparatorsToText: (currentText: string, nextText: string, options: TypesettingOptions) => string;
|
|
3
3
|
declare const createSegments: (src: string) => string[];
|
|
4
4
|
declare const addSeparatorsToSegment: (current: string, next: string | undefined, options: TypesettingOptions) => string;
|
|
5
|
-
declare const shouldAddWbr: (current: string, next: string) => boolean | null;
|
|
6
5
|
declare const shouldAddThinSpace: (current: string, next: string) => boolean;
|
|
6
|
+
declare const isBreakable: (current: string, next: string) => boolean;
|
|
7
7
|
export default insertSeparatorsToText;
|
|
8
|
-
export { createSegments, addSeparatorsToSegment,
|
|
8
|
+
export { createSegments, addSeparatorsToSegment, shouldAddThinSpace, isBreakable };
|
|
9
9
|
//# sourceMappingURL=insert-separators.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insert-separators.d.ts","sourceRoot":"","sources":["../src/insert-separators.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"insert-separators.d.ts","sourceRoot":"","sources":["../src/insert-separators.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAQ7C,QAAA,MAAM,sBAAsB,gBAAiB,MAAM,YAAY,MAAM,WAAW,kBAAkB,KAAG,MAWpG,CAAA;AAOD,QAAA,MAAM,cAAc,QAAS,MAAM,KAAG,MAAM,EAG3C,CAAA;AAQD,QAAA,MAAM,sBAAsB,YAAa,MAAM,qCAAsB,kBAAkB,KAAG,MAezF,CAAA;AAQD,QAAA,MAAM,kBAAkB,YAAa,MAAM,QAAQ,MAAM,KAAG,OAE3D,CAAA;AAQD,QAAA,MAAM,WAAW,YAAa,MAAM,QAAQ,MAAM,KAAG,OAKpD,CAAA;AAED,eAAe,sBAAsB,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.shouldAddThinSpace = exports.shouldAddWbr = exports.addSeparatorsToSegment = exports.createSegments = void 0;
|
|
7
|
-
const linebreak_1 = __importDefault(require("linebreak"));
|
|
8
|
-
const utils_text_classes_1 = require("./utils-text-classes");
|
|
9
|
-
const utils_tags_1 = require("./utils-tags");
|
|
1
|
+
import LineBreaker from "linebreak";
|
|
2
|
+
import { CharClass, LanguageClass } from "./util-text-classes";
|
|
3
|
+
import { createWbr, createThinSpace } from "./util-tags";
|
|
10
4
|
const insertSeparatorsToText = (currentText, nextText, options) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
const currentSegments = createSegments(currentText);
|
|
6
|
+
const nextSegments = createSegments(nextText);
|
|
7
|
+
const formattedText = currentSegments.reduce((accumulatedText, segment, index, array) => {
|
|
8
|
+
const current = segment;
|
|
9
|
+
const next = array[index + 1] || nextSegments[0];
|
|
10
|
+
return accumulatedText + addSeparatorsToSegment(current, next, options);
|
|
11
|
+
}, "");
|
|
12
|
+
return formattedText;
|
|
19
13
|
};
|
|
20
14
|
const createSegments = (src) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
exports.createSegments = createSegments;
|
|
25
|
-
const addSeparatorsToSegment = (current, next = '', options) => {
|
|
26
|
-
if (!next)
|
|
27
|
-
return current;
|
|
28
|
-
const addWbr = options.useWordBreak && shouldAddWbr(current, next);
|
|
29
|
-
const addSpace = options.insertThinSpaces && shouldAddThinSpace(current, next);
|
|
30
|
-
return (current +
|
|
31
|
-
(addSpace ? (0, utils_tags_1.createThinSpaceSpan)(options.thinSpaceWidth, options.classNamePrefix) : '') +
|
|
32
|
-
(addWbr ? utils_tags_1.wbr : ''));
|
|
15
|
+
const segmenter = new Intl.Segmenter("ja-JP", { granularity: "word" });
|
|
16
|
+
return Array.from(segmenter.segment(src), ({ segment }) => segment);
|
|
33
17
|
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
18
|
+
const addSeparatorsToSegment = (current, next = "", options) => {
|
|
19
|
+
if (!next)
|
|
20
|
+
return current;
|
|
21
|
+
const addThinSpace = options.insertThinSpaces && shouldAddThinSpace(current, next);
|
|
22
|
+
const breakable = isBreakable(current, next);
|
|
23
|
+
if (addThinSpace) {
|
|
24
|
+
return current + createThinSpace(options.thinSpaceWidth, breakable);
|
|
25
|
+
}
|
|
26
|
+
if (options.useWordBreak && breakable) {
|
|
27
|
+
return current + createWbr();
|
|
28
|
+
}
|
|
29
|
+
return current;
|
|
40
30
|
};
|
|
41
|
-
exports.shouldAddWbr = shouldAddWbr;
|
|
42
31
|
const shouldAddThinSpace = (current, next) => {
|
|
43
|
-
|
|
32
|
+
return LanguageClass.shouldAddThinSpace(current, next) || CharClass.shouldAddThinSpace(current, next);
|
|
33
|
+
};
|
|
34
|
+
const isBreakable = (current, next) => {
|
|
35
|
+
const combinedText = current.slice(-1) + next.slice(0, 1);
|
|
36
|
+
const lb = new LineBreaker(combinedText);
|
|
37
|
+
const breakOpportunity = lb.nextBreak();
|
|
38
|
+
return breakOpportunity ? breakOpportunity.position === 1 : false;
|
|
39
|
+
};
|
|
40
|
+
var insert_separators_default = insertSeparatorsToText;
|
|
41
|
+
export {
|
|
42
|
+
addSeparatorsToSegment,
|
|
43
|
+
createSegments,
|
|
44
|
+
insert_separators_default as default,
|
|
45
|
+
isBreakable,
|
|
46
|
+
shouldAddThinSpace
|
|
44
47
|
};
|
|
45
|
-
exports.shouldAddThinSpace = shouldAddThinSpace;
|
|
46
|
-
exports.default = insertSeparatorsToText;
|
|
47
|
-
//# sourceMappingURL=insert-separators.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
/*
|
|
3
|
+
* カスタムフォント: 1/10000 UPM 幅のスペースとノンブレーキングスペースを定義。
|
|
4
|
+
* 注意:完全なゼロ幅スペースを使用すると、Safari では letter-spacing が無視される。
|
|
5
|
+
* @sharapeco による貢献に感謝します。{@link https://gist.github.com/sharapeco/1dd7f4433dad07648e1325e1fa5926ee}
|
|
6
|
+
*/
|
|
7
|
+
font-family: ling-one;
|
|
8
|
+
src: url('data:font/woff2;base64,AAEAAAAKAIAAAwAgT1MvMhG03xcAAAEoAAAAYGNtYXAADABzAAABkAAAADRnbHlmJAM2GwAAAcwAAAAYaGVhZCLbfFwAAACsAAAANmhoZWEnEvkrAAAA5AAAACRobXR4AAEAAAAAAYgAAAAIbG9jYQAMABgAAAHEAAAACG1heHAAcQAiAAABCAAAACBuYW1lBbsdPAAAAeQAAACKcG9zdHQrY6cAAAJwAAAALQABAAAAAQAAsWqD8F8PPPUAAycQAAAAAOHcugAAAAAA4edeTwAAAAAAAQABAAAABwACAAAAAAAAAAEAACcQ+DAAAAB9AAAAfAABAAEAAAAAAAAAAAAAAAAAAAABAAEAAAADAAMAAQAAAAAAAQACAB4ABgAAAGQAAAAAAAAAAwB9AZAABQAIGWQXcAAAAu4ZZBdwAAANrAAyC7gAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc3N6bQBAACAAIB9A+DAH0CcQB9AAAAABAAAAABOIG1gAAAAgAAAAAQAAAAAAAAAAAAIAAAADAAAAFAADAAEAAAAUAAQAIAAAAAQABAABAAAAIP//AAAAIP///+EAAQAAAAAAAAAMAAwADAABAAAAAAABAAEAAgAANRcjAQEBAQAAAAAAAAYATgADAAEECQABAAgAAAADAAEECQACAAIACAADAAEECQADAB4ACgADAAEECQAEAAwAKAADAAEECQAFAAgANAADAAEECQAGAAwAKABMAGkAbgBnADEAMQAuADAAOwBzAHMAegBtADsATABpAG4AZwAtADEATABpAG4AZwAtADEAdgAxAC4AMAAAAAIAAAAAAAD/tQAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAMBAgRuYnNwAAAA')
|
|
9
|
+
format('woff2');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.typeset-word-break {
|
|
13
|
+
word-break: keep-all;
|
|
14
|
+
overflow-wrap: anywhere;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.typeset-thin-space,
|
|
18
|
+
.typeset-kerning {
|
|
19
|
+
font-family: ling-one; /* カスタムフォントのスペースを使用します。 */
|
|
20
|
+
line-height: 0; /* 空白による行の高さの影響を無視します。 */
|
|
21
|
+
letter-spacing: 0; /* 親要素から継承される letter-spacing の影響を無視します。 */
|
|
22
|
+
user-select: none; /* ユーザーによるテキストのコピーを無効にします。 */
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.typeset-no-breaks {
|
|
26
|
+
letter-spacing: 0; /* 親要素から継承される letter-spacing の影響を無視します。 */
|
|
27
|
+
}
|
|
@@ -3,5 +3,7 @@ export declare const japaneseRegex: RegExp;
|
|
|
3
3
|
export declare const openingsRegex: RegExp;
|
|
4
4
|
export declare const closingsRegex: RegExp;
|
|
5
5
|
export declare const middleDotsRegex: RegExp;
|
|
6
|
+
export declare const commasRegex: RegExp;
|
|
7
|
+
export declare const periodsRegex: RegExp;
|
|
6
8
|
export declare const noBreakRulesRegex: RegExp;
|
|
7
|
-
//# sourceMappingURL=
|
|
9
|
+
//# sourceMappingURL=util-regex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util-regex.d.ts","sourceRoot":"","sources":["../src/util-regex.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,QAC4E,CAAA;AAKnG,eAAO,MAAM,aAAa,QAAwD,CAAA;AAKlF,eAAO,MAAM,aAAa,QAA8B,CAAA;AAKxD,eAAO,MAAM,aAAa,QAA8B,CAAA;AAKxD,eAAO,MAAM,eAAe,QAAU,CAAA;AAKtC,eAAO,MAAM,WAAW,QAAQ,CAAA;AAKhC,eAAO,MAAM,YAAY,QAAQ,CAAA;AAKjC,eAAO,MAAM,iBAAiB,QAE7B,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const latinRegex = /[\p{scx=Latin}0-9⁰¹²³⁴-⁾₀-₎¢¤$€£¥+−×÷=≠><≥≤±≈~¬∅∞∫∏∑√∂%‰@&.,:;!¡?¿'"‘’“”\-(){}[\]|/\\^_`*#\s]+/u;
|
|
2
|
+
const japaneseRegex = /[\p{scx=Hiragana}\p{scx=Katakana}|ヲ-゚\p{scx=Han}]+/u;
|
|
3
|
+
const openingsRegex = /(|[|{|〔|〈|《|「|『|【|〘|〖|“|‘/;
|
|
4
|
+
const closingsRegex = /)|]|}|〕|〉|》|」|』|】|〙|〗|”|’/;
|
|
5
|
+
const middleDotsRegex = /・|:|;/;
|
|
6
|
+
const commasRegex = /、|,/;
|
|
7
|
+
const periodsRegex = /。|./;
|
|
8
|
+
const noBreakRulesRegex = new RegExp(
|
|
9
|
+
`[${"\u2014\u2025\u2026\uFF3F"}${String.fromCharCode(9472)}-${String.fromCharCode(9599)}]+`
|
|
10
|
+
);
|
|
11
|
+
export {
|
|
12
|
+
closingsRegex,
|
|
13
|
+
commasRegex,
|
|
14
|
+
japaneseRegex,
|
|
15
|
+
latinRegex,
|
|
16
|
+
middleDotsRegex,
|
|
17
|
+
noBreakRulesRegex,
|
|
18
|
+
openingsRegex,
|
|
19
|
+
periodsRegex
|
|
20
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import './style/typesetting.css';
|
|
2
|
+
declare const createWbr: () => string;
|
|
3
|
+
declare const createThinSpace: (thisSpaceWidth: string, breakable?: boolean) => string;
|
|
4
|
+
declare const createKerning: (kerningValue: number, breakable?: boolean) => string;
|
|
5
|
+
declare const applyWrapperStyle: (text: string, useWordBreak: boolean) => string;
|
|
6
|
+
declare const applyLatinStyle: (segment: string) => string;
|
|
7
|
+
declare const applyNoBreaksStyle: (segment: string) => string;
|
|
8
|
+
export { createWbr, createThinSpace, createKerning, applyWrapperStyle, applyLatinStyle, applyNoBreaksStyle };
|
|
9
|
+
//# sourceMappingURL=util-tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util-tags.d.ts","sourceRoot":"","sources":["../src/util-tags.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA;AAMhC,QAAA,MAAM,SAAS,QAAO,MAErB,CAAA;AAQD,QAAA,MAAM,eAAe,mBAAoB,MAAM,cAAc,OAAO,KAAG,MAMtE,CAAA;AASD,QAAA,MAAM,aAAa,iBAAkB,MAAM,cAAc,OAAO,KAAG,MAiBlE,CAAA;AAQD,QAAA,MAAM,iBAAiB,SAAU,MAAM,gBAAgB,OAAO,KAAG,MAKhE,CAAA;AAOD,QAAA,MAAM,eAAe,YAAa,MAAM,KAAG,MAG1C,CAAA;AAOD,QAAA,MAAM,kBAAkB,YAAa,MAAM,KAAG,MAG7C,CAAA;AAuBD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import "./style/typesetting.css";
|
|
2
|
+
const createWbr = () => {
|
|
3
|
+
return "<wbr>";
|
|
4
|
+
};
|
|
5
|
+
const createThinSpace = (thisSpaceWidth, breakable) => {
|
|
6
|
+
const content = breakable ? " " : " ";
|
|
7
|
+
const className = "typeset-thin-space";
|
|
8
|
+
const style = `letter-spacing: ${thisSpaceWidth};`;
|
|
9
|
+
const uiIgnored = true;
|
|
10
|
+
return createStyledSpan(content, className, style, uiIgnored);
|
|
11
|
+
};
|
|
12
|
+
const createKerning = (kerningValue, breakable) => {
|
|
13
|
+
if (kerningValue === 0)
|
|
14
|
+
return "";
|
|
15
|
+
const className = "typeset-kerning";
|
|
16
|
+
const uiIgnored = true;
|
|
17
|
+
if (kerningValue < 0) {
|
|
18
|
+
const content = "";
|
|
19
|
+
const emValue = kerningValue / 1e3 / 2 + "em";
|
|
20
|
+
const style = `margin: ${emValue};`;
|
|
21
|
+
return createStyledSpan(content, className, style, uiIgnored);
|
|
22
|
+
} else {
|
|
23
|
+
const content = breakable ? " " : " ";
|
|
24
|
+
const emValue = kerningValue / 1e3 + "em";
|
|
25
|
+
const style = `letter-spacing: ${emValue};`;
|
|
26
|
+
return createStyledSpan(content, className, style, uiIgnored);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const applyWrapperStyle = (text, useWordBreak) => {
|
|
30
|
+
const wrapperName = "typeset";
|
|
31
|
+
const wordBreakName = "typeset-word-break";
|
|
32
|
+
const className = useWordBreak ? `${wrapperName} ${wordBreakName}` : wrapperName;
|
|
33
|
+
return createStyledSpan(text, className);
|
|
34
|
+
};
|
|
35
|
+
const applyLatinStyle = (segment) => {
|
|
36
|
+
const className = "typeset-latin";
|
|
37
|
+
return createStyledSpan(segment, className);
|
|
38
|
+
};
|
|
39
|
+
const applyNoBreaksStyle = (segment) => {
|
|
40
|
+
const className = "typeset-no-breaks";
|
|
41
|
+
return createStyledSpan(segment, className);
|
|
42
|
+
};
|
|
43
|
+
const createStyledSpan = (content, className, style = "", uiIgnored = false) => {
|
|
44
|
+
const styleAttr = style ? ` style="${style}"` : "";
|
|
45
|
+
const extraAttrs = uiIgnored ? ' aria-hidden="true" data-nosnippet=""' : "";
|
|
46
|
+
return `<span class="${className}"${styleAttr}${extraAttrs}>${content}</span>`;
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
applyLatinStyle,
|
|
50
|
+
applyNoBreaksStyle,
|
|
51
|
+
applyWrapperStyle,
|
|
52
|
+
createKerning,
|
|
53
|
+
createThinSpace,
|
|
54
|
+
createWbr
|
|
55
|
+
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
declare const CharClass: {
|
|
2
2
|
shouldNotBreak: (segment: string) => boolean;
|
|
3
3
|
shouldAddThinSpace: (current: string, next: string) => boolean;
|
|
4
|
+
startsWithPunctuation: (segment: string) => boolean;
|
|
4
5
|
};
|
|
5
6
|
declare const LanguageClass: {
|
|
6
7
|
isLatin: (segment: string) => boolean;
|
|
7
8
|
isJapanese: (segment: string) => boolean;
|
|
8
|
-
|
|
9
|
+
hasLanguageTransition: (current: string, next: string) => boolean;
|
|
9
10
|
shouldAddThinSpace: (current: string, next: string) => boolean;
|
|
10
11
|
};
|
|
11
12
|
export { CharClass, LanguageClass };
|
|
12
|
-
//# sourceMappingURL=
|
|
13
|
+
//# sourceMappingURL=util-text-classes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util-text-classes.d.ts","sourceRoot":"","sources":["../src/util-text-classes.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,SAAS;8BAMa,MAAM,KAAG,OAAO;kCAUZ,MAAM,QAAQ,MAAM,KAAG,OAAO;qCA0C3B,MAAM,KAAG,OAAO;CAKlD,CAAA;AAOD,QAAA,MAAM,aAAa;uBAME,MAAM,KAAG,OAAO;0BASb,MAAM,KAAG,OAAO;qCAWL,MAAM,QAAQ,MAAM,KAAG,OAAO;kCAUjC,MAAM,QAAQ,MAAM,KAAG,OAAO;CAG7D,CAAA;AAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as util from "./util-regex";
|
|
2
|
+
const CharClass = {
|
|
3
|
+
/**
|
|
4
|
+
* セグメントが分離禁則文字で構成されているかどうかを判定します。
|
|
5
|
+
* @param segment - 判定するテキストセグメント
|
|
6
|
+
* @return 分離禁則文字で構成されている場合はtrue、そうでない場合はfalse
|
|
7
|
+
*/
|
|
8
|
+
shouldNotBreak: (segment) => {
|
|
9
|
+
return util.noBreakRulesRegex.test(segment);
|
|
10
|
+
},
|
|
11
|
+
/**
|
|
12
|
+
* 2つのセグメント間に四分アキを追加すべきかを判断します。
|
|
13
|
+
* @param current - 現在のセグメント
|
|
14
|
+
* @param next - 次のセグメント
|
|
15
|
+
* @return 四分アキを追加すべきかどうか
|
|
16
|
+
*/
|
|
17
|
+
shouldAddThinSpace: (current, next) => {
|
|
18
|
+
const spaceAfterRegex = new RegExp(
|
|
19
|
+
`(${util.closingsRegex.source}|${util.commasRegex.source}|${util.periodsRegex.source})`
|
|
20
|
+
);
|
|
21
|
+
const settings = {
|
|
22
|
+
spaceBefore: {
|
|
23
|
+
regex: util.openingsRegex,
|
|
24
|
+
hasSpaceBefore: true,
|
|
25
|
+
hasSpaceAfter: false
|
|
26
|
+
},
|
|
27
|
+
spaceAfter: {
|
|
28
|
+
regex: spaceAfterRegex,
|
|
29
|
+
hasSpaceBefore: false,
|
|
30
|
+
hasSpaceAfter: true
|
|
31
|
+
},
|
|
32
|
+
spaceBoth: {
|
|
33
|
+
regex: util.middleDotsRegex,
|
|
34
|
+
hasSpaceBefore: true,
|
|
35
|
+
hasSpaceAfter: true
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
for (const { regex, hasSpaceBefore, hasSpaceAfter } of Object.values(settings)) {
|
|
39
|
+
if (hasSpaceBefore && regex.test(next) && !regex.test(current)) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
if (hasSpaceAfter && regex.test(current) && !regex.test(next)) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* 与えられた文字列の最初の文字が句読点に一致するかどうか判断します。
|
|
50
|
+
* @param {string} segment - 判断対象の文字列
|
|
51
|
+
* @return {boolean} 最初の文字が句読点であればtrueを返します。
|
|
52
|
+
*/
|
|
53
|
+
startsWithPunctuation: (segment) => {
|
|
54
|
+
const combinedRegex = new RegExp(`^[${util.periodsRegex.source}${util.commasRegex.source}]`);
|
|
55
|
+
return combinedRegex.test(segment);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const LanguageClass = {
|
|
59
|
+
/**
|
|
60
|
+
* セグメントがラテン文字で構成されているかどうかを判定します。
|
|
61
|
+
* @param segment - 判定するテキストセグメント
|
|
62
|
+
* @return ラテン文字で構成されている場合はtrue、そうでない場合はfalse
|
|
63
|
+
*/
|
|
64
|
+
isLatin: (segment) => {
|
|
65
|
+
return util.latinRegex.test(segment);
|
|
66
|
+
},
|
|
67
|
+
/**
|
|
68
|
+
* セグメントが日本語文字で構成されているかどうかを判定します。
|
|
69
|
+
* @param segment - 判定するテキストセグメント
|
|
70
|
+
* @return 日本語文字で構成されている場合はtrue、そうでない場合はfalse
|
|
71
|
+
*/
|
|
72
|
+
isJapanese: (segment) => {
|
|
73
|
+
return util.japaneseRegex.test(segment);
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* 現在のセグメントと次のセグメントの言語が異なるかどうかを判定します。
|
|
77
|
+
* この関数は、一方が日本語で他方が非日本語の場合にtrueを返します。
|
|
78
|
+
* @param current - 現在のテキストセグメント
|
|
79
|
+
* @param next - 次のテキストセグメント
|
|
80
|
+
* @return 両セグメント間で言語が異なる場合にtrueを返す
|
|
81
|
+
*/
|
|
82
|
+
hasLanguageTransition: (current, next) => {
|
|
83
|
+
return LanguageClass.isJapanese(current) !== LanguageClass.isJapanese(next);
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* 2つのセグメント間に四分アキを追加すべきかを判断します。
|
|
87
|
+
* @param current - 現在のセグメント
|
|
88
|
+
* @param next - 次のセグメント
|
|
89
|
+
* @return 四分アキを追加すべきかどうか
|
|
90
|
+
*/
|
|
91
|
+
shouldAddThinSpace: (current, next) => {
|
|
92
|
+
return LanguageClass.hasLanguageTransition(current, next) && !CharClass.startsWithPunctuation(next);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
export {
|
|
96
|
+
CharClass,
|
|
97
|
+
LanguageClass
|
|
98
|
+
};
|
package/dist/win-browser.js
CHANGED
package/dist/win.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { JSDOM } from "jsdom";
|
|
2
|
+
const win = new JSDOM().window;
|
|
3
|
+
var win_default = win;
|
|
4
|
+
export {
|
|
5
|
+
win_default as default
|
|
6
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "palt-typesetting",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A typesetting library.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
6
7
|
"files": [
|
|
8
|
+
"types/**/*",
|
|
7
9
|
"dist/**/*",
|
|
8
10
|
"bundle/**/*"
|
|
9
11
|
],
|
|
@@ -13,12 +15,10 @@
|
|
|
13
15
|
},
|
|
14
16
|
"scripts": {
|
|
15
17
|
"clean:dist": "rm -rf ./dist",
|
|
16
|
-
"copy:
|
|
17
|
-
"prebuild": "npm run clean:dist && npm run copy:
|
|
18
|
-
"build": "
|
|
19
|
-
"
|
|
20
|
-
"bundle": "esbuild ./dist/bundle.js --bundle --outfile=./bundle/typesetter.min.js --minify --sourcemap --platform=browser --target=es2016 --global-name=Typesetter",
|
|
21
|
-
"test": "jest",
|
|
18
|
+
"copy:css": "mkdir -p ./dist/style && cp -R ./src/style/* ./dist/style",
|
|
19
|
+
"prebuild": "npm run clean:dist && npm run copy:css",
|
|
20
|
+
"build": "node ./scripts/build.js && webpack",
|
|
21
|
+
"test": "vitest",
|
|
22
22
|
"lint": "eslint ./src/** --no-error-on-unmatched-pattern",
|
|
23
23
|
"lint:fix": "eslint ./src/** --fix"
|
|
24
24
|
},
|
|
@@ -35,16 +35,21 @@
|
|
|
35
35
|
"linebreak": "^1.1.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@
|
|
38
|
+
"@babel/core": "^7.23.9",
|
|
39
|
+
"@babel/preset-env": "^7.23.9",
|
|
39
40
|
"@types/jsdom": "^21.1.6",
|
|
40
41
|
"@types/node": "^20",
|
|
41
42
|
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
|
42
43
|
"@typescript-eslint/parser": "^6.18.0",
|
|
43
44
|
"babel-jest": "^29.7.0",
|
|
45
|
+
"babel-loader": "^9.1.3",
|
|
46
|
+
"css-loader": "^6.10.0",
|
|
44
47
|
"esbuild": "^0.19.11",
|
|
45
48
|
"eslint": "^8",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
+
"style-loader": "^3.3.4",
|
|
50
|
+
"typescript": "^5",
|
|
51
|
+
"vitest": "^1.2.2",
|
|
52
|
+
"webpack": "^5.90.3",
|
|
53
|
+
"webpack-cli": "^5.1.4"
|
|
49
54
|
}
|
|
50
55
|
}
|