@davidsouther/jiffies 1.0.0 → 1.1.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.
Files changed (172) hide show
  1. package/build/assert.d.ts +23 -23
  2. package/build/assert.js +33 -33
  3. package/build/case.d.ts +1 -1
  4. package/build/case.js +5 -5
  5. package/build/components/button_bar.d.ts +8 -8
  6. package/build/components/button_bar.js +27 -27
  7. package/build/components/inline_edit.d.ts +12 -12
  8. package/build/components/inline_edit.js +48 -48
  9. package/build/components/logger.d.ts +6 -7
  10. package/build/components/logger.js +22 -22
  11. package/build/components/select.d.ts +13 -10
  12. package/build/components/select.js +3 -3
  13. package/build/components/test.d.ts +1 -1
  14. package/build/components/test.js +2 -2
  15. package/build/components/virtual_scroll.d.ts +40 -41
  16. package/build/components/virtual_scroll.js +94 -94
  17. package/build/components/virtual_scroll.test.d.ts +1 -1
  18. package/build/components/virtual_scroll.test.js +21 -21
  19. package/build/context.d.ts +15 -15
  20. package/build/context.js +43 -43
  21. package/build/context.test.d.ts +1 -1
  22. package/build/context.test.js +46 -46
  23. package/build/debounce.d.ts +1 -1
  24. package/build/debounce.js +7 -7
  25. package/build/display.d.ts +5 -5
  26. package/build/display.js +11 -11
  27. package/build/dom/css/border.d.ts +11 -11
  28. package/build/dom/css/border.js +27 -27
  29. package/build/dom/css/constants.d.ts +31 -31
  30. package/build/dom/css/constants.js +28 -28
  31. package/build/dom/css/core.d.ts +5 -5
  32. package/build/dom/css/core.js +24 -24
  33. package/build/dom/css/fstyle.d.ts +5 -5
  34. package/build/dom/css/fstyle.js +32 -32
  35. package/build/dom/css/sizing.d.ts +5 -5
  36. package/build/dom/css/sizing.js +10 -10
  37. package/build/dom/dom.d.ts +26 -27
  38. package/build/dom/dom.js +95 -95
  39. package/build/dom/fc.d.ts +14 -14
  40. package/build/dom/fc.js +36 -35
  41. package/build/dom/fc.test.d.ts +1 -1
  42. package/build/dom/fc.test.js +21 -21
  43. package/build/dom/form/form.app.d.ts +1 -1
  44. package/build/dom/form/form.app.js +23 -23
  45. package/build/dom/form/form.d.ts +26 -26
  46. package/build/dom/form/form.js +34 -34
  47. package/build/dom/form/form.test.js +1 -1
  48. package/build/dom/html.d.ts +113 -117
  49. package/build/dom/html.js +114 -114
  50. package/build/dom/html.test.d.ts +1 -1
  51. package/build/dom/html.test.js +58 -58
  52. package/build/dom/provide.d.ts +3 -3
  53. package/build/dom/provide.js +7 -7
  54. package/build/dom/router/link.d.ts +6 -6
  55. package/build/dom/router/link.js +3 -3
  56. package/build/dom/router/router.d.ts +12 -12
  57. package/build/dom/router/router.js +49 -49
  58. package/build/dom/svg.d.ts +64 -64
  59. package/build/dom/svg.js +65 -65
  60. package/build/dom/test.d.ts +1 -1
  61. package/build/dom/test.js +2 -2
  62. package/build/dom/types/css.d.ts +6612 -6612
  63. package/build/dom/types/css.js +23 -23
  64. package/build/dom/types/dom.js +1 -1
  65. package/build/dom/types/html.d.ts +616 -616
  66. package/build/dom/types/html.js +1 -1
  67. package/build/dom/xml.d.ts +1 -1
  68. package/build/dom/xml.js +4 -5
  69. package/build/equal.d.ts +5 -5
  70. package/build/equal.js +37 -37
  71. package/build/equal.test.d.ts +1 -1
  72. package/build/equal.test.js +20 -20
  73. package/build/flags.d.ts +7 -7
  74. package/build/flags.js +48 -48
  75. package/build/flags.test.d.ts +1 -1
  76. package/build/flags.test.js +35 -35
  77. package/build/fs.d.ts +48 -48
  78. package/build/fs.js +144 -144
  79. package/build/fs.test.d.ts +1 -1
  80. package/build/fs.test.js +43 -43
  81. package/build/generator.d.ts +1 -1
  82. package/build/generator.js +10 -10
  83. package/build/generator.test.d.ts +1 -1
  84. package/build/generator.test.js +24 -24
  85. package/build/is_browser.d.ts +1 -1
  86. package/build/is_browser.js +1 -1
  87. package/build/loader.d.mts +22 -22
  88. package/build/loader.mjs +35 -35
  89. package/build/lock.d.ts +1 -1
  90. package/build/lock.js +23 -23
  91. package/build/lock.test.d.ts +1 -1
  92. package/build/lock.test.js +16 -16
  93. package/build/log.d.ts +26 -26
  94. package/build/log.js +46 -46
  95. package/build/observable/observable.d.ts +83 -0
  96. package/build/observable/observable.js +148 -0
  97. package/build/observable/observable.test.d.ts +1 -0
  98. package/build/observable/observable.test.js +21 -0
  99. package/build/range.d.ts +1 -1
  100. package/build/range.js +7 -7
  101. package/build/result.d.ts +31 -31
  102. package/build/result.js +65 -65
  103. package/build/result.test.d.ts +1 -1
  104. package/build/result.test.js +71 -71
  105. package/build/safe.d.ts +1 -1
  106. package/build/safe.js +10 -10
  107. package/build/scope/describe.d.ts +18 -14
  108. package/build/scope/describe.js +61 -52
  109. package/build/scope/display/console.d.ts +2 -2
  110. package/build/scope/display/console.js +21 -21
  111. package/build/scope/display/dom.d.ts +3 -3
  112. package/build/scope/display/dom.js +26 -26
  113. package/build/scope/display/junit.d.ts +2 -2
  114. package/build/scope/display/junit.js +17 -17
  115. package/build/scope/execute.d.ts +12 -12
  116. package/build/scope/execute.js +85 -85
  117. package/build/scope/expect.d.ts +23 -23
  118. package/build/scope/expect.js +108 -108
  119. package/build/scope/fix.d.ts +4 -4
  120. package/build/scope/fix.js +22 -22
  121. package/build/scope/index.d.ts +3 -3
  122. package/build/scope/index.js +3 -3
  123. package/build/scope/scope.d.ts +17 -17
  124. package/build/scope/scope.js +1 -1
  125. package/build/server/http/apps.d.ts +5 -5
  126. package/build/server/http/apps.js +23 -23
  127. package/build/server/http/css.d.ts +5 -5
  128. package/build/server/http/css.js +50 -47
  129. package/build/server/http/index.d.ts +21 -21
  130. package/build/server/http/index.js +73 -73
  131. package/build/server/http/response.d.ts +4 -4
  132. package/build/server/http/response.js +40 -40
  133. package/build/server/http/sitemap.d.ts +2 -2
  134. package/build/server/http/sitemap.js +42 -42
  135. package/build/server/http/static.d.ts +2 -2
  136. package/build/server/http/static.js +21 -21
  137. package/build/server/http/typescript.d.ts +5 -5
  138. package/build/server/http/typescript.js +40 -40
  139. package/build/server/main.d.ts +2 -2
  140. package/build/server/main.js +9 -9
  141. package/build/test.d.mts +2 -2
  142. package/build/test.mjs +23 -23
  143. package/build/test_all.d.ts +7 -7
  144. package/build/test_all.js +18 -18
  145. package/build/transpile.d.mts +3 -3
  146. package/build/transpile.mjs +18 -18
  147. package/package.json +3 -3
  148. package/src/components/logger.ts +2 -3
  149. package/src/components/virtual_scroll.test.ts +4 -4
  150. package/src/components/virtual_scroll.ts +8 -8
  151. package/src/diff.test.ts +48 -0
  152. package/src/diff.ts +84 -0
  153. package/src/dom/dom.ts +73 -61
  154. package/src/dom/fc.ts +10 -9
  155. package/src/dom/html.test.ts +5 -5
  156. package/src/dom/html.ts +7 -10
  157. package/src/dom/observable.test.ts +43 -0
  158. package/src/dom/observable.ts +11 -0
  159. package/src/dom/router/router.ts +4 -4
  160. package/src/dom/test.ts +5 -1
  161. package/src/dom/xml.ts +1 -2
  162. package/src/index.html +6 -3
  163. package/src/observable/_notes +21 -8
  164. package/src/observable/event.ts +93 -0
  165. package/src/observable/observable.test.ts +73 -0
  166. package/src/observable/observable.ts +403 -0
  167. package/src/scope/describe.ts +14 -1
  168. package/src/scope/display/dom.ts +2 -2
  169. package/src/scope/execute.ts +2 -5
  170. package/src/server/http/css.ts +3 -1
  171. package/src/test_all.ts +10 -8
  172. package/src/observable/observable._js +0 -175
