@loadbare/app 0.4.0 → 0.5.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 (160) hide show
  1. package/README.md +53 -82
  2. package/dist/build/assemble.d.ts +7 -5
  3. package/dist/build/assemble.d.ts.map +1 -1
  4. package/dist/build/assemble.js +29 -9
  5. package/dist/build/cli.d.ts +20 -12
  6. package/dist/build/cli.d.ts.map +1 -1
  7. package/dist/build/cli.js +34 -16
  8. package/dist/build/elements.d.ts +15 -29
  9. package/dist/build/elements.d.ts.map +1 -1
  10. package/dist/build/elements.js +25 -111
  11. package/dist/build/expand.d.ts +1 -1
  12. package/dist/build/expand.js +1 -1
  13. package/dist/build/locations.d.ts +14 -37
  14. package/dist/build/locations.d.ts.map +1 -1
  15. package/dist/build/locations.js +24 -67
  16. package/dist/build/origins.d.ts +109 -0
  17. package/dist/build/origins.d.ts.map +1 -0
  18. package/dist/build/origins.js +270 -0
  19. package/dist/core/lb-constants.d.ts +1 -0
  20. package/dist/core/lb-constants.d.ts.map +1 -1
  21. package/dist/core/lb-constants.js +15 -8
  22. package/dist/core/lb-types.d.ts +2 -2
  23. package/dist/core/lb-types.d.ts.map +1 -1
  24. package/dist/hub/lb-apply.js +1 -1
  25. package/dist/hub/lb-hub.d.ts.map +1 -1
  26. package/dist/hub/lb-hub.js +44 -17
  27. package/dist/hub/lb-rows.js +3 -3
  28. package/dist/server/lb-server.d.ts +5 -4
  29. package/dist/server/lb-server.d.ts.map +1 -1
  30. package/dist/tests/assemble.test.js +11 -4
  31. package/dist/tests/elements.test.js +47 -51
  32. package/dist/tests/expand.test.d.ts +1 -1
  33. package/dist/tests/expand.test.js +2 -2
  34. package/dist/tests/fixtures/elements/collision/imports.d.ts +3 -0
  35. package/dist/tests/fixtures/elements/collision/imports.d.ts.map +1 -0
  36. package/dist/tests/fixtures/elements/collision/imports.js +1 -0
  37. package/dist/tests/fixtures/elements/manifest/imports.d.ts +3 -0
  38. package/dist/tests/fixtures/elements/manifest/imports.d.ts.map +1 -0
  39. package/dist/tests/fixtures/elements/manifest/imports.js +1 -0
  40. package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts +3 -0
  41. package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts.map +1 -0
  42. package/dist/tests/fixtures/elements/manifest-bad-entry/imports.js +1 -0
  43. package/dist/tests/fixtures/elements/{collision/elements.d.ts → manifest-not-array/imports.d.ts} +1 -1
  44. package/dist/tests/fixtures/elements/manifest-not-array/imports.d.ts.map +1 -0
  45. package/dist/tests/fixtures/elements/manifest-not-array/imports.js +1 -0
  46. package/dist/tests/fixtures/elements/pkg/acme-widget.d.ts +2 -0
  47. package/dist/tests/fixtures/elements/pkg/acme-widget.d.ts.map +1 -0
  48. package/dist/tests/fixtures/elements/pkg/acme-widget.js +1 -0
  49. package/dist/tests/lb-express.test.js +1 -1
  50. package/dist/tests/origins.test.d.ts +10 -0
  51. package/dist/tests/origins.test.d.ts.map +1 -0
  52. package/dist/tests/origins.test.js +326 -0
  53. package/dist/tests/pages.test.js +3 -3
  54. package/dist/tests/styles.test.js +7 -4
  55. package/docs/reference/builder.md +128 -0
  56. package/docs/reference/chrome.md +75 -0
  57. package/docs/reference/css.md +44 -0
  58. package/docs/reference/custom-elements.md +327 -0
  59. package/docs/reference/data-binding.md +240 -0
  60. package/docs/reference/overview.md +38 -0
  61. package/docs/reference/page-files.md +175 -0
  62. package/docs/reference/server.md +123 -0
  63. package/docs/reference/widgets.md +163 -0
  64. package/docs/roadmap.md +130 -0
  65. package/docs/testing.md +228 -0
  66. package/docs/theory.md +344 -223
  67. package/docs/tutorials/000-getting-started.md +86 -0
  68. package/docs/tutorials/010-pages-and-navigation.md +129 -0
  69. package/docs/tutorials/020-css.md +103 -0
  70. package/docs/tutorials/030-html-decomposition.md +79 -0
  71. package/docs/tutorials/040-displaying-data.md +169 -0
  72. package/docs/tutorials/050-actions.md +77 -0
  73. package/docs/tutorials/060-custom-element-code.md +73 -0
  74. package/docs/tutorials/065-conditional-rendering.md +161 -0
  75. package/docs/tutorials/070-displaying-a-list.md +137 -0
  76. package/docs/tutorials/072-inserting-into-a-list.md +88 -0
  77. package/docs/tutorials/074-deleting-from-a-list.md +77 -0
  78. package/docs/tutorials/076-updating-a-list-item.md +86 -0
  79. package/docs/tutorials/080-widget-requests.md +124 -0
  80. package/docs/tutorials/090-using-widget-libraries.md +75 -0
  81. package/package.json +4 -12
  82. package/dist/client.js +0 -522
  83. package/dist/demo-static/src/widgets/app-box.d.ts +0 -15
  84. package/dist/demo-static/src/widgets/app-box.d.ts.map +0 -1
  85. package/dist/demo-static/src/widgets/app-box.js +0 -19
  86. package/dist/tests/fixtures/elements/collision/elements.d.ts.map +0 -1
  87. package/dist/tests/fixtures/elements/collision/elements.js +0 -3
  88. package/dist/tests/fixtures/elements/manifest/elements.d.ts +0 -5
  89. package/dist/tests/fixtures/elements/manifest/elements.d.ts.map +0 -1
  90. package/dist/tests/fixtures/elements/manifest/elements.js +0 -3
  91. package/dist/tests/fixtures/elements/manifest-bad-tag/elements.d.ts +0 -5
  92. package/dist/tests/fixtures/elements/manifest-bad-tag/elements.d.ts.map +0 -1
  93. package/dist/tests/fixtures/elements/manifest-bad-tag/elements.js +0 -3
  94. package/dist/tests/fixtures/elements/manifest-bad-value/elements.d.ts +0 -5
  95. package/dist/tests/fixtures/elements/manifest-bad-value/elements.d.ts.map +0 -1
  96. package/dist/tests/fixtures/elements/manifest-bad-value/elements.js +0 -3
  97. package/dist/tests/golden.test.d.ts +0 -19
  98. package/dist/tests/golden.test.d.ts.map +0 -1
  99. package/dist/tests/golden.test.js +0 -60
  100. package/dist/tests/helpers/window.d.ts +0 -43
  101. package/dist/tests/helpers/window.d.ts.map +0 -1
  102. package/dist/tests/helpers/window.js +0 -78
  103. package/dist/tests/lb-input.test.d.ts +0 -9
  104. package/dist/tests/lb-input.test.d.ts.map +0 -1
  105. package/dist/tests/lb-input.test.js +0 -78
  106. package/dist/tests/lb-list.test.d.ts +0 -12
  107. package/dist/tests/lb-list.test.d.ts.map +0 -1
  108. package/dist/tests/lb-list.test.js +0 -44
  109. package/dist/tests/lb-options.test.d.ts +0 -10
  110. package/dist/tests/lb-options.test.d.ts.map +0 -1
  111. package/dist/tests/lb-options.test.js +0 -121
  112. package/dist/tests/lb-picker.test.d.ts +0 -14
  113. package/dist/tests/lb-picker.test.d.ts.map +0 -1
  114. package/dist/tests/lb-picker.test.js +0 -59
  115. package/dist/tests/lb-select.test.d.ts +0 -9
  116. package/dist/tests/lb-select.test.d.ts.map +0 -1
  117. package/dist/tests/lb-select.test.js +0 -71
  118. package/dist/tests/lb-table.test.d.ts +0 -15
  119. package/dist/tests/lb-table.test.d.ts.map +0 -1
  120. package/dist/tests/lb-table.test.js +0 -205
  121. package/dist/widgets/index.d.ts +0 -7
  122. package/dist/widgets/index.d.ts.map +0 -1
  123. package/dist/widgets/index.js +0 -6
  124. package/dist/widgets/lb-input.d.ts +0 -2
  125. package/dist/widgets/lb-input.d.ts.map +0 -1
  126. package/dist/widgets/lb-input.js +0 -48
  127. package/dist/widgets/lb-list.d.ts +0 -2
  128. package/dist/widgets/lb-list.d.ts.map +0 -1
  129. package/dist/widgets/lb-list.js +0 -17
  130. package/dist/widgets/lb-options.d.ts +0 -26
  131. package/dist/widgets/lb-options.d.ts.map +0 -1
  132. package/dist/widgets/lb-options.js +0 -72
  133. package/dist/widgets/lb-picker.d.ts +0 -2
  134. package/dist/widgets/lb-picker.d.ts.map +0 -1
  135. package/dist/widgets/lb-picker.js +0 -25
  136. package/dist/widgets/lb-select.d.ts +0 -2
  137. package/dist/widgets/lb-select.d.ts.map +0 -1
  138. package/dist/widgets/lb-select.js +0 -43
  139. package/dist/widgets/lb-table.d.ts +0 -2
  140. package/dist/widgets/lb-table.d.ts.map +0 -1
  141. package/dist/widgets/lb-table.js +0 -113
  142. package/docs/application-chrome.md +0 -36
  143. package/docs/building-html-pages.md +0 -130
  144. package/docs/getting-started.md +0 -120
  145. package/docs/guide.md +0 -1164
  146. package/docs/hosting.md +0 -218
  147. package/docs/latent-risks.md +0 -20
  148. package/widgets/index.ts +0 -6
  149. package/widgets/lb-input.html +0 -1
  150. package/widgets/lb-input.ts +0 -64
  151. package/widgets/lb-list.html +0 -1
  152. package/widgets/lb-list.ts +0 -21
  153. package/widgets/lb-options.html +0 -4
  154. package/widgets/lb-options.ts +0 -88
  155. package/widgets/lb-picker.html +0 -7
  156. package/widgets/lb-picker.ts +0 -27
  157. package/widgets/lb-select.html +0 -4
  158. package/widgets/lb-select.ts +0 -55
  159. package/widgets/lb-table.html +0 -8
  160. package/widgets/lb-table.ts +0 -126
