tosijs-ui 1.6.7 → 1.6.10

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.
Files changed (38) hide show
  1. package/README.md +1 -1
  2. package/dist/code-editor.d.ts +6 -0
  3. package/dist/code-editor.js +43 -0
  4. package/dist/diff.d.ts +61 -0
  5. package/dist/diff.js +132 -0
  6. package/dist/doc-browser.js +347 -29
  7. package/dist/doc-system/doc-system-styles.js +4 -1
  8. package/dist/doc-system/doc-system.js +8 -0
  9. package/dist/doc-system/routing.d.ts +8 -0
  10. package/dist/doc-system/routing.js +13 -0
  11. package/dist/doc-system/site/dev-server.js +56 -0
  12. package/dist/doc-system/site/generate-site.js +14 -2
  13. package/dist/doc-system/site/orchestrator.js +3 -1
  14. package/dist/doc-system/site/site-config.d.ts +7 -0
  15. package/dist/iife.js +87 -78
  16. package/dist/iife.js.map +19 -16
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +1 -0
  19. package/dist/live-example/code-transform.d.ts +44 -7
  20. package/dist/live-example/code-transform.js +0 -0
  21. package/dist/live-example/component.d.ts +53 -2
  22. package/dist/live-example/component.js +477 -27
  23. package/dist/live-example/example-store.d.ts +12 -0
  24. package/dist/live-example/example-store.js +47 -0
  25. package/dist/live-example/insert-examples.d.ts +1 -1
  26. package/dist/live-example/insert-examples.js +24 -2
  27. package/dist/live-example/save-to-source.d.ts +23 -0
  28. package/dist/live-example/save-to-source.js +104 -0
  29. package/dist/live-example/styles.d.ts +22 -0
  30. package/dist/live-example/styles.js +26 -0
  31. package/dist/live-example/test-harness.js +2 -2
  32. package/dist/live-example/types.d.ts +2 -1
  33. package/dist/menu.js +14 -4
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/dist/version.d.ts +1 -1
  36. package/dist/version.js +1 -1
  37. package/llms.txt +3 -1
  38. package/package.json +6 -6
package/README.md CHANGED
@@ -67,7 +67,7 @@ npm add tosijs-ui
67
67
  Then import the component `elementCreator` and create elements. A `tosijs`
68
68
  `elementCreator` is syntax sugar around `document.createElement()`.
69
69
 
70
- ```ts
70
+ ```typescript
71
71
  import { tosiTable } from 'tosijs-ui'
72
72
 
73
73
  document.body.append(tosiTable())