@@ -16,16 +16,16 @@ describe("html", () => {
16
16
  });
17
17
 
18
18
  it("attaches event handlers", () => {
19
- let clicked = false;
19
+ let clicked = 0;
20
20
  const btn = button({
21
21
  events: {
22
22
  click: () => {
23
- clicked = true;
23
+ clicked += 1;
24
24
  },
25
25
  },
26
26
  });
27
27
  btn.dispatchEvent(new Event("click"));
28
- expect(clicked).toBe(true);
28
+ expect(clicked).toBe(1);
29
29
  });
30
30
 
31
31
  it("removes event handlers", () => {
@@ -41,7 +41,7 @@ describe("html", () => {
41
41
 
42
42
  expect(clicked).toBe(1);
43
43
 
44
- btn.update({ events: { click: undefined } });
44
+ btn.update({ events: { click: null } });
45
45
  btn.dispatchEvent(new Event("click"));
46
46
  expect(clicked).toBe(1);
47
47
  });
@@ -49,7 +49,7 @@ describe("html", () => {
49
49
  it("sets style properties", () => {
50
50
  const btn = button({
51
51
  style: { flexDirection: "column" },
52
- }) as unknown as HTMLButtonElement;
52
+ });
53
53
 
54
54
  expect(btn.style.flexDirection).toBe("column");
55
55
  });
package/src/dom/html.ts CHANGED
@@ -1,19 +1,16 @@
1
- import { DenormAttrs, DenormChildren, up, Updatable } from "./dom.js";
2
- import { Properties } from "./types/css.js";
3
-
4
- export type UHTMLElement<E extends HTMLElement = HTMLElement> = Updatable<
5
- Omit<E, "style">
6
- > & { style: Properties };
1
+ import { DenormAttrs, DenormChildren, up } from "./dom.js";
7
2
 
8
3
  const makeHTMLElement =
9
4
  <K extends keyof HTMLElementTagNameMap>(name: K) =>
10
5
  (
11
- attrs?: DenormAttrs<Omit<HTMLElementTagNameMap[K], "style">>,
6
+ attrs?: DenormAttrs<HTMLElementTagNameMap[K]>,
12
7
  ...children: DenormChildren[]
13
8
  ) =>
14
- up(document.createElement(name), attrs, ...children) as UHTMLElement<
15
- HTMLElementTagNameMap[K]
16
- >;
9
+ up(
10
+ document.createElement(name),
11
+ attrs,
12
+ ...children
13
+ ) as HTMLElementTagNameMap[K];
17
14
 
18
15
  export const a = makeHTMLElement("a");
19
16
  export const abbr = makeHTMLElement("abbr");
@@ -0,0 +1,43 @@
1
+ import { O } from "./observable.js";
2
+ import { Subject, map } from "../observable/observable.js";
3
+ import { describe, it } from "../scope/describe.js";
4
+ import { expect } from "../scope/expect.js";
5
+ import { div, span } from "./html.js";
6
+ import { DOMUpdates } from "./dom.js";
7
+
8
+ describe("DOM Observable", () => {
9
+ it("updates a dom node with observable results", async () => {
10
+ const subject = new Subject<string>();
11
+ const observable = subject.pipe(map((s) => [s]));
12
+
13
+ const element = O(div(), observable);
14
+
15
+ expect(element.innerText).toEqual("");
16
+ await subject.next("H");
17
+ expect(element.innerText).toEqual("H");
18
+ await subject.next("He");
19
+ expect(element.innerText).toEqual("He");
20
+ });
21
+
22
+ it("updates a dom node's attributes", async () => {
23
+ const classes = new Subject<string[]>();
24
+ const observable = classes.map<DOMUpdates>((c) => [{ class: c.join(" ") }]);
25
+
26
+ const element = O(span(), observable);
27
+
28
+ expect(element.classList.contains("warning")).toBe(false);
29
+ expect(element.classList.contains("error")).toBe(false);
30
+
31
+ await classes.next(["warning"]);
32
+ expect(element.classList.contains("warning")).toBe(true);
33
+ expect(element.classList.contains("error")).toBe(false);
34
+
35
+ await classes.next(["error"]);
36
+ expect(element.classList.contains("warning")).toBe(true);
37
+ expect(element.classList.contains("error")).toBe(true);
38
+
39
+ await classes.next(["!warning", "!error"]);
40
+ expect(element.classList.contains("warning")).toBe(false);
41
+ expect(element.classList.contains("error")).toBe(false);
42
+ });
43
+ });
@@ -0,0 +1,11 @@
1
+ import { Observable } from "../observable/observable.js";
2
+
3
+ export function O<E extends Element>(
4
+ element: E,
5
+ observable: Observable<Parameters<E["update"]>>
6
+ ): E {
7
+ observable.subscribe((t) => {
8
+ element.update(...t);
9
+ });
10
+ return element;
11
+ }
@@ -1,10 +1,10 @@
1
- import { DOMElement, Updatable } from "../dom";
1
+ import { DOMElement } from "../dom";
2
2
  import { Link } from "./link";
3
3
 
4
4
  export interface Router {
5
5
  current?: string;
6
6
  navigate: (url: string) => (event: Event) => void;
7
- (target: Updatable<DOMElement>): Updatable<DOMElement>;
7
+ (target: DOMElement): DOMElement;
8
8
  }
9
9
 
10
10
  let baseURI = `${document.baseURI}`;
@@ -15,8 +15,8 @@ const normalizeHref = () => {
15
15
  let globalRouter: Router;
16
16
  export const Router = {
17
17
  for(links: Link[], index: string, setGlobalRouter = true): Router {
18
- let target: Updatable<Element>;
19
- const partialRouter: Partial<Router> = (t: Updatable<Element>) => {
18
+ let target: Element;
19
+ const partialRouter: Partial<Router> = (t: Element) => {
20
20
  target = t;
21
21
  const href = normalizeHref();
22
22
  const route = href === baseURI ? baseURI + index : href;
package/src/dom/test.ts CHANGED
@@ -1,2 +1,6 @@
1
1
  export {};
2
- await Promise.all([import("./html.test.js"), import("./fc.test.js")]);
2
+ await Promise.all([
3
+ import("./html.test.js"),
4
+ import("./fc.test.js"),
5
+ import("./observable.test.js"),
6
+ ]);
package/src/dom/xml.ts CHANGED
@@ -7,6 +7,5 @@ export function xml(
7
7
  (attrs, [attr, val]) => `${attrs} ${attr}="${val}"`,
8
8
  ""
9
9
  );
10
- const kids = children.join("");
11
- return `<${tag} ${attrs}>${kids}</${tag}>`;
10
+ return `<${tag} ${attrs}>${children.join("")}</${tag}>`;
12
11
  }
package/src/index.html CHANGED
@@ -15,11 +15,14 @@
15
15
  <div style="display: none" id="status"></div>
16
16
  <div style="display: none" id="json"></div>
17
17
  <div style="display: none" id="xml"></div>
18
- <script type="module" src="./test_all.js"></script>
19
- <script type="module" src="./dom/test.js"></script>
20
- <script type="module" src="./components/test.js"></script>
21
18
 
22
19
  <script type="module">
20
+ await Promise.all([
21
+ import("./test_all.js"),
22
+ import("./dom/test.js"),
23
+ import("./components/test.js"),
24
+ ]);
25
+
23
26
  import { execute } from "./scope/execute.js";
24
27
  import { displayStatistics } from "./scope/display/dom.js";
25
28
  import { onConsole } from "./scope/display/console.js";
@@ -1,13 +1,26 @@
1
- Subject
2
- BehaviorSubject
3
- ReplaySubject
1
+ Subscriber
2
+ next(t: T)
3
+ error(e: E)
4
+ complete()
5
+
4
6
  Observable
5
- of
6
- from
7
- fromEvent
8
- pipe
7
+ ::of(...Ts)
8
+ ::combineLatest([...])
9
+ ::from(promise|Iterable|Subscribable)
10
+ ::fromEvent(element, eventName)
11
+ (subscriber) -> subscription
12
+ .subscribe(subscriber) -> subscription
13
+ .pipe(...operators) -> Observable
14
+
15
+ Subject
16
+ -> BehaviorSubject(t)
17
+ -> ReplaySubject(n)
18
+
9
19
  operator
10
- map
11
20
  filter
21
+ first/last
22
+ map
23
+ publishReplay
12
24
  reduce
25
+ takeUntil
13
26
  tap
@@ -0,0 +1,93 @@
1
+ import { display } from "../display.js";
2
+ import { Observable } from "./observable.js";
3
+
4
+ export interface Next<T> {
5
+ value: T;
6
+ completed: false;
7
+ failed: false;
8
+ }
9
+
10
+ export interface Error<E> {
11
+ error: E;
12
+ completed: false;
13
+ failed: true;
14
+ }
15
+
16
+ export interface Completed {
17
+ completed: true;
18
+ failed: false;
19
+ }
20
+
21
+ export interface Failed {
22
+ completed: true;
23
+ failed: true;
24
+ }
25
+
26
+ export type Event<T, E> = Next<T> | Error<E> | Completed | Failed;
27
+
28
+ export interface EventSubscriber<T, E> {
29
+ next(e: Event<T, E>): void;
30
+ }
31
+
32
+ export const next = <T>(value: T): Next<T> => ({
33
+ value,
34
+ completed: false,
35
+ failed: false,
36
+ });
37
+ export const error = <E>(e: E): Error<E> => ({
38
+ error: e,
39
+ completed: false,
40
+ failed: true,
41
+ });
42
+ export const completed = (): Completed => ({ completed: true, failed: false });
43
+ export const failed = (): Failed => ({ completed: true, failed: true });
44
+
45
+ export const isNext = <T>(event: Event<T, unknown>): event is Next<T> =>
46
+ !event.completed && !event.failed && event.value !== undefined;
47
+ export const isError = <E>(event: Event<unknown, E>): event is Error<E> =>
48
+ event.failed && !event.completed;
49
+ export const isCompleted = (
50
+ event: Event<unknown, unknown>
51
+ ): event is Completed => event.completed && !event.failed;
52
+ export const isFailed = (event: Event<unknown, unknown>): event is Failed =>
53
+ event.completed && event.failed;
54
+
55
+ export const isEvent = <T, E>(t: T | Event<T, E>): t is Event<T, E> => {
56
+ const b = t as Event<unknown, unknown>;
57
+ return isNext(b) || isError(b) || isCompleted(b);
58
+ };
59
+
60
+ export const asEvents = <T, E>(a: (T | Event<T, E>)[]): Event<T, E>[] =>
61
+ a.map((e) => (isEvent(e) ? e : next(e)));
62
+
63
+ const marble = <T, E>(event: Event<T, E>): string =>
64
+ isError(event)
65
+ ? "X"
66
+ : isFailed(event)
67
+ ? "!"
68
+ : isCompleted(event)
69
+ ? "|"
70
+ : `(${display(event.value)})`;
71
+
72
+ export const marbles = <T, E>(events: Event<T, E>[]): string =>
73
+ `:${events.map(marble).join("-")}`;
74
+
75
+ export const collect = <T, E>(input$: Observable<T, E>) => {
76
+ const collected: Event<T, E>[] = [];
77
+
78
+ const subscription = input$.subscribe({
79
+ next: (x: T) => {
80
+ collected.push(next(x));
81
+ },
82
+ error: (e: E) => {
83
+ collected.push(error(e));
84
+ },
85
+ complete: () => {
86
+ collected.push(completed());
87
+ },
88
+ });
89
+
90
+ subscription.unsubscribe();
91
+
92
+ return collected;
93
+ };
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it } from "../scope/index.js";
2
+ import { Observable, Subject, filter, map } from "./observable.js";
3
+
4
+ describe("Observables", () => {
5
+ describe("basics", () => {
6
+ it("can create and observe a scalar subject", async () => {
7
+ const subject = new Subject<number>();
8
+
9
+ let resolved = 42;
10
+
11
+ subject.subscribe({
12
+ next: (n) => {
13
+ resolved = n;
14
+ },
15
+ });
16
+
17
+ expect(resolved).toBe(42);
18
+ await subject.next(64);
19
+ expect(resolved).toBe(64);
20
+ });
21
+ });
22
+
23
+ describe("creation", () => {
24
+ it("builds an observable of items", async () => {
25
+ const stream = Observable.of(2, 4, 8, 16);
26
+ let values: number[] = [];
27
+ await new Promise<void>((resolve) => {
28
+ stream.subscribe({
29
+ next: (n) => {
30
+ values.unshift(n);
31
+ },
32
+ complete: () => {
33
+ resolve();
34
+ },
35
+ });
36
+ });
37
+ expect(values).toEqual([16, 8, 4, 2]);
38
+ });
39
+ });
40
+
41
+ describe("pipes", () => {
42
+ it("runs a pipe", async () => {
43
+ const subject = new Subject<number>();
44
+
45
+ let resolved = 0;
46
+ const inflate = (i: number) => (n: number) => n + i;
47
+ const biggerThan = (i: number) => (n: number) => n > i;
48
+ const assign = (n: number) => {
49
+ resolved = n;
50
+ };
51
+
52
+ subject.pipe(map(inflate(22)), filter(biggerThan(70))).subscribe(assign);
53
+
54
+ expect(resolved).toBe(0);
55
+ await subject.next(42);
56
+ expect(resolved).toBe(0);
57
+ await subject.next(50);
58
+ expect(resolved).toBe(72);
59
+ });
60
+ });
61
+
62
+ describe("Subject", () => {
63
+ it("is callable", async () => {
64
+ const subject = new Subject<number>();
65
+ let resolved = 0;
66
+ subject.subscribe((n) => {
67
+ resolved = n;
68
+ });
69
+ await subject.next(42);
70
+ expect(resolved).toBe(42);
71
+ });
72
+ });
73
+ });