@@ -0,0 +1,124 @@
1
+ # Widget Requests
2
+
3
+ Our list example showed the use of forms and submit. The inputs
4
+ were passive in the sense that they did not trigger any change on their
5
+ own.
6
+
7
+ Now we will see how to make a widget that fires events when its value
8
+ changes.
9
+
10
+ ## Writing the widget
11
+
12
+ Our new custom input will no longer rely on Loadbare's form handling,
13
+ and so it must reimplement the data scoping logic that is in
14
+ Loadbare. This reimplementation approach is neither encouraged nor
15
+ discouraged. This tutorial shows only that it is possible, and exposes
16
+ how Loadbare internals work.
17
+
18
+ ```html
19
+ <!-- src/note-input.html -->
20
+ <input type="text" />
21
+ ```
22
+
23
+ ```ts
24
+ // src/note-input.ts
25
+ import {
26
+ ATTR_CELL,
27
+ ATTR_KEY,
28
+ ATTR_QUERY,
29
+ ATTR_VALUE,
30
+ LB_EVENT_NAME,
31
+ } from "@loadbare/app/constants";
32
+
33
+ class NoteInput extends HTMLElement {
34
+ static observedAttributes = [ATTR_VALUE];
35
+
36
+ attributeChangedCallback(_name: string, _old: string, value: string) {
37
+ const input = this.querySelector("input");
38
+ if (input) input.value = value;
39
+ }
40
+
41
+ connectedCallback() {
42
+ this.addEventListener("change", () => {
43
+ const input = this.querySelector("input");
44
+ if (!input) return;
45
+ const query = this.closest(`[${ATTR_QUERY}]`)?.getAttribute(ATTR_QUERY);
46
+ const key = this.closest(`[${ATTR_KEY}]`)?.getAttribute(ATTR_KEY);
47
+ const cell = this.getAttribute(ATTR_CELL);
48
+ if (!query || !key || !cell) return;
49
+ this.dispatchEvent(
50
+ new CustomEvent(LB_EVENT_NAME, {
51
+ bubbles: true,
52
+ detail: { op: "cell-change", query, key, cell, value: input.value },
53
+ }),
54
+ );
55
+ });
56
+ }
57
+ }
58
+
59
+ customElements.define("note-input", NoteInput);
60
+ ```
61
+
62
+ A widget with both a `.html` and a `.ts` file shares one tag name; the
63
+ build finds each half independently. On change, it reads its own
64
+ `lb-query`/`lb-key`/`lb-cell` coordinates and dispatches a `cell-change`
65
+ request itself, the way `lb-update` does for a whole form.
66
+
67
+ ## Using it
68
+
69
+ ```html
70
+ <!-- src/pages/about.page.html -->
71
+ <lb-list lb-query="notes">
72
+ <ul>
73
+ <template lb-key="id">
74
+ <li>
75
+ <note-input lb-cell="text"></note-input>
76
+ <button lb-delete>Delete</button>
77
+ </li>
78
+ </template>
79
+ </ul>
80
+ </lb-list>
81
+ ```
82
+
83
+ The `<form lb-update>` and Save button are gone — `note-input` commits on
84
+ every change, so there's nothing left to batch.
85
+
86
+ ## Answering it server-side
87
+
88
+ ```ts
89
+ // src/pages/about.hooks.ts
90
+ import { patch } from "@loadbare/app/server";
91
+
92
+ export const hooks = {
93
+ // ...beforeGet and actions unchanged...
94
+ crud: {
95
+ notes: {
96
+ // ...tupleInsert, tupleDelete, tupleUpdate unchanged...
97
+ cellChange: {
98
+ run: async (ctx, { key, value }) => {
99
+ const note = await ctx.db.updateNote(key, value);
100
+ return { notes: patch({ rows: [note] }) };
101
+ },
102
+ refresh: [],
103
+ },
104
+ },
105
+ },
106
+ };
107
+ ```
108
+
109
+ `cellChange` reuses `updateNote` from [Updating a List Item](./076-updating-a-list-item.md)
110
+ — the database doesn't care whether the edit came from a form's values
111
+ map or one widget's value.
112
+
113
+ ## Run it
114
+
115
+ ```
116
+ npm run dev
117
+ ```
118
+
119
+ Edit a note's text and click elsewhere — it commits immediately, no Save
120
+ button. Reload — the change is still there.
121
+
122
+ ---
123
+ Prev: [Updating a List Item](./076-updating-a-list-item.md)
124
+ Next: [Using Widget Libraries](./090-using-widget-libraries.md)
@@ -0,0 +1,75 @@
1
+ # Using Widget Libraries
2
+
3
+ [Displaying a List](./070-displaying-a-list.md) already installed one widget
4
+ library, `@loadbare/widgets`. This tutorial covers what that step actually
5
+ did, and why it is the same step for a library from anywhere else.
6
+
7
+ [Custom Element Code](./060-custom-element-code.md) and
8
+ [Widget Requests](./080-widget-requests.md) wrote widgets by hand, one
9
+ file per tag, discovered because the tag turned up in a page. A widget
10
+ installed from a package works the same way once the package is listed —
11
+ listing the package is the only new piece.
12
+
13
+ ## Installing the library
14
+
15
+ ```
16
+ npm install @loadbare/widgets
17
+ ```
18
+
19
+ ## Declaring the package
20
+
21
+ The builder finds a widget by scanning for its filename. It scans the
22
+ application's own `src/` without being asked; an installed package has to
23
+ be listed first. That list lives in one file, `imports.ts`, at the root of
24
+ `src/`:
25
+
26
+ ```ts
27
+ // src/imports.ts
28
+ export default ["@loadbare/widgets"];
29
+ ```
30
+
31
+ List the package, not its tags. The builder scans it the same way it scans
32
+ `src/`, so `lb-select.html` and `lb-select.js` inside the package define and
33
+ register `<lb-select>` with nothing else written down. A package that ships
34
+ compiled says which of its directories holds those files — see
35
+ [Widgets from packages](../reference/builder.md#widgets-from-packages) — and
36
+ that is the package author's line to write, not the application's.
37
+
38
+ Only tags actually used in the chrome file or a page are bundled. Listing a
39
+ package says where to look; it does not import anything on its own.
40
+
41
+ ## Using a tag
42
+
43
+ Once the package is listed, a tag from the library is used exactly like a
44
+ widget written by hand — the query scope and cell attributes work the same
45
+ regardless of where the script came from:
46
+
47
+ ```html
48
+ <!-- src/pages/index.page.html -->
49
+ <div lb-query="status">
50
+ <lb-select lb-cell="state">
51
+ <option value="open">Open</option>
52
+ <option value="closed">Closed</option>
53
+ </lb-select>
54
+ </div>
55
+ ```
56
+
57
+ `lb-select` follows the `lb-value` contract
58
+ [Custom Element Code](./060-custom-element-code.md) described: the hub
59
+ writes the query result to `lb-value`, and the widget's own class —
60
+ imported from `@loadbare/widgets`, not written in this
61
+ application — reacts to it.
62
+
63
+ ## Where this stops
64
+
65
+ This only covers consuming a published widget, not writing one for
66
+ publication — that's the same class shape
67
+ [Custom Element Code](./060-custom-element-code.md) and
68
+ [Widget Requests](./080-widget-requests.md) already wrote, packaged and
69
+ given an import specifier instead of living in an application's `src/`.
70
+ It doesn't cover `lb-table`'s footer destination or `lb-picker`'s
71
+ expansion parameters, which are in
72
+ [The Basic Widget Library](../reference/widgets.md).
73
+
74
+ ---
75
+ Prev: [Widget Requests](./080-widget-requests.md)
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@loadbare/app",
3
3
  "description": "High performance web app framework for server-bound applications",
4
- "version": "0.4.0",
4
+ "version": "0.5.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
8
- "widgets",
9
8
  "docs",
10
9
  "README.md"
11
10
  ],