@@ -4,6 +4,12 @@ export declare class CodeEditor extends WebComponent {
4
4
  private source;
5
5
  get value(): string;
6
6
  set value(text: string);
7
+ private _original;
8
+ get original(): string;
9
+ set original(text: string);
10
+ private diffOverlay;
11
+ get showingDiff(): boolean;
12
+ showDiff(on: boolean): void;
7
13
  static initAttributes: {
8
14
  mode: string;
9
15
  theme: string;
@@ -23,6 +23,7 @@ and an `ace` property that returns the `ace` module, giving you complete access
23
23
  /*{ "parent": "Components" }*/
24
24
  import { Component as WebComponent } from 'tosijs';
25
25
  import { scriptTag } from './via-tag';
26
+ import { tosiDiff } from './diff';
26
27
  const ACE_BASE_URL = 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.23.2/';
27
28
  const DEFAULT_THEME = 'ace/theme/tomorrow';
28
29
  const getAce = async () => {
@@ -37,6 +38,10 @@ const makeCodeEditor = async (codeElement, mode = 'html', options = {}, theme =
37
38
  tabSize: 2,
38
39
  useSoftTabs: true,
39
40
  useWorker: false,
41
+ // Wrap wide lines instead of scrolling horizontally; indentedSoftWrap keeps
42
+ // wrapped continuations aligned under the line's indent.
43
+ wrap: true,
44
+ indentedSoftWrap: true,
40
45
  ...options,
41
46
  });
42
47
  editor.setTheme(theme);
@@ -58,6 +63,44 @@ export class CodeEditor extends WebComponent {
58
63
  this.editor.session.getUndoManager().reset();
59
64
  }
60
65
  }
66
+ // Baseline for `showDiff()` — the version to diff the current `value` against.
67
+ // Defaults to the current value (no diff) until a caller sets it.
68
+ _original;
69
+ get original() {
70
+ return this._original ?? this.value;
71
+ }
72
+ set original(text) {
73
+ this._original = text;
74
+ }
75
+ // Diff overlay — deliberately built only on the editor's public surface
76
+ // (`value` + `original`) and the tosi-diff component, never the underlying
77
+ // editor's API, so it survives a future Ace → CodeMirror swap untouched.
78
+ diffOverlay;
79
+ get showingDiff() {
80
+ return this.diffOverlay !== undefined && !this.diffOverlay.hidden;
81
+ }
82
+ showDiff(on) {
83
+ if (on) {
84
+ if (this.diffOverlay === undefined) {
85
+ this.diffOverlay = tosiDiff({
86
+ style: {
87
+ position: 'absolute',
88
+ inset: '0',
89
+ zIndex: '5',
90
+ overflow: 'auto',
91
+ background: 'var(--tosi-diff-bg, var(--background, #fff))',
92
+ },
93
+ });
94
+ this.append(this.diffOverlay);
95
+ }
96
+ this.diffOverlay.original = this.original;
97
+ this.diffOverlay.modified = this.value;
98
+ this.diffOverlay.hidden = false;
99
+ }
100
+ else if (this.diffOverlay !== undefined) {
101
+ this.diffOverlay.hidden = true;
102
+ }
103
+ }
61
104
  static initAttributes = {
62
105
  mode: 'javascript',
63
106
  theme: DEFAULT_THEME,
package/dist/diff.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { Component, ElementCreator, PartsMap } from 'tosijs';
2
+ export type DiffOp = 'context' | 'add' | 'remove';
3
+ export interface DiffLine {
4
+ op: DiffOp;
5
+ text: string;
6
+ }
7
+ /**
8
+ * Line-level diff of two strings via longest-common-subsequence, returning each
9
+ * line tagged `context` (unchanged), `remove` (only in `before`), or `add` (only
10
+ * in `after`), in display order.
11
+ */
12
+ export declare function diffLines(before: string, after: string): DiffLine[];
13
+ interface DiffParts extends PartsMap {
14
+ body: HTMLElement;
15
+ }
16
+ export declare class TosiDiff extends Component<DiffParts> {
17
+ static preferredTagName: string;
18
+ static initAttributes: {
19
+ original: string;
20
+ modified: string;
21
+ };
22
+ static shadowStyleSpec: {
23
+ ':host': {
24
+ display: string;
25
+ overflow: string;
26
+ font: string;
27
+ background: string;
28
+ color: string;
29
+ };
30
+ ':host([hidden])': {
31
+ display: string;
32
+ };
33
+ '.diff-line': {
34
+ display: string;
35
+ gridTemplateColumns: string;
36
+ whiteSpace: string;
37
+ wordBreak: string;
38
+ };
39
+ '.diff-line .marker': {
40
+ textAlign: string;
41
+ userSelect: string;
42
+ opacity: string;
43
+ };
44
+ '.diff-add': {
45
+ background: string;
46
+ };
47
+ '.diff-add .marker': {
48
+ color: string;
49
+ };
50
+ '.diff-remove': {
51
+ background: string;
52
+ };
53
+ '.diff-remove .marker': {
54
+ color: string;
55
+ };
56
+ };
57
+ content: () => HTMLDivElement[];
58
+ render(): void;
59
+ }
60
+ export declare const tosiDiff: ElementCreator<TosiDiff>;
61
+ export {};
package/dist/diff.js ADDED
@@ -0,0 +1,132 @@
1
+ /*#
2
+ # diff
3
+
4
+ `<tosi-diff>` renders a unified, line-by-line diff between two strings — the kind
5
+ of view you'd see in a code review, with removed lines marked `-` and added
6
+ lines marked `+`.
7
+
8
+ Set its `original` and `modified` properties (or attributes) to the two versions
9
+ of the text; it recomputes and re-renders. (They're named `original`/`modified`
10
+ rather than `before`/`after` to avoid the native `Element.before()`/`after()`
11
+ methods.)
12
+
13
+ ```js
14
+ const { tosiDiff } = tosijsui
15
+
16
+ preview.append(
17
+ tosiDiff({
18
+ original: 'one\ntwo\nthree\nfour',
19
+ modified: 'one\nTWO\nthree\nfour\nfive',
20
+ style: { width: '100%', height: '100%' },
21
+ })
22
+ )
23
+ ```
24
+
25
+ The diff is computed with a longest-common-subsequence pass over the lines, so
26
+ unchanged lines are shown as context and only genuine insertions/deletions are
27
+ highlighted. The pure `diffLines(before, after)` function is exported too, if you
28
+ just want the data.
29
+ */
30
+ /*{ "parent": "Components" }*/
31
+ import { Component, elements } from 'tosijs';
32
+ const { div, span } = elements;
33
+ /**
34
+ * Line-level diff of two strings via longest-common-subsequence, returning each
35
+ * line tagged `context` (unchanged), `remove` (only in `before`), or `add` (only
36
+ * in `after`), in display order.
37
+ */
38
+ export function diffLines(before, after) {
39
+ const a = before.split('\n');
40
+ const b = after.split('\n');
41
+ const m = a.length;
42
+ const n = b.length;
43
+ // lcs[i][j] = length of the LCS of a[i:] and b[j:]
44
+ const lcs = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
45
+ for (let i = m - 1; i >= 0; i -= 1) {
46
+ for (let j = n - 1; j >= 0; j -= 1) {
47
+ lcs[i][j] =
48
+ a[i] === b[j]
49
+ ? lcs[i + 1][j + 1] + 1
50
+ : Math.max(lcs[i + 1][j], lcs[i][j + 1]);
51
+ }
52
+ }
53
+ const out = [];
54
+ let i = 0;
55
+ let j = 0;
56
+ while (i < m && j < n) {
57
+ if (a[i] === b[j]) {
58
+ out.push({ op: 'context', text: a[i] });
59
+ i += 1;
60
+ j += 1;
61
+ }
62
+ else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
63
+ out.push({ op: 'remove', text: a[i] });
64
+ i += 1;
65
+ }
66
+ else {
67
+ out.push({ op: 'add', text: b[j] });
68
+ j += 1;
69
+ }
70
+ }
71
+ while (i < m) {
72
+ out.push({ op: 'remove', text: a[i] });
73
+ i += 1;
74
+ }
75
+ while (j < n) {
76
+ out.push({ op: 'add', text: b[j] });
77
+ j += 1;
78
+ }
79
+ return out;
80
+ }
81
+ const MARKER = { context: ' ', add: '+', remove: '-' };
82
+ export class TosiDiff extends Component {
83
+ static preferredTagName = 'tosi-diff';
84
+ // `before`/`after` would collide with the native Element.before()/after()
85
+ // methods, so the component props are `original`/`modified`.
86
+ static initAttributes = {
87
+ original: '',
88
+ modified: '',
89
+ };
90
+ static shadowStyleSpec = {
91
+ ':host': {
92
+ display: 'block',
93
+ overflow: 'auto',
94
+ font: 'var(--tosi-code-font, 12px/1.5 monospace)',
95
+ background: 'var(--tosi-diff-bg, #fff)',
96
+ color: 'var(--tosi-diff-color, #222)',
97
+ },
98
+ // `:host{display:block}` would otherwise beat the UA `[hidden]` rule, so the
99
+ // element couldn't be hidden via the attribute — restore that.
100
+ ':host([hidden])': {
101
+ display: 'none',
102
+ },
103
+ '.diff-line': {
104
+ display: 'grid',
105
+ gridTemplateColumns: '1.5em 1fr',
106
+ whiteSpace: 'pre-wrap',
107
+ wordBreak: 'break-word',
108
+ },
109
+ '.diff-line .marker': {
110
+ textAlign: 'center',
111
+ userSelect: 'none',
112
+ opacity: '0.5',
113
+ },
114
+ '.diff-add': {
115
+ background: 'var(--tosi-diff-add-bg, #e6ffed)',
116
+ },
117
+ '.diff-add .marker': { color: 'var(--tosi-diff-add-color, #22863a)' },
118
+ '.diff-remove': {
119
+ background: 'var(--tosi-diff-remove-bg, #ffeef0)',
120
+ },
121
+ '.diff-remove .marker': { color: 'var(--tosi-diff-remove-color, #cb2431)' },
122
+ };
123
+ content = () => [div({ part: 'body' })];
124
+ render() {
125
+ super.render();
126
+ const lines = diffLines(this.original, this.modified);
127
+ this.parts.body.replaceChildren(...lines.map((line) => div({ class: `diff-line diff-${line.op}` }, span({ class: 'marker' }, MARKER[line.op]),
128
+ // Non-breaking fallback so empty lines keep their row height.
129
+ span({ class: 'text' }, line.text === '' ? ' ' : line.text))));
130
+ }
131
+ }
132
+ export const tosiDiff = TosiDiff.elementCreator();