@cocreate/elements 1.46.0 → 2.0.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/.github/FUNDING.yml +1 -1
- package/.github/workflows/automated.yml +18 -7
- package/CHANGELOG.md +753 -700
- package/CONTRIBUTING.md +6 -6
- package/README.md +469 -46
- package/demo/index.html +1 -1
- package/docs/index.html +7 -7
- package/package.json +12 -11
- package/src/crudHandler.js +153 -47
- package/src/dataHandler.js +7 -0
- package/src/dataObject.js +54 -0
- package/src/formHandler.js +226 -170
- package/src/formSelectors.js +1 -0
- package/src/getDataHandler.js +97 -94
- package/src/hrefHandler.js +104 -0
- package/src/iframeHandler.js +90 -0
- package/src/index.js +446 -12
- package/src/initHandler.js +96 -46
- package/src/mapRegistry.js +10 -1
- package/src/setDataHandler.js +171 -87
- package/src/socketHandler.js +328 -0
- package/src/socketSelectors.js +3 -0
- package/src/srcHandler.js +69 -32
- package/src/subscribeHandler.js +64 -64
- package/src/valueQuery.js +3 -4
- package/src/valueQuerySelector.js +1 -0
- package/test/deferred-src.test.cjs +11 -0
- package/test/form-enter.test.cjs +48 -0
- package/test/get-data.test.cjs +100 -0
- package/test/href-handler.test.cjs +132 -0
- package/test/init-read.test.cjs +145 -0
- package/test/lazy-loading.test.cjs +168 -0
- package/test/load-more.test.cjs +19 -0
- package/test/save-array.test.cjs +31 -0
- package/test/save-completion.test.cjs +36 -0
- package/test/set-data-type.test.cjs +119 -0
- package/test/ssr-response.test.cjs +108 -0
- package/webpack.config.js +1 -0
- package/src/dndHandler.js +0 -155
package/CONTRIBUTING.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# Contributing to CoCreate-elements
|
|
2
2
|
|
|
3
|
-
This project is work of [many contributors](https://github.com/
|
|
4
|
-
You're encouraged to submit [pull requests](https://github.com/
|
|
5
|
-
[propose features and discuss issues](https://github.com/
|
|
3
|
+
This project is work of [many contributors](https://github.com/CoCreateJS/elements/graphs/contributors).
|
|
4
|
+
You're encouraged to submit [pull requests](https://github.com/CoCreateJS/elements/pulls),
|
|
5
|
+
[propose features and discuss issues](https://github.com/CoCreateJS/elements/issues).
|
|
6
6
|
|
|
7
7
|
In the examples below, substitute your Github username for `contributor` in URLs.
|
|
8
8
|
|
|
9
9
|
## Fork the Project
|
|
10
10
|
|
|
11
|
-
Fork the [project on Github](https://github.com/
|
|
11
|
+
Fork the [project on Github](https://github.com/CoCreateJS/elements) and check out your copy.
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
git elements https://github.com/contributor/CoCreate-elements.git
|
|
15
15
|
cd CoCreate-elements
|
|
16
|
-
git remote add upstream https://github.com/
|
|
16
|
+
git remote add upstream https://github.com/CoCreateJS/elements.git
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## Create a Topic Branch
|
|
@@ -75,7 +75,7 @@ git push origin my-feature-branch
|
|
|
75
75
|
|
|
76
76
|
## Make a Pull Request
|
|
77
77
|
|
|
78
|
-
Go to [https://github.com/
|
|
78
|
+
Go to [https://github.com/CoCreateJS/elements](https://github.com/CoCreateJS/elements) and select your feature branch.
|
|
79
79
|
Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days.
|
|
80
80
|
|
|
81
81
|
## Rebase
|
package/README.md
CHANGED
|
@@ -1,91 +1,514 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @cocreate/elements
|
|
2
|
+
|
|
3
|
+
Bind any HTML element directly to your data using HTML5 attributes. An element declares *where its value lives* — a storage, database, array, document, and key — and the module handles the rest: reading the value in, writing changes back, and keeping it synchronized in realtime as other clients and servers broadcast updates. There is no query code, no fetch layer, and no view model. The markup is the data binding.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
For a complete guide and working demo refer to the [documentation](https://CoCreateJS.com/docs/elements).
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
* [Features](#features)
|
|
14
|
+
* [Installation](#installation)
|
|
15
|
+
* [Usage](#usage)
|
|
16
|
+
* [How it Works](#how-it-works)
|
|
17
|
+
* [The Data Scope](#the-data-scope)
|
|
18
|
+
* [Core Attributes](#core-attributes)
|
|
19
|
+
* [Behavior Attributes](#behavior-attributes)
|
|
20
|
+
* [Key Expressions](#key-expressions)
|
|
21
|
+
* [Value Pipeline](#value-pipeline)
|
|
22
|
+
* [Forms](#forms)
|
|
23
|
+
* [Filtering and Lists](#filtering-and-lists)
|
|
24
|
+
* [Realtime Synchronization](#realtime-synchronization)
|
|
25
|
+
* [Actions](#actions)
|
|
26
|
+
* [Element Methods](#element-methods)
|
|
27
|
+
* [JavaScript API](#javascript-api)
|
|
28
|
+
* [Behavior Notes](#behavior-notes)
|
|
29
|
+
* [Announcements](#announcements)
|
|
30
|
+
* [Roadmap](#roadmap)
|
|
31
|
+
* [How to Contribute](#how-to-contribute)
|
|
32
|
+
* [About](#about)
|
|
33
|
+
* [License](#license)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
* **Declarative Data Binding:** Point an element at a document field and it reads, renders, and persists that field without any application code.
|
|
40
|
+
* **Automatic CRUD Resolution:** The operation is inferred from the attributes present, so the same markup creates a record when it has no id and updates it when it does.
|
|
41
|
+
* **Realtime Two-Way Sync:** Elements subscribe to their own data scope and update instantly when the underlying record changes anywhere in the system.
|
|
42
|
+
* **Batched Reads:** Elements sharing a scope are collected into a single query, so a document bound across twenty fields performs one read.
|
|
43
|
+
* **Forms as Documents:** A form groups fields into one payload, propagates its scope to its children, and saves them as a single operation.
|
|
44
|
+
* **Value Transformation Pipeline:** Type coercion, prefixes, suffixes, replacements, casing, and encoding are applied on the way in and out.
|
|
45
|
+
* **Filter Integration:** Works with `@cocreate/filter` to drive queries, sorting, pagination, and infinite scroll from markup.
|
|
46
|
+
* **Action Integration:** Registers `save`, `delete`, and `reset` so persistence composes into action chains.
|
|
47
|
+
* **Automatic Binding:** Elements inserted later, including rendered templates, are initialized and subscribed automatically.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install @cocreate/elements
|
|
55
|
+
```
|
|
2
56
|
|
|
3
|
-
|
|
57
|
+
```bash
|
|
58
|
+
yarn add @cocreate/elements
|
|
59
|
+
```
|
|
4
60
|
|
|
5
|
-
|
|
6
|
-

|
|
7
|
-

|
|
8
|
-

|
|
9
|
-

|
|
10
|
-

|
|
61
|
+
### CDN
|
|
11
62
|
|
|
12
|
-
|
|
63
|
+
```html
|
|
64
|
+
<script src="https://cdn.CoCreateJS.com/elements/latest/CoCreate-elements.min.js"></script>
|
|
65
|
+
```
|
|
13
66
|
|
|
14
|
-
|
|
67
|
+
---
|
|
15
68
|
|
|
16
|
-
|
|
69
|
+
## Usage
|
|
17
70
|
|
|
18
|
-
|
|
71
|
+
### Display a Value
|
|
19
72
|
|
|
20
73
|
```html
|
|
21
|
-
<
|
|
74
|
+
<span array="users" object="64b9a32e18f21bc56789abcd" key="name"></span>
|
|
22
75
|
```
|
|
23
76
|
|
|
77
|
+
The element reads the `name` field of that document and renders it. If the document changes anywhere in the system, the element updates.
|
|
78
|
+
|
|
79
|
+
### Edit a Value
|
|
80
|
+
|
|
24
81
|
```html
|
|
25
|
-
<
|
|
82
|
+
<input
|
|
83
|
+
array="users"
|
|
84
|
+
object="64b9a32e18f21bc56789abcd"
|
|
85
|
+
key="email"
|
|
86
|
+
realtime="true" />
|
|
26
87
|
```
|
|
27
88
|
|
|
28
|
-
|
|
89
|
+
With `realtime`, every keystroke persists the field. Without it, the value is saved when a `save` action runs.
|
|
29
90
|
|
|
30
|
-
|
|
31
|
-
|
|
91
|
+
### Group Fields Into a Document
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<form array="users" object="64b9a32e18f21bc56789abcd">
|
|
95
|
+
<input key="name" />
|
|
96
|
+
<input key="email" />
|
|
97
|
+
<textarea key="bio"></textarea>
|
|
98
|
+
|
|
99
|
+
<button actions="save">Save</button>
|
|
100
|
+
</form>
|
|
32
101
|
```
|
|
33
102
|
|
|
34
|
-
|
|
103
|
+
The form propagates its scope to every field, so each input only declares its `key`. Saving sends one payload containing all three fields.
|
|
35
104
|
|
|
36
|
-
|
|
37
|
-
|
|
105
|
+
### Create a Record
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<form array="users" object>
|
|
109
|
+
<input key="name" />
|
|
110
|
+
<input key="email" />
|
|
111
|
+
|
|
112
|
+
<button actions="save, reset">Create</button>
|
|
113
|
+
</form>
|
|
38
114
|
```
|
|
39
115
|
|
|
40
|
-
|
|
116
|
+
An empty `object` attribute means "no document yet". On save the module issues a create, then writes the new id back into the form and its fields, so subsequent saves update the same record.
|
|
41
117
|
|
|
42
|
-
|
|
43
|
-
- [Announcements](#announcements)
|
|
44
|
-
- [Roadmap](#roadmap)
|
|
45
|
-
- [How to Contribute](#how-to-contribute)
|
|
46
|
-
- [About](#about)
|
|
47
|
-
- [License](#license)
|
|
118
|
+
### Render a List
|
|
48
119
|
|
|
49
|
-
|
|
120
|
+
```html
|
|
121
|
+
<div
|
|
122
|
+
array="users"
|
|
123
|
+
object
|
|
124
|
+
filter-query-key="status"
|
|
125
|
+
filter-query-value="active"
|
|
126
|
+
filter-limit="20"
|
|
127
|
+
filter-sort-key="name"
|
|
128
|
+
render-query="[template]">
|
|
129
|
+
<div template>
|
|
130
|
+
<span>{{object.name}}</span>
|
|
131
|
+
<span>{{object.email}}</span>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
```
|
|
50
135
|
|
|
51
|
-
|
|
136
|
+
### Delete a Record
|
|
52
137
|
|
|
53
|
-
|
|
138
|
+
```html
|
|
139
|
+
<button
|
|
140
|
+
array="users"
|
|
141
|
+
object="64b9a32e18f21bc56789abcd"
|
|
142
|
+
actions="delete">
|
|
143
|
+
Delete
|
|
144
|
+
</button>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Multiple targets can be selected with `delete-query`. Each target declares its
|
|
148
|
+
own CRUD scope; object targets sharing the same storage, database, and array are
|
|
149
|
+
sent in one delete request.
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<button
|
|
153
|
+
actions="delete"
|
|
154
|
+
delete-query="$document [data-delete]:checked[]">
|
|
155
|
+
Delete selected
|
|
156
|
+
</button>
|
|
157
|
+
|
|
158
|
+
<input
|
|
159
|
+
type="checkbox"
|
|
160
|
+
data-delete
|
|
161
|
+
array="users"
|
|
162
|
+
object="64b9a32e18f21bc56789abcd" />
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## How it Works
|
|
168
|
+
|
|
169
|
+
1. On load the module scans for elements declaring `storage`, `database`, `array`, or `render-json`.
|
|
170
|
+
2. Each element's attributes are parsed into a normalized CRUD payload, and its **type** is inferred from which attributes are present.
|
|
171
|
+
3. A **dataKey** is generated from the scope, and every element sharing that key is grouped together. Field-level `key` is deliberately excluded from document-scope keys so all fields of one document share a single scope.
|
|
172
|
+
4. The scope is subscribed to over the socket so future changes are pushed to every bound element.
|
|
173
|
+
5. Reads are debounced and batched, so one query serves every element in the scope.
|
|
174
|
+
6. The response is distributed to each element, which extracts its own field and renders it through the value pipeline.
|
|
175
|
+
7. Editable elements listen for input. When `realtime` is enabled, changes persist automatically.
|
|
176
|
+
8. Writes resolve to a create or an update depending on whether an id is present, and the resulting id is propagated back into the markup.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## The Data Scope
|
|
181
|
+
|
|
182
|
+
Attributes describe a hierarchy, from the storage provider down to a single field.
|
|
183
|
+
|
|
184
|
+
| Level | Attribute | Description |
|
|
185
|
+
| ----- | --------- | ----------- |
|
|
186
|
+
| Storage | `storage` | Storage provider or alias |
|
|
187
|
+
| Database | `database` | Database name |
|
|
188
|
+
| Array | `array` | Collection, table, or dataset |
|
|
189
|
+
| Index | `index` | Index within the array |
|
|
190
|
+
| Object | `object` | Document id, empty for a new document |
|
|
191
|
+
| Key | `key` | Field within the document |
|
|
192
|
+
|
|
193
|
+
The **type** of operation is inferred from the deepest level present:
|
|
194
|
+
|
|
195
|
+
| Attributes Present | Inferred Type |
|
|
196
|
+
| ------------------ | ------------- |
|
|
197
|
+
| `object` or `key` (with `array`) | `object` |
|
|
198
|
+
| `index` (with `array`) | `index` |
|
|
199
|
+
| `array` | `array` |
|
|
200
|
+
| `database` | `database` |
|
|
201
|
+
| `storage` | `storage` |
|
|
202
|
+
|
|
203
|
+
Any of these may hold a comma separated list to target several scopes at once.
|
|
54
204
|
|
|
55
|
-
|
|
205
|
+
```html
|
|
206
|
+
<div array="users, admins" key="name"></div>
|
|
207
|
+
```
|
|
56
208
|
|
|
57
|
-
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Core Attributes
|
|
212
|
+
|
|
213
|
+
| Attribute | Description |
|
|
214
|
+
| --------- | ----------- |
|
|
215
|
+
| `storage` | Storage provider targeted by the operation |
|
|
216
|
+
| `database` | Database name, defaults to the organization |
|
|
217
|
+
| `array` | Collection or table name |
|
|
218
|
+
| `index` | Index scope within the array |
|
|
219
|
+
| `object` | Document id. Empty creates a new document, `ObjectId()` generates one, `pending` marks a create in flight |
|
|
220
|
+
| `key` | Field path within the document |
|
|
221
|
+
| `updateName` | Rename target when updating a named scope |
|
|
222
|
+
| `organization_id` | Tenant identifier |
|
|
223
|
+
| `host` | Host context |
|
|
224
|
+
| `apikey` | API key used for the operation |
|
|
225
|
+
| `room` | Realtime room scope |
|
|
226
|
+
| `reference` | When `false`, strips storage metadata from the returned object |
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Behavior Attributes
|
|
231
|
+
|
|
232
|
+
Each of these accepts `"false"` to opt out, and most default to enabled.
|
|
233
|
+
|
|
234
|
+
| Attribute | Description |
|
|
235
|
+
| --------- | ----------- |
|
|
236
|
+
| `crud="false"` | Excludes the element from binding entirely |
|
|
237
|
+
| `read="false"` | Element never reads, it only writes |
|
|
238
|
+
| `save="false"` | Element never writes, it only reads |
|
|
239
|
+
| `update="false"` | Element ignores incoming updates after its first read |
|
|
240
|
+
| `listen="false"` | Element ignores broadcasts, but still accepts its own reads |
|
|
241
|
+
| `delete` | Marks the element as a delete target |
|
|
242
|
+
| `upsert` | Creates the document if it does not exist when updating |
|
|
243
|
+
| `realtime="true"` | Persists on every input event |
|
|
244
|
+
| `crdt="true"` | Routes text edits through collaborative merge instead of overwriting |
|
|
245
|
+
| `broadcast="false"` | Suppresses broadcasting the change to other clients |
|
|
246
|
+
| `broadcast-sender="false"` | Suppresses echoing the change back to the sender |
|
|
247
|
+
| `broadcast-client="false"` | Suppresses propagation to other tabs |
|
|
248
|
+
| `form-attributes="false"` | Prevents the element from inheriting its form's scope |
|
|
249
|
+
| `reset` | Controls reset behavior, see [Forms](#forms) |
|
|
250
|
+
| `splice`, `slice`, `update` | Array mutation modes when the key targets an index |
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Key Expressions
|
|
255
|
+
|
|
256
|
+
`key` supports more than a plain field name.
|
|
257
|
+
|
|
258
|
+
| Expression | Resolves To |
|
|
259
|
+
| ---------- | ----------- |
|
|
260
|
+
| `name` | A top-level field |
|
|
261
|
+
| `profile.address.city` | A nested field via dot notation |
|
|
262
|
+
| `tags[0]` | An array member by index |
|
|
263
|
+
| `{}` | The entire document, for reading or writing whole objects |
|
|
264
|
+
| `tags.$length` | The length of an array field |
|
|
265
|
+
| `$data` | The complete response payload |
|
|
266
|
+
| `$object` / `$array` | The full result collection for the current type |
|
|
58
267
|
|
|
59
|
-
|
|
268
|
+
```html
|
|
269
|
+
<span array="posts" object="64b9a32e18f21bc56789abcd" key="comments.$length"></span>
|
|
270
|
+
```
|
|
60
271
|
|
|
61
|
-
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Value Pipeline
|
|
275
|
+
|
|
276
|
+
Values are transformed on the way in and out by `@cocreate/element-prototype`. These attributes apply to any bound element.
|
|
277
|
+
|
|
278
|
+
| Attribute | Description |
|
|
279
|
+
| --------- | ----------- |
|
|
280
|
+
| `value-type` | Coerces the value, for example `json`, `html`, `text`, `array`, `number` |
|
|
281
|
+
| `value-prefix` | Prepends a string |
|
|
282
|
+
| `value-suffix` | Appends a string |
|
|
283
|
+
| `value-replace` | Replaces the first match of a pattern |
|
|
284
|
+
| `value-replaceall` | Replaces every match of a pattern |
|
|
285
|
+
| `value-replacement` | Replacement string used by the above |
|
|
286
|
+
| `value-lowercase` | Lowercases the value |
|
|
287
|
+
| `value-uppercase` | Uppercases the value |
|
|
288
|
+
| `value-encode` | Encodes the value, for example base64 or URI |
|
|
289
|
+
| `value-decode` | Decodes the value |
|
|
290
|
+
| `value-remove-query` | Removes matching nodes before reading an HTML value |
|
|
291
|
+
| `value-dispatch` | Clears the value when a query returns no results |
|
|
292
|
+
| `value-bubbles` | Bubbles the synthetic input event |
|
|
293
|
+
| `value-query` | Composes this element's value from other elements |
|
|
294
|
+
| `value-attribute` | Writes the composed value to an attribute instead of the value |
|
|
62
295
|
|
|
63
|
-
|
|
296
|
+
```html
|
|
297
|
+
<textarea
|
|
298
|
+
array="files"
|
|
299
|
+
object="64b9a32e18f21bc56789abcd"
|
|
300
|
+
key="src"
|
|
301
|
+
value-type="text"
|
|
302
|
+
value-replaceall="/```html\n|\n```/g"></textarea>
|
|
303
|
+
```
|
|
64
304
|
|
|
65
|
-
|
|
305
|
+
---
|
|
66
306
|
|
|
67
|
-
|
|
307
|
+
## Forms
|
|
68
308
|
|
|
69
|
-
|
|
309
|
+
### Scope Inheritance
|
|
310
|
+
|
|
311
|
+
A form propagates `organization_id`, `host`, `storage`, `database`, `array`, `index`, `object`, and `key` to descendant elements that participate in binding. Add `form-attributes="false"` to an element that must keep its own scope.
|
|
312
|
+
|
|
313
|
+
### Generated Ids
|
|
314
|
+
|
|
315
|
+
`object="ObjectId()"` generates a client-side id at initialization, letting related records reference each other before they are persisted.
|
|
316
|
+
|
|
317
|
+
### Saving
|
|
318
|
+
|
|
319
|
+
Saving a form collects every bound field into one payload per type and issues a single operation. Saving an individual element inside a form delegates to the form, so a field never writes a partial document by accident.
|
|
320
|
+
|
|
321
|
+
### Reset
|
|
322
|
+
|
|
323
|
+
The `reset` attribute controls what a reset preserves.
|
|
324
|
+
|
|
325
|
+
| Value | Document Id | Value |
|
|
326
|
+
| ----- | ----------- | ----- |
|
|
327
|
+
| omitted | cleared | cleared |
|
|
328
|
+
| `object` | cleared | preserved |
|
|
329
|
+
| `value` | preserved | cleared |
|
|
330
|
+
| `false` | preserved | preserved |
|
|
331
|
+
|
|
332
|
+
```html
|
|
333
|
+
<input key="organization_id" value="$organization_id" reset="false" hidden />
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## Filtering and Lists
|
|
339
|
+
|
|
340
|
+
Filter attributes from `@cocreate/filter` compose directly with a bound scope to drive queries, sorting, limits, and pagination.
|
|
341
|
+
|
|
342
|
+
```html
|
|
343
|
+
<div
|
|
344
|
+
array="posts"
|
|
345
|
+
object
|
|
346
|
+
filter-query-key="status"
|
|
347
|
+
filter-query-value="published"
|
|
348
|
+
filter-sort-key="created.on"
|
|
349
|
+
filter-sort-direction="desc"
|
|
350
|
+
filter-limit="10"
|
|
351
|
+
render-query="[template]">
|
|
352
|
+
<div filter-on="scroll" filter-query="$parent"></div>
|
|
353
|
+
<article template>{{object.title}}</article>
|
|
354
|
+
</div>
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
A filter element may target another element with `filter-query`, so an input elsewhere on the page can drive a list's query. Changing a filter re-reads the scope and re-renders.
|
|
70
358
|
|
|
71
|
-
|
|
359
|
+
---
|
|
72
360
|
|
|
73
|
-
|
|
361
|
+
## Realtime Synchronization
|
|
74
362
|
|
|
75
|
-
|
|
363
|
+
Every scope subscribes over the socket on two channels: one for the specific document and one for the collection it belongs to. A change therefore reaches both the element bound to that record and any list rendering the collection.
|
|
76
364
|
|
|
77
|
-
|
|
365
|
+
Subscriptions are reference counted. When the last element bound to a scope is removed from the DOM, the module unsubscribes automatically, so rendered lists and modals do not leak channels.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Actions
|
|
370
|
+
|
|
371
|
+
| Action | Completion Event | Behavior |
|
|
372
|
+
| ------ | ---------------- | -------- |
|
|
373
|
+
| `save` | `saved` | Persists the element, or its form when it belongs to one |
|
|
374
|
+
| `delete` | `deleted` | Deletes the bound document, honoring `delete-query` for multiple targets |
|
|
375
|
+
| `reset` | `reset` | Restores the form according to each field's `reset` attribute |
|
|
376
|
+
|
|
377
|
+
```html
|
|
378
|
+
<button actions="save, reset">Save and clear</button>
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Element Methods
|
|
384
|
+
|
|
385
|
+
Binding attaches methods directly to elements, so imperative code and action chains share one implementation.
|
|
386
|
+
|
|
387
|
+
| Method | Available On | Description |
|
|
388
|
+
| ------ | ------------ | ----------- |
|
|
389
|
+
| `getValue()` | any bound element | Reads the value through the value pipeline |
|
|
390
|
+
| `setValue(value)` | any bound element | Writes the value and dispatches input and change |
|
|
391
|
+
| `read()` | any bound element | Re-reads the element's scope |
|
|
392
|
+
| `save()` | any bound element or form | Persists the element or the whole form |
|
|
393
|
+
| `getData()` | forms | Returns the assembled payload without saving |
|
|
394
|
+
| `getFilter()` / `setFilter()` | filtered elements | Reads or replaces the active filter, re-reading the scope |
|
|
395
|
+
|
|
396
|
+
```javascript
|
|
397
|
+
const form = document.querySelector("#profile");
|
|
398
|
+
const payload = await form.getData();
|
|
399
|
+
await form.save();
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## JavaScript API
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
import elements from "@cocreate/elements";
|
|
408
|
+
|
|
409
|
+
elements.init();
|
|
410
|
+
elements.init(document.querySelector("#profile"));
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
| Method | Description |
|
|
414
|
+
| ------ | ----------- |
|
|
415
|
+
| `init(element)` | Initializes an element, a collection, or the whole document |
|
|
416
|
+
| `read(element, data, dataKey)` | Reads a scope and distributes the result |
|
|
417
|
+
| `save(element, action)` | Persists an element or form |
|
|
418
|
+
| `getData(element)` | Assembles the payload for an element or form |
|
|
419
|
+
| `getDataObject(element)` | Normalizes an element's attributes into a CRUD payload |
|
|
420
|
+
| `reset(action)` | Runs reset logic for a form |
|
|
421
|
+
| `setDataType(element, data, action)` | Applies a created record's id back into the markup |
|
|
422
|
+
| `elements`, `keys`, `forms` | Internal registries of bound elements and scopes |
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Behavior Notes
|
|
427
|
+
|
|
428
|
+
* An element must declare `storage`, `database`, or `array` to be initialized. A lone `object` or `key` is not a binding, which is why fields inside a form rely on inherited scope.
|
|
429
|
+
* Reads are debounced for 500ms and deduplicated per scope, so many elements binding one document produce a single query.
|
|
430
|
+
* An element reads once per scope. Changing a filter or calling `read()` resets that state.
|
|
431
|
+
* A document id must be a 24 character hexadecimal value, or the placeholders `pending` and `ObjectId()`.
|
|
432
|
+
* Elements rendered on the server carry a `rendered` marker and skip their first client render, preserving server output.
|
|
433
|
+
* Save on input requires `realtime`, and never applies to a `_id` field.
|
|
434
|
+
* When `crdt` is enabled and a document id exists, text edits merge collaboratively rather than overwriting.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Announcements
|
|
439
|
+
|
|
440
|
+
All updates to this library are documented in our [CHANGELOG](https://github.com/CoCreateJS/elements/blob/master/CHANGELOG.md) and [releases](https://github.com/CoCreateJS/elements/releases). You may also subscribe to email for releases and breaking changes.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Roadmap
|
|
445
|
+
|
|
446
|
+
Upcoming enhancements include:
|
|
447
|
+
|
|
448
|
+
* Expanded array mutation operators
|
|
449
|
+
* Optimistic write rollback on failure
|
|
450
|
+
* Schema-aware value coercion
|
|
451
|
+
* Development mode diagnostics for unbound and misconfigured scopes
|
|
452
|
+
* Devtools inspection of an element's scope and subscriptions
|
|
453
|
+
|
|
454
|
+
If you are interested in the future direction of this project, please take a look at our open [issues](https://github.com/CoCreateJS/elements/issues) and [pull requests](https://github.com/CoCreateJS/elements/pulls). We would love to hear your feedback.
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## How to Contribute
|
|
459
|
+
|
|
460
|
+
We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](https://github.com/CoCreateJS/elements/blob/master/CONTRIBUTING.md) guide for details.
|
|
461
|
+
|
|
462
|
+
We want this library to be community-driven, and CoCreate led. We need your help to realize this goal. To help make sure we are building the right things in the right order, we ask that you create [issues](https://github.com/CoCreateJS/elements/issues) and [pull requests](https://github.com/CoCreateJS/elements/pulls) or merely upvote or comment on existing issues or pull requests.
|
|
78
463
|
|
|
79
464
|
We appreciate your continued support, thank you!
|
|
80
465
|
|
|
81
|
-
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## About
|
|
469
|
+
|
|
470
|
+
CoCreate-elements is guided and supported by the CoCreate Developer Experience Team.
|
|
471
|
+
|
|
472
|
+
Please Email the Developer Experience Team [here](mailto:develop@CoCreateJS.com) in case of any queries.
|
|
473
|
+
|
|
474
|
+
CoCreate-elements is maintained and funded by CoCreate. The names and logos for CoCreate are trademarks of CoCreate, LLC.
|
|
475
|
+
|
|
476
|
+
---
|
|
82
477
|
|
|
83
|
-
|
|
478
|
+
## License
|
|
84
479
|
|
|
85
480
|
This software is dual-licensed under the GNU Affero General Public License version 3 (AGPLv3) and a commercial license.
|
|
86
481
|
|
|
87
|
-
|
|
482
|
+
* **Open Source Use**: For open-source projects and non-commercial use, this software is available under the AGPLv3. The AGPLv3 allows you to freely use, modify, and distribute this software, provided that all modifications and derivative works are also licensed under the AGPLv3. For the full license text, see the [LICENSE file](https://github.com/CoCreateJS/elements/blob/master/LICENSE).
|
|
88
483
|
|
|
89
|
-
|
|
484
|
+
* **Commercial Use**: For-profit companies and individuals intending to use this software for commercial purposes must obtain a commercial license. The commercial license is available when you sign up for an API key on our [website](https://CoCreateJS.com). This license permits proprietary use and modification of the software without the copyleft requirements of the AGPLv3. It is ideal for integrating this software into proprietary commercial products and applications.
|
|
90
485
|
|
|
91
486
|
If you have not purchased a commercial license and intend to use this software for commercial purposes, you are required to sign up for an API key on our website.
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
### Enter shortcuts for action buttons
|
|
490
|
+
|
|
491
|
+
Set `submit-query` on a form or an inner section to explicitly select the action
|
|
492
|
+
element Enter should click from a single-line input:
|
|
493
|
+
|
|
494
|
+
```html
|
|
495
|
+
<form>
|
|
496
|
+
<section submit-query="#next-step">
|
|
497
|
+
<input name="name" />
|
|
498
|
+
<button id="next-step" type="button" actions="disabled, validate, save, disabled">Next</button>
|
|
499
|
+
</section>
|
|
500
|
+
</form>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
The nearest `submit-query` within the form wins. Its value uses CoCreate query
|
|
504
|
+
selectors, resolved from the element carrying the attribute. The resolved
|
|
505
|
+
target must have `actions`, belong to the same form, and be visible and enabled.
|
|
506
|
+
No action target is inferred when the attribute is absent. Empty or unresolved
|
|
507
|
+
queries, multiple returned targets, and disabled targets do not fall through to
|
|
508
|
+
native submission. Held Enter does not repeatedly activate the button.
|
|
509
|
+
|
|
510
|
+
Textareas, selects, editable content, input widgets, composition, modified
|
|
511
|
+
keystrokes, and events already handled by another listener keep their normal
|
|
512
|
+
keyboard behavior. This shortcut calls `.click()`; it does not submit the form
|
|
513
|
+
itself. Existing `action`/`method` handling remains separate, and a submit button
|
|
514
|
+
with `actions` can still preprocess an external submission through its chain.
|
package/demo/index.html
CHANGED
|
@@ -195,6 +195,6 @@
|
|
|
195
195
|
|
|
196
196
|
<!-- <script src="../dist/CoCreate-elements.js"></script> -->
|
|
197
197
|
<!-- <script src="../../../CoCreateJS/dist/CoCreate.js"></script> -->
|
|
198
|
-
<script src="https://
|
|
198
|
+
<script src="https://CoCreateJS.com/dist/CoCreate.js"></script>
|
|
199
199
|
</body>
|
|
200
200
|
</html>
|
package/docs/index.html
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<meta name="robots" content="index,follow" />
|
|
14
14
|
<meta
|
|
15
15
|
property="og:image"
|
|
16
|
-
content="https://cdn.
|
|
16
|
+
content="https://cdn.CoCreateJS.com/docs/elements.png" />
|
|
17
17
|
|
|
18
18
|
<title>CoCreate-elements Documentation | CoCreateJS</title>
|
|
19
19
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
rel="icon"
|
|
23
23
|
type="image/png"
|
|
24
24
|
sizes="32x32"
|
|
25
|
-
href="https://
|
|
25
|
+
href="https://CoCreateJS.com/images/favicon.ico" />
|
|
26
26
|
<link
|
|
27
27
|
rel="stylesheet"
|
|
28
28
|
href="../index.css"
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
share-title="CoCreate elements"
|
|
76
76
|
share-height="600"
|
|
77
77
|
share-width="700"
|
|
78
|
-
share-media="https://cdn.
|
|
78
|
+
share-media="https://cdn.CoCreateJS.com/docs/elements.png"
|
|
79
79
|
hover="display:block!important"
|
|
80
80
|
hover-query=".social-networks">
|
|
81
81
|
<div class="display:none social-networks">
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
></a>
|
|
107
107
|
</div>
|
|
108
108
|
<a
|
|
109
|
-
href="https://github.com/
|
|
109
|
+
href="https://github.com/CoCreateJS/CoCreate-elements"
|
|
110
110
|
target="_blank"
|
|
111
111
|
class="margin-right:15px"
|
|
112
112
|
><i src="/assets/svg/github.svg"></i
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
<p class="padding:10px_0px line-height:1.5">
|
|
146
146
|
Or you can use cdn link:
|
|
147
147
|
</p>
|
|
148
|
-
<pre><code class="language-html"><script>https://cdn.
|
|
148
|
+
<pre><code class="language-html"><script>https://cdn.CoCreateJS.com/elements/latest/CoCreate-elements.min.js</script></code></pre>
|
|
149
149
|
|
|
150
150
|
<div
|
|
151
151
|
id="elements-usage"
|
|
@@ -330,13 +330,13 @@
|
|
|
330
330
|
</div>
|
|
331
331
|
</div>
|
|
332
332
|
<button
|
|
333
|
-
href="https://github.com/
|
|
333
|
+
href="https://github.com/CoCreateJS/CoCreate-elements/tree/master/docs/index.html?message=docs%3A%20describe%20your%20change..."
|
|
334
334
|
target="_blank"
|
|
335
335
|
class="display:flex justify-content:center align-items:center position:fixed bottom:15px right:15px height:50px width:50px border-radius:50% box-shadow:0px_2px_10px_0px_rgba(0,_0,_0,_0.4)">
|
|
336
336
|
<i src="../assets/svg/pencil-alt.svg"></i>
|
|
337
337
|
</button>
|
|
338
338
|
</main>
|
|
339
339
|
|
|
340
|
-
<script src="https://
|
|
340
|
+
<script src="https://CoCreateJS.com/dist/CoCreate.js"></script>
|
|
341
341
|
</body>
|
|
342
342
|
</html>
|