@@ -22,8 +21,7 @@
22
21
  "./rows": "./dist/hub/lb-rows.js",
23
22
  "./server": "./dist/server/lb-server.js",
24
23
  "./express": "./dist/server/lb-express.js",
25
- "./build": "./dist/build/elements.js",
26
- "./widgets/*": "./dist/widgets/*.js"
24
+ "./build": "./dist/build/elements.js"
27
25
  },
28
26
  "scripts": {
29
27
  "prepublishOnly": "npm run typecheck && npm run test && npm run build",
@@ -33,16 +31,10 @@
33
31
  "release:minor": "node scripts/bump-release.mjs minor",
34
32
  "release:major": "node scripts/bump-release.mjs major",
35
33
  "prebuild": "node --eval \"fs.rmSync('dist',{recursive:true,force:true})\" --input-type=module",
36
- "build:client": "esbuild client/main.ts --bundle --format=iife --outfile=dist/client.js",
37
34
  "build:server": "tsc --project tsconfig.build.json",
38
- "build": "npm run build:server && npm run build:client",
39
- "build:demo": "npm run build:server && tsx build/cli.ts --src demo --out dist/demo",
40
- "dev": "npm run build:demo && (tsx build/cli.ts --src demo --out dist/demo --watch & tsx demo/server.ts)",
41
- "build:demo-static": "npm run build:server && tsx build/cli.ts --src demo-static/src --out dist/demo-static",
42
- "dev:demo-static": "npm run build:demo-static -- --watch & node demo-static/serve.mjs",
35
+ "build": "npm run build:server",
36
+ "postbuild": "node --eval \"fs.chmodSync('dist/build/cli.js', 0o755)\" --input-type=module",
43
37
  "test": "tsx --test \"tests/**/*.test.ts\"",
44
- "test:golden": "UPDATE_GOLDEN=1 tsx --test tests/golden.test.ts",
45
- "pretypecheck": "npm run build:demo",
46
38
  "typecheck": "tsc --noEmit",
47
39
  "format": "prettier --write .",
48
40
  "format:check": "prettier --check ."