New primitive to fill a line with as many doc parts as possible (#1120)
* Add new fill primitive and use it to wrap text in JSX This adds a new `fill` primitive that can be used to fill lines with as much code as possible before moving to a new line with the same indentation. It is used here layout JSX children. This gives us nicer wrapping for JSX elements containings lots of text interspersed with tags. * Quick fix for jsx whitespace regressions * Fix a couple more bugs * Tidy up the `fill` algorithm Attempt to make the algorithm a little more regular, and improve the naming of variables to make it a little easier to understand (I hope!). * Small tidy up of JSX whitespace declarations * Remove unnecessary code It turns out that `children` is only used in the case when the element is printed on a single line, in which case all the types of JSX whitespaces behave the same, so we don't need to special case leading/trailing/solitary whitespace. * A little more tidy up based on PR feedback * Fix up tests after rebasing * Make it explicit that we keep multiple consecutive spaces * Add an explanatory comment * Fix broken snapshot in master * Ignore existing commands when deciding whether content will fit when using fill * Fix a bug where children would get incorrectly filled onto a line * Tidy up JSX whitespace namesmaster
parent
d4217f5508
commit
5cda955efc
|
@ -54,6 +54,12 @@ function conditionalGroup(states, opts) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fill(parts) {
|
||||||
|
parts.forEach(assertDoc);
|
||||||
|
|
||||||
|
return { type: "fill", parts };
|
||||||
|
}
|
||||||
|
|
||||||
function ifBreak(breakContents, flatContents) {
|
function ifBreak(breakContents, flatContents) {
|
||||||
if (breakContents) {
|
if (breakContents) {
|
||||||
assertDoc(breakContents);
|
assertDoc(breakContents);
|
||||||
|
@ -103,6 +109,7 @@ module.exports = {
|
||||||
literalline,
|
literalline,
|
||||||
group,
|
group,
|
||||||
conditionalGroup,
|
conditionalGroup,
|
||||||
|
fill,
|
||||||
lineSuffix,
|
lineSuffix,
|
||||||
lineSuffixBoundary,
|
lineSuffixBoundary,
|
||||||
breakParent,
|
breakParent,
|
||||||
|
|
|
@ -101,6 +101,13 @@ function printDoc(doc) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doc.type === "fill") {
|
||||||
|
return ("fill") +
|
||||||
|
"(" +
|
||||||
|
doc.parts.map(printDoc).join(", ") +
|
||||||
|
")";
|
||||||
|
}
|
||||||
|
|
||||||
if (doc.type === "line-suffix") {
|
if (doc.type === "line-suffix") {
|
||||||
return "lineSuffix(" + printDoc(doc.contents) + ")";
|
return "lineSuffix(" + printDoc(doc.contents) + ")";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const docBuilders = require("./doc-builders");
|
||||||
|
const concat = docBuilders.concat;
|
||||||
|
const line = docBuilders.line;
|
||||||
|
const softline = docBuilders.softline;
|
||||||
|
const fill = docBuilders.fill;
|
||||||
|
const ifBreak = docBuilders.ifBreak;
|
||||||
|
|
||||||
const MODE_BREAK = 1;
|
const MODE_BREAK = 1;
|
||||||
const MODE_FLAT = 2;
|
const MODE_FLAT = 2;
|
||||||
|
|
||||||
|
@ -40,7 +47,7 @@ function makeAlign(ind, n) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function fits(next, restCommands, width) {
|
function fits(next, restCommands, width, mustBeFlat) {
|
||||||
let restIdx = restCommands.length;
|
let restIdx = restCommands.length;
|
||||||
const cmds = [next];
|
const cmds = [next];
|
||||||
while (width >= 0) {
|
while (width >= 0) {
|
||||||
|
@ -80,8 +87,17 @@ function fits(next, restCommands, width) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "group":
|
case "group":
|
||||||
|
if (mustBeFlat && doc.break) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]);
|
cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "fill":
|
||||||
|
for (var i = doc.parts.length - 1; i >= 0; i--) {
|
||||||
|
cmds.push([ind, mode, doc.parts[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "if-break":
|
case "if-break":
|
||||||
if (mode === MODE_BREAK) {
|
if (mode === MODE_BREAK) {
|
||||||
|
@ -220,6 +236,86 @@ function printDocToString(doc, options) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Fills each line with as much code as possible before moving to a new
|
||||||
|
// line with the same indentation.
|
||||||
|
//
|
||||||
|
// Expects doc.parts to be an array of alternating content and
|
||||||
|
// whitespace. The whitespace contains the linebreaks.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// ["I", line, "love", line, "monkeys"]
|
||||||
|
// or
|
||||||
|
// [{ type: group, ... }, softline, { type: group, ... }]
|
||||||
|
//
|
||||||
|
// It uses this parts structure to handle three main layout cases:
|
||||||
|
// * The first two content items fit on the same line without
|
||||||
|
// breaking
|
||||||
|
// -> output the first content item and the whitespace "flat".
|
||||||
|
// * Only the first content item fits on the line without breaking
|
||||||
|
// -> output the first content item "flat" and the whitespace with
|
||||||
|
// "break".
|
||||||
|
// * Neither content item fits on the line without breaking
|
||||||
|
// -> output the first content item and the whitespace with "break".
|
||||||
|
case "fill": {
|
||||||
|
let rem = width - pos;
|
||||||
|
|
||||||
|
const parts = doc.parts;
|
||||||
|
if (parts.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = parts[0];
|
||||||
|
const contentFlatCmd = [ind, MODE_FLAT, content];
|
||||||
|
const contentBreakCmd = [ind, MODE_BREAK, content];
|
||||||
|
const contentFits = fits(contentFlatCmd, [], width - rem, true)
|
||||||
|
|
||||||
|
if (parts.length === 1) {
|
||||||
|
if (contentFits) {
|
||||||
|
cmds.push(contentFlatCmd);
|
||||||
|
} else {
|
||||||
|
cmds.push(contentBreakCmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const whitespace = parts[1];
|
||||||
|
const whitespaceFlatCmd = [ind, MODE_FLAT, whitespace]
|
||||||
|
const whitespaceBreakCmd = [ind, MODE_BREAK, whitespace]
|
||||||
|
|
||||||
|
if (parts.length === 2) {
|
||||||
|
if (contentFits) {
|
||||||
|
cmds.push(whitespaceFlatCmd);
|
||||||
|
cmds.push(contentFlatCmd);
|
||||||
|
} else {
|
||||||
|
cmds.push(whitespaceBreakCmd);
|
||||||
|
cmds.push(contentBreakCmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const remaining = parts.slice(2);
|
||||||
|
const remainingCmd = [ind, mode, fill(remaining)];
|
||||||
|
|
||||||
|
const secondContent = parts[2];
|
||||||
|
const firstAndSecondContentFlatCmd = [ind, MODE_FLAT, concat([content, whitespace, secondContent])];
|
||||||
|
const firstAndSecondContentFits = fits(firstAndSecondContentFlatCmd, [], rem, true);
|
||||||
|
|
||||||
|
if (firstAndSecondContentFits) {
|
||||||
|
cmds.push(remainingCmd)
|
||||||
|
cmds.push(whitespaceFlatCmd);
|
||||||
|
cmds.push(contentFlatCmd);
|
||||||
|
} else if (contentFits) {
|
||||||
|
cmds.push(remainingCmd)
|
||||||
|
cmds.push(whitespaceBreakCmd);
|
||||||
|
cmds.push(contentFlatCmd);
|
||||||
|
} else {
|
||||||
|
cmds.push(remainingCmd);
|
||||||
|
cmds.push(whitespaceBreakCmd);
|
||||||
|
cmds.push(contentBreakCmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "if-break":
|
case "if-break":
|
||||||
if (mode === MODE_BREAK) {
|
if (mode === MODE_BREAK) {
|
||||||
if (doc.breakContents) {
|
if (doc.breakContents) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldRecurse) {
|
if (shouldRecurse) {
|
||||||
if (doc.type === "concat") {
|
if (doc.type === "concat" || doc.type === "fill") {
|
||||||
for (var i = 0; i < doc.parts.length; i++) {
|
for (var i = 0; i < doc.parts.length; i++) {
|
||||||
traverseDocRec(doc.parts[i]);
|
traverseDocRec(doc.parts[i]);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) {
|
||||||
function mapDoc(doc, func) {
|
function mapDoc(doc, func) {
|
||||||
doc = func(doc);
|
doc = func(doc);
|
||||||
|
|
||||||
if (doc.type === "concat") {
|
if (doc.type === "concat" || doc.type === "fill") {
|
||||||
return Object.assign({}, doc, {
|
return Object.assign({}, doc, {
|
||||||
parts: doc.parts.map(d => mapDoc(d, func))
|
parts: doc.parts.map(d => mapDoc(d, func))
|
||||||
});
|
});
|
||||||
|
|
106
src/printer.js
106
src/printer.js
|
@ -17,6 +17,7 @@ var group = docBuilders.group;
|
||||||
var indent = docBuilders.indent;
|
var indent = docBuilders.indent;
|
||||||
var align = docBuilders.align;
|
var align = docBuilders.align;
|
||||||
var conditionalGroup = docBuilders.conditionalGroup;
|
var conditionalGroup = docBuilders.conditionalGroup;
|
||||||
|
var fill = docBuilders.fill;
|
||||||
var ifBreak = docBuilders.ifBreak;
|
var ifBreak = docBuilders.ifBreak;
|
||||||
var breakParent = docBuilders.breakParent;
|
var breakParent = docBuilders.breakParent;
|
||||||
var lineSuffixBoundary = docBuilders.lineSuffixBoundary;
|
var lineSuffixBoundary = docBuilders.lineSuffixBoundary;
|
||||||
|
@ -3455,8 +3456,8 @@ function printJSXChildren(path, options, print, jsxWhitespace) {
|
||||||
|
|
||||||
if (/\S/.test(value)) {
|
if (/\S/.test(value)) {
|
||||||
// treat each line of text as its own entity
|
// treat each line of text as its own entity
|
||||||
value.split(/(\r?\n\s*)/).forEach(line => {
|
value.split(/(\r?\n\s*)/).forEach(textLine => {
|
||||||
const newlines = line.match(/\n/g);
|
const newlines = textLine.match(/\n/g);
|
||||||
if (newlines) {
|
if (newlines) {
|
||||||
children.push(hardline);
|
children.push(hardline);
|
||||||
|
|
||||||
|
@ -3467,27 +3468,38 @@ function printJSXChildren(path, options, print, jsxWhitespace) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const beginSpace = /^\s+/.test(line);
|
if (textLine.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const beginSpace = /^\s+/.test(textLine);
|
||||||
if (beginSpace) {
|
if (beginSpace) {
|
||||||
children.push(jsxWhitespace);
|
children.push(jsxWhitespace);
|
||||||
|
} else {
|
||||||
children.push(softline);
|
children.push(softline);
|
||||||
}
|
}
|
||||||
|
|
||||||
const stripped = line.replace(/^\s+|\s+$/g, "");
|
const stripped = textLine.replace(/^\s+|\s+$/g, "");
|
||||||
if (stripped) {
|
if (stripped) {
|
||||||
children.push(stripped);
|
|
||||||
|
// Split text into words separated by "line"s.
|
||||||
|
stripped.split(/(\s+)/).forEach(word => {
|
||||||
|
const space = /\s+/.test(word);
|
||||||
|
if (space) {
|
||||||
|
children.push(line);
|
||||||
|
} else {
|
||||||
|
children.push(word);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const endSpace = /\s+$/.test(line);
|
const endSpace = /\s+$/.test(textLine);
|
||||||
if (endSpace) {
|
if (endSpace) {
|
||||||
children.push(softline);
|
|
||||||
children.push(jsxWhitespace);
|
children.push(jsxWhitespace);
|
||||||
|
} else {
|
||||||
|
children.push(softline);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isLineNext(util.getLast(children))) {
|
|
||||||
children.push(softline);
|
|
||||||
}
|
|
||||||
} else if (/\n/.test(value)) {
|
} else if (/\n/.test(value)) {
|
||||||
children.push(hardline);
|
children.push(hardline);
|
||||||
|
|
||||||
|
@ -3500,15 +3512,22 @@ function printJSXChildren(path, options, print, jsxWhitespace) {
|
||||||
// eg; one or more spaces separating two elements
|
// eg; one or more spaces separating two elements
|
||||||
for (let i = 0; i < value.length; ++i) {
|
for (let i = 0; i < value.length; ++i) {
|
||||||
children.push(jsxWhitespace);
|
children.push(jsxWhitespace);
|
||||||
|
// Because fill expects alternating content and whitespace parts
|
||||||
|
// we need to include an empty content part between each JSX
|
||||||
|
// whitespace.
|
||||||
|
if (i + 1 < value.length) {
|
||||||
|
children.push('');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
children.push(softline);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
children.push(print(childPath));
|
children.push(print(childPath));
|
||||||
|
|
||||||
// add a line unless it's followed by a JSX newline
|
// add a softline where we have two adjacent elements that are not
|
||||||
|
// literals
|
||||||
let next = n.children[i + 1];
|
let next = n.children[i + 1];
|
||||||
if (!(next && /^\s*\n/.test(next.value))) {
|
const followedByJSXElement = next && !namedTypes.Literal.check(next);
|
||||||
|
if (followedByJSXElement) {
|
||||||
children.push(softline);
|
children.push(softline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3565,9 +3584,9 @@ function printJSXElement(path, options, print) {
|
||||||
// Record any breaks. Should never go from true to false, only false to true.
|
// Record any breaks. Should never go from true to false, only false to true.
|
||||||
let forcedBreak = willBreak(openingLines);
|
let forcedBreak = willBreak(openingLines);
|
||||||
|
|
||||||
const jsxWhitespace = options.singleQuote
|
const rawJsxWhitespace = options.singleQuote ? "{' '}" : '{" "}';
|
||||||
? ifBreak("{' '}", " ")
|
const jsxWhitespace = ifBreak(concat([softline, rawJsxWhitespace, softline]), " ")
|
||||||
: ifBreak('{" "}', " ");
|
|
||||||
const children = printJSXChildren(path, options, print, jsxWhitespace);
|
const children = printJSXChildren(path, options, print, jsxWhitespace);
|
||||||
|
|
||||||
// Trim trailing lines, recording if there was a hardline
|
// Trim trailing lines, recording if there was a hardline
|
||||||
|
@ -3598,56 +3617,37 @@ function printJSXElement(path, options, print) {
|
||||||
children.unshift(hardline);
|
children.unshift(hardline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group by line, recording if there was a hardline.
|
// Tweak how we format children if outputting this element over multiple lines.
|
||||||
let groups = [[]]; // Initialize the first line's group
|
// Also detect whether we will force this element to output over multiple lines.
|
||||||
|
let multilineChildren = [];
|
||||||
children.forEach((child, i) => {
|
children.forEach((child, i) => {
|
||||||
// leading and trailing JSX whitespace don't go into a group
|
|
||||||
|
// Ensure that we display leading, trailing, and solitary whitespace as
|
||||||
|
// `{" "}` when outputting this element over multiple lines.
|
||||||
if (child === jsxWhitespace) {
|
if (child === jsxWhitespace) {
|
||||||
if (i === 0) {
|
if (children.length === 1) {
|
||||||
groups.unshift(child);
|
multilineChildren.push(rawJsxWhitespace);
|
||||||
|
return;
|
||||||
|
} else if (i === 0) {
|
||||||
|
multilineChildren.push(concat([rawJsxWhitespace, hardline]));
|
||||||
return;
|
return;
|
||||||
} else if (i === children.length - 1) {
|
} else if (i === children.length - 1) {
|
||||||
groups.push(child);
|
multilineChildren.push(concat([hardline, rawJsxWhitespace]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let prev = children[i - 1];
|
multilineChildren.push(child);
|
||||||
if (prev && willBreak(prev)) {
|
|
||||||
|
if (willBreak(child)) {
|
||||||
forcedBreak = true;
|
forcedBreak = true;
|
||||||
|
|
||||||
// On a new line, so create a new group and put this element in it.
|
|
||||||
groups.push([child]);
|
|
||||||
} else {
|
|
||||||
// Not on a newline, so add this element to the current group.
|
|
||||||
util.getLast(groups).push(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we record hardline of last element.
|
|
||||||
if (!forcedBreak && i === children.length - 1) {
|
|
||||||
if (willBreak(child)) forcedBreak = true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const childrenGroupedByLine = [
|
|
||||||
hardline,
|
|
||||||
// Conditional groups suppress break propagation; we want to output
|
|
||||||
// hard lines without breaking up the entire jsx element.
|
|
||||||
// Note that leading and trailing JSX Whitespace don't go into a group.
|
|
||||||
concat(
|
|
||||||
groups.map(
|
|
||||||
contents =>
|
|
||||||
(Array.isArray(contents)
|
|
||||||
? conditionalGroup([concat(contents)])
|
|
||||||
: contents)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
const multiLineElem = group(
|
const multiLineElem = group(
|
||||||
concat([
|
concat([
|
||||||
openingLines,
|
openingLines,
|
||||||
indent(group(concat(childrenGroupedByLine), { shouldBreak: true })),
|
indent(concat([hardline, fill(multilineChildren)])),
|
||||||
hardline,
|
hardline,
|
||||||
closingLines
|
closingLines
|
||||||
])
|
])
|
||||||
|
@ -3658,7 +3658,7 @@ function printJSXElement(path, options, print) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return conditionalGroup([
|
return conditionalGroup([
|
||||||
group(concat([openingLines, concat(children), closingLines])),
|
group(concat([openingLines, fill(children), closingLines])),
|
||||||
multiLineElem
|
multiLineElem
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,8 @@ var App = require("App.react");
|
||||||
|
|
||||||
var app = (
|
var app = (
|
||||||
<App y={42}>
|
<App y={42}>
|
||||||
{" "}// error, y: number but foo expects string in App.react
|
{" "}
|
||||||
|
// error, y: number but foo expects string in App.react
|
||||||
Some text.
|
Some text.
|
||||||
</App>
|
</App>
|
||||||
);
|
);
|
||||||
|
|
|
@ -146,13 +146,15 @@ nest_plz = (
|
||||||
|
|
||||||
regression_not_transformed_1 = (
|
regression_not_transformed_1 = (
|
||||||
<span>
|
<span>
|
||||||
{" "}<Icon icon="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" />
|
{" "}
|
||||||
|
<Icon icon="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
regression_not_transformed_2 = (
|
regression_not_transformed_2 = (
|
||||||
<span>
|
<span>
|
||||||
<Icon icon="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" />{" "}
|
<Icon icon="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" />
|
||||||
|
{" "}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -178,22 +180,15 @@ similar_3 = (
|
||||||
|
|
||||||
not_broken_end = (
|
not_broken_end = (
|
||||||
<div>
|
<div>
|
||||||
long text long text long text long text long text long text long text long text
|
long text long text long text long text long text long text long text long
|
||||||
{" "}
|
text <link>url</link> long text long text
|
||||||
<link>url</link>
|
|
||||||
{" "}
|
|
||||||
long text long text
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
not_broken_begin = (
|
not_broken_begin = (
|
||||||
<div>
|
<div>
|
||||||
<br />
|
<br /> long text long text long text long text long text long text long text
|
||||||
{" "}
|
long text<link>url</link> long text long text
|
||||||
long text long text long text long text long text long text long text long text
|
|
||||||
<link>url</link>
|
|
||||||
{" "}
|
|
||||||
long text long text
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`test.js 1`] = `
|
||||||
|
// Wrapping text
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
Some text that would need to wrap on to a new line in order to display correctly and nicely
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<first>f</first> <first>f</first> <first>f</first> <first>f</first> <first>f</first> <first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<first>f</first><first>f</first><first>f</first><first>f</first><first>f</first><first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<a /><b /><c />
|
||||||
|
<first>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</first> <first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<sadashdkjahsdkjhaskjdhaksjdhkashdkashdkasjhdkajshdkashdkashd /> <first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
before<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at mollis lorem.</div>after
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}{stuff}{stuff}after{stuff}after
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after {stuff} {stuff} {stuff} after {stuff} after
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
Please state your <b>name</b> and <b>occupation</b> for the board of <b>school</b> directors.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
function DiffOverview(props) {
|
||||||
|
const { source, target, since } = props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="alert alert-info">
|
||||||
|
<p>
|
||||||
|
This diff overview is computed against the current list of records in
|
||||||
|
this collection and the list it contained on <b>{humanDate(since)}</b>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Note:</b> <code>last_modified</code> and <code>schema</code> record metadata
|
||||||
|
are omitted for easier review.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Diff source={source} target={target} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = <font size={-3}><i>Starting at minute {graphActivity.startTime}, running for {graphActivity.length} to minute {graphActivity.startTime + graphActivity.length}</i></font>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
First second third
|
||||||
|
<div attr="a very long string attribute that will overflow because it is very long">Something</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
First
|
||||||
|
</div>
|
||||||
|
Second
|
||||||
|
<div>
|
||||||
|
Third
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
First <div>
|
||||||
|
Second
|
||||||
|
</div> Third
|
||||||
|
</div>
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Wrapping text
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
Some text that would need to wrap on to a new line in order to display
|
||||||
|
correctly and nicely
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
<first>f</first> <first>f</first> <first>f</first> <first>f</first>
|
||||||
|
{" "}
|
||||||
|
<first>f</first> <first>f</first>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
<first>f</first><first>f</first><first>f</first><first>f</first>
|
||||||
|
<first>f</first><first>f</first>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
<a /><b /><c />
|
||||||
|
<first>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</first>
|
||||||
|
{" "}
|
||||||
|
<first>f</first>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
<sadashdkjahsdkjhaskjdhaksjdhkashdkashdkasjhdkajshdkashdkashd />
|
||||||
|
{" "}
|
||||||
|
<first>f</first>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
before
|
||||||
|
<div>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at
|
||||||
|
mollis lorem.
|
||||||
|
</div>
|
||||||
|
after
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}
|
||||||
|
{stuff}{stuff}after{stuff}after
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after
|
||||||
|
{" "}
|
||||||
|
{stuff} {stuff} {stuff} after {stuff} after
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
Please state your <b>name</b> and <b>occupation</b> for the board of
|
||||||
|
{" "}
|
||||||
|
<b>school</b> directors.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
function DiffOverview(props) {
|
||||||
|
const { source, target, since } = props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="alert alert-info">
|
||||||
|
<p>
|
||||||
|
This diff overview is computed against the current list of records in
|
||||||
|
this collection and the list it contained on <b>{humanDate(since)}</b>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Note:</b> <code>last_modified</code> and <code>schema</code> record
|
||||||
|
metadata
|
||||||
|
are omitted for easier review.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Diff source={source} target={target} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<font size={-3}>
|
||||||
|
<i>
|
||||||
|
Starting at minute {graphActivity.startTime}, running for
|
||||||
|
{" "}
|
||||||
|
{graphActivity.length} to minute
|
||||||
|
{" "}
|
||||||
|
{graphActivity.startTime + graphActivity.length}
|
||||||
|
</i>
|
||||||
|
</font>
|
||||||
|
);
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
First second third
|
||||||
|
<div attr="a very long string attribute that will overflow because it is very long">
|
||||||
|
Something
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
First
|
||||||
|
</div>
|
||||||
|
Second
|
||||||
|
<div>
|
||||||
|
Third
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
x = (
|
||||||
|
<div>
|
||||||
|
First
|
||||||
|
{" "}
|
||||||
|
<div>
|
||||||
|
Second
|
||||||
|
</div>
|
||||||
|
{" "}
|
||||||
|
Third
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
`;
|
|
@ -0,0 +1 @@
|
||||||
|
run_spec(__dirname, null, ["typescript"]);
|
|
@ -0,0 +1,95 @@
|
||||||
|
// Wrapping text
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
Some text that would need to wrap on to a new line in order to display correctly and nicely
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<first>f</first> <first>f</first> <first>f</first> <first>f</first> <first>f</first> <first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<first>f</first><first>f</first><first>f</first><first>f</first><first>f</first><first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<a /><b /><c />
|
||||||
|
<first>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</first> <first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Wrapping tags
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<sadashdkjahsdkjhaskjdhaksjdhkashdkashdkasjhdkajshdkashdkashd /> <first>f</first>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
before<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at mollis lorem.</div>after
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}{stuff}{stuff}after{stuff}after
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after {stuff} {stuff} {stuff} after {stuff} after
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
Please state your <b>name</b> and <b>occupation</b> for the board of <b>school</b> directors.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
function DiffOverview(props) {
|
||||||
|
const { source, target, since } = props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="alert alert-info">
|
||||||
|
<p>
|
||||||
|
This diff overview is computed against the current list of records in
|
||||||
|
this collection and the list it contained on <b>{humanDate(since)}</b>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Note:</b> <code>last_modified</code> and <code>schema</code> record metadata
|
||||||
|
are omitted for easier review.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Diff source={source} target={target} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = <font size={-3}><i>Starting at minute {graphActivity.startTime}, running for {graphActivity.length} to minute {graphActivity.startTime + graphActivity.length}</i></font>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
First second third
|
||||||
|
<div attr="a very long string attribute that will overflow because it is very long">Something</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
First
|
||||||
|
</div>
|
||||||
|
Second
|
||||||
|
<div>
|
||||||
|
Third
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
x =
|
||||||
|
<div>
|
||||||
|
First <div>
|
||||||
|
Second
|
||||||
|
</div> Third
|
||||||
|
</div>
|
|
@ -18,6 +18,7 @@ exports[`nbsp.js 1`] = `
|
||||||
many_nbsp = <div> </div>
|
many_nbsp = <div> </div>
|
||||||
single_nbsp = <div> </div>
|
single_nbsp = <div> </div>
|
||||||
many_raw_nbsp = <div> </div>
|
many_raw_nbsp = <div> </div>
|
||||||
|
many_raw_spaces = <div> </div>
|
||||||
|
|
||||||
|
|
||||||
amp = <span>foo & bar</span>
|
amp = <span>foo & bar</span>
|
||||||
|
@ -26,6 +27,7 @@ raw_amp = <span>foo & bar</span>
|
||||||
many_nbsp = <div> </div>;
|
many_nbsp = <div> </div>;
|
||||||
single_nbsp = <div> </div>;
|
single_nbsp = <div> </div>;
|
||||||
many_raw_nbsp = <div> </div>;
|
many_raw_nbsp = <div> </div>;
|
||||||
|
many_raw_spaces = <div> </div>;
|
||||||
|
|
||||||
amp = <span>foo & bar</span>;
|
amp = <span>foo & bar</span>;
|
||||||
raw_amp = <span>foo & bar</span>;
|
raw_amp = <span>foo & bar</span>;
|
||||||
|
@ -36,6 +38,7 @@ exports[`nbsp.js 2`] = `
|
||||||
many_nbsp = <div> </div>
|
many_nbsp = <div> </div>
|
||||||
single_nbsp = <div> </div>
|
single_nbsp = <div> </div>
|
||||||
many_raw_nbsp = <div> </div>
|
many_raw_nbsp = <div> </div>
|
||||||
|
many_raw_spaces = <div> </div>
|
||||||
|
|
||||||
|
|
||||||
amp = <span>foo & bar</span>
|
amp = <span>foo & bar</span>
|
||||||
|
@ -44,6 +47,7 @@ raw_amp = <span>foo & bar</span>
|
||||||
many_nbsp = <div> </div>;
|
many_nbsp = <div> </div>;
|
||||||
single_nbsp = <div> </div>;
|
single_nbsp = <div> </div>;
|
||||||
many_raw_nbsp = <div> </div>;
|
many_raw_nbsp = <div> </div>;
|
||||||
|
many_raw_spaces = <div> </div>;
|
||||||
|
|
||||||
amp = <span>foo & bar</span>;
|
amp = <span>foo & bar</span>;
|
||||||
raw_amp = <span>foo & bar</span>;
|
raw_amp = <span>foo & bar</span>;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
many_nbsp = <div> </div>
|
many_nbsp = <div> </div>
|
||||||
single_nbsp = <div> </div>
|
single_nbsp = <div> </div>
|
||||||
many_raw_nbsp = <div> </div>
|
many_raw_nbsp = <div> </div>
|
||||||
|
many_raw_spaces = <div> </div>
|
||||||
|
|
||||||
|
|
||||||
amp = <span>foo & bar</span>
|
amp = <span>foo & bar</span>
|
||||||
|
|
Loading…
Reference in New Issue