@almadar/std 16.182.0 → 16.184.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/behaviors/lolo/infra/atoms/std-migration-job.lolo +2 -2
- package/behaviors/lolo/ui/core/.hand-authored.json +4 -0
- package/behaviors/lolo/ui/core/atoms/std-browse.lolo +11 -0
- package/behaviors/lolo/ui/core/atoms/std-related.lolo +86 -9
- package/behaviors/lolo/ui/core/atoms/std-rich-editor.lolo +115 -1
- package/behaviors/lolo/ui/core/atoms/std-tag-taxonomy.lolo +62 -2
- package/behaviors/lolo/ui/core/atoms/std-thread.lolo +43 -2
- package/behaviors/lolo/ui/core/atoms/std-tree.lolo +247 -0
- package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +110 -2
- package/behaviors/lolo/ui/core/molecules/ui-file-tree.lolo +18 -2
- package/behaviors/lolo/ui/core/organisms/ui-detail-panel.lolo +6 -2
- package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +2 -2
- package/behaviors/lolo/ui/core/organisms/ui-form.lolo +2 -2
- package/behaviors/lolo/ui/game/atoms/std-fx-trail.lolo +63 -0
- package/behaviors/lolo/ui/game/atoms/std-gate-lock.lolo +96 -0
- package/behaviors/lolo/ui/game/atoms/std-lives.lolo +121 -0
- package/behaviors/lolo/ui/game/atoms/std-patrol-hazard.lolo +96 -0
- package/behaviors/lolo/ui/game/atoms/std-tutorial-autodemo.lolo +136 -0
- package/behaviors/lolo/ui/game/atoms/std-tutorial-overlay.lolo +197 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-slope-probe.lolo +117 -0
- package/behaviors/lolo/ui/learning/atoms/ui-math-canvas.lolo +18 -0
- package/behaviors/registry/infra/atoms/std-migration-job.orb +2 -2
- package/behaviors/registry/ui/core/atoms/std-browse.orb +17 -0
- package/behaviors/registry/ui/core/atoms/std-related.orb +256 -3
- package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +407 -1
- package/behaviors/registry/ui/core/atoms/std-tag-taxonomy.orb +240 -8
- package/behaviors/registry/ui/core/atoms/std-thread.orb +254 -4
- package/behaviors/registry/ui/core/atoms/std-tree.orb +656 -0
- package/behaviors/registry/ui/core/atoms/std-version-history.orb +479 -6
- package/behaviors/registry/ui/core/molecules/ui-file-tree.orb +43 -19
- package/behaviors/registry/ui/core/organisms/ui-detail-panel.orb +28 -3
- package/behaviors/registry/ui/core/organisms/ui-form-section.orb +8 -2
- package/behaviors/registry/ui/core/organisms/ui-form.orb +8 -2
- package/behaviors/registry/ui/game/atoms/std-fx-trail.orb +376 -0
- package/behaviors/registry/ui/game/atoms/std-gate-lock.orb +852 -0
- package/behaviors/registry/ui/game/atoms/std-lives.orb +739 -0
- package/behaviors/registry/ui/game/atoms/std-patrol-hazard.orb +768 -0
- package/behaviors/registry/ui/game/atoms/std-tutorial-autodemo.orb +732 -0
- package/behaviors/registry/ui/game/atoms/std-tutorial-overlay.orb +1212 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-slope-probe.orb +908 -0
- package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +26 -0
- package/dist/behaviors/exports-reader.js +5478 -2954
- package/dist/behaviors/functions/index.d.ts +763 -15
- package/dist/behaviors/functions/index.js +5447 -2953
- package/dist/behaviors/index.d.ts +1 -1
- package/dist/behaviors/index.js +5479 -2955
- package/dist/behaviors/query.js +5478 -2954
- package/dist/behaviors-embeddings.hash.json +3 -3
- package/dist/behaviors-embeddings.json +362 -330
- package/dist/behaviors-registry.json +2812 -542
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5479 -2955
- package/dist/knob-embeddings.hash.json +3 -3
- package/dist/knob-embeddings.json +1 -1
- package/dist/registry/factory-signatures.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
app std-tree "1.0.0"
|
|
2
|
+
"std-tree — generic hierarchical node browser. Fetches a flat TreeNode collection and renders it through file-tree's flat `items` mode (parentId-nested at render time by the component, not the .lolo); OPEN_NODE is the external handoff for a selected node's id. Rebindable: pass `fields` at the call site to retarget it at any parent-pointer entity (categories, org units, comment threads)."
|
|
3
|
+
orbital TreeNodeOrbital {
|
|
4
|
+
type TreeNodeLoaded = Event { data : [TreeNode] } "Fired when the tree node collection finishes loading"
|
|
5
|
+
|
|
6
|
+
type TreeNodeLoadFailed = Event { error : string, code : string } "Fired when the tree node collection fails to load"
|
|
7
|
+
|
|
8
|
+
entity TreeNode [persistent: treenodes] {
|
|
9
|
+
id : string!
|
|
10
|
+
name : string! @description "The descriptive label for this node." @synonyms "label, title, text"
|
|
11
|
+
parentId : string @description "Reference to the parent node in the hierarchy; empty marks a root." @synonyms "parent, superior, ancestor" = ""
|
|
12
|
+
icon : string @description "Icon name shown beside the node." @synonyms "glyph, symbol, pictogram" = ""
|
|
13
|
+
createdAt : string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
trait TreeBrowse -> @rebindable TreeNode [interaction, collection] {
|
|
17
|
+
initial: loading
|
|
18
|
+
|
|
19
|
+
state loading {
|
|
20
|
+
INIT -> loading
|
|
21
|
+
(fetch TreeNode {
|
|
22
|
+
emit: { failure: TreeNodeLoadFailed, success: TreeNodeLoaded }
|
|
23
|
+
})
|
|
24
|
+
(render-ui main {
|
|
25
|
+
align: center
|
|
26
|
+
children: [{ type: spinner }, {
|
|
27
|
+
color: muted
|
|
28
|
+
content: "Loading tree…"
|
|
29
|
+
type: typography
|
|
30
|
+
variant: caption
|
|
31
|
+
}]
|
|
32
|
+
className: py-12
|
|
33
|
+
direction: vertical
|
|
34
|
+
gap: md
|
|
35
|
+
type: stack
|
|
36
|
+
})
|
|
37
|
+
TreeNodeLoaded -> browsing
|
|
38
|
+
(render-ui main {
|
|
39
|
+
children: [{
|
|
40
|
+
align: center
|
|
41
|
+
children: [{ name: list-tree, type: icon }, {
|
|
42
|
+
content: @config.title
|
|
43
|
+
type: typography
|
|
44
|
+
variant: h3
|
|
45
|
+
}, {
|
|
46
|
+
label: (array/len ?data)
|
|
47
|
+
size: sm
|
|
48
|
+
type: badge
|
|
49
|
+
variant: neutral
|
|
50
|
+
}]
|
|
51
|
+
direction: horizontal
|
|
52
|
+
gap: sm
|
|
53
|
+
type: stack
|
|
54
|
+
}, { type: divider }, {
|
|
55
|
+
items: (array/map ?data (fn row {
|
|
56
|
+
icon: @row.icon
|
|
57
|
+
id: @row.id
|
|
58
|
+
label: @row.name
|
|
59
|
+
parentId: @row.parentId
|
|
60
|
+
}))
|
|
61
|
+
onNodeSelect: OPEN_NODE
|
|
62
|
+
type: file-tree
|
|
63
|
+
}]
|
|
64
|
+
direction: vertical
|
|
65
|
+
gap: md
|
|
66
|
+
type: stack
|
|
67
|
+
})
|
|
68
|
+
TreeNodeLoadFailed -> error
|
|
69
|
+
(render-ui main {
|
|
70
|
+
align: center
|
|
71
|
+
children: [{
|
|
72
|
+
color: error
|
|
73
|
+
name: alert-triangle
|
|
74
|
+
type: icon
|
|
75
|
+
}, {
|
|
76
|
+
content: "Failed to load tree"
|
|
77
|
+
type: typography
|
|
78
|
+
variant: body
|
|
79
|
+
}, {
|
|
80
|
+
color: muted
|
|
81
|
+
content: ?error
|
|
82
|
+
type: typography
|
|
83
|
+
variant: caption
|
|
84
|
+
}, {
|
|
85
|
+
action: RETRY
|
|
86
|
+
icon: rotate-ccw
|
|
87
|
+
label: Retry
|
|
88
|
+
type: button
|
|
89
|
+
variant: ghost
|
|
90
|
+
}]
|
|
91
|
+
className: py-8
|
|
92
|
+
direction: vertical
|
|
93
|
+
gap: sm
|
|
94
|
+
type: stack
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
state browsing {
|
|
99
|
+
INIT -> loading
|
|
100
|
+
(fetch TreeNode {
|
|
101
|
+
emit: { failure: TreeNodeLoadFailed, success: TreeNodeLoaded }
|
|
102
|
+
})
|
|
103
|
+
(render-ui main {
|
|
104
|
+
align: center
|
|
105
|
+
children: [{ type: spinner }, {
|
|
106
|
+
color: muted
|
|
107
|
+
content: "Loading tree…"
|
|
108
|
+
type: typography
|
|
109
|
+
variant: caption
|
|
110
|
+
}]
|
|
111
|
+
className: py-12
|
|
112
|
+
direction: vertical
|
|
113
|
+
gap: md
|
|
114
|
+
type: stack
|
|
115
|
+
})
|
|
116
|
+
OPEN_NODE -> browsing
|
|
117
|
+
(set @entity.id ?id)
|
|
118
|
+
TreeNodeLoaded -> browsing
|
|
119
|
+
(render-ui main {
|
|
120
|
+
children: [{
|
|
121
|
+
align: center
|
|
122
|
+
children: [{ name: list-tree, type: icon }, {
|
|
123
|
+
content: @config.title
|
|
124
|
+
type: typography
|
|
125
|
+
variant: h3
|
|
126
|
+
}, {
|
|
127
|
+
label: (array/len ?data)
|
|
128
|
+
size: sm
|
|
129
|
+
type: badge
|
|
130
|
+
variant: neutral
|
|
131
|
+
}]
|
|
132
|
+
direction: horizontal
|
|
133
|
+
gap: sm
|
|
134
|
+
type: stack
|
|
135
|
+
}, { type: divider }, {
|
|
136
|
+
items: (array/map ?data (fn row {
|
|
137
|
+
icon: @row.icon
|
|
138
|
+
id: @row.id
|
|
139
|
+
label: @row.name
|
|
140
|
+
parentId: @row.parentId
|
|
141
|
+
}))
|
|
142
|
+
onNodeSelect: OPEN_NODE
|
|
143
|
+
type: file-tree
|
|
144
|
+
}]
|
|
145
|
+
direction: vertical
|
|
146
|
+
gap: md
|
|
147
|
+
type: stack
|
|
148
|
+
})
|
|
149
|
+
TreeNodeLoadFailed -> error
|
|
150
|
+
(render-ui main {
|
|
151
|
+
align: center
|
|
152
|
+
children: [{
|
|
153
|
+
color: error
|
|
154
|
+
name: alert-triangle
|
|
155
|
+
type: icon
|
|
156
|
+
}, {
|
|
157
|
+
content: "Failed to load tree"
|
|
158
|
+
type: typography
|
|
159
|
+
variant: body
|
|
160
|
+
}, {
|
|
161
|
+
color: muted
|
|
162
|
+
content: ?error
|
|
163
|
+
type: typography
|
|
164
|
+
variant: caption
|
|
165
|
+
}, {
|
|
166
|
+
action: RETRY
|
|
167
|
+
icon: rotate-ccw
|
|
168
|
+
label: Retry
|
|
169
|
+
type: button
|
|
170
|
+
variant: ghost
|
|
171
|
+
}]
|
|
172
|
+
className: py-8
|
|
173
|
+
direction: vertical
|
|
174
|
+
gap: sm
|
|
175
|
+
type: stack
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
state error {
|
|
180
|
+
INIT -> loading
|
|
181
|
+
(fetch TreeNode {
|
|
182
|
+
emit: { failure: TreeNodeLoadFailed, success: TreeNodeLoaded }
|
|
183
|
+
})
|
|
184
|
+
(render-ui main { type: spinner })
|
|
185
|
+
;; the error screen's Retry button: INIT is lifecycle-only and the bus never
|
|
186
|
+
;; delivers it, so the affordance must target a first-class user event
|
|
187
|
+
RETRY -> loading
|
|
188
|
+
(fetch TreeNode {
|
|
189
|
+
emit: { failure: TreeNodeLoadFailed, success: TreeNodeLoaded }
|
|
190
|
+
})
|
|
191
|
+
(render-ui main { type: spinner })
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
emits {
|
|
195
|
+
OPEN_NODE {
|
|
196
|
+
id : string!
|
|
197
|
+
}
|
|
198
|
+
@description "Signals a tree node has been selected for external handoff."
|
|
199
|
+
@synonyms "select, choose, open, activate"
|
|
200
|
+
@tier "domain"
|
|
201
|
+
TreeNodeLoaded {
|
|
202
|
+
data : [TreeNode]
|
|
203
|
+
}
|
|
204
|
+
@description "Indicates the tree node collection has been successfully retrieved."
|
|
205
|
+
@synonyms "loaded, fetched, retrieved, ready"
|
|
206
|
+
@tier "domain"
|
|
207
|
+
TreeNodeLoadFailed {
|
|
208
|
+
error : string
|
|
209
|
+
code : string
|
|
210
|
+
}
|
|
211
|
+
@description "Indicates a failure to load the tree node collection."
|
|
212
|
+
@synonyms "error, failed, problem, unsuccessful"
|
|
213
|
+
@tier "internal"
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
listens {
|
|
217
|
+
OPEN_NODE {
|
|
218
|
+
id : string!
|
|
219
|
+
}
|
|
220
|
+
@description "A tree node was selected for external handoff."
|
|
221
|
+
@synonyms "select, choose, open, activate"
|
|
222
|
+
@tier "domain"
|
|
223
|
+
TreeNodeLoaded {
|
|
224
|
+
data : [TreeNode]
|
|
225
|
+
}
|
|
226
|
+
@description "Indicates the tree node collection has been successfully retrieved."
|
|
227
|
+
@synonyms "loaded, fetched, retrieved, ready"
|
|
228
|
+
@tier "domain"
|
|
229
|
+
TreeNodeLoadFailed {
|
|
230
|
+
error : string
|
|
231
|
+
code : string
|
|
232
|
+
}
|
|
233
|
+
@description "Indicates a failure to load the tree node collection."
|
|
234
|
+
@synonyms "error, failed, problem, unsuccessful"
|
|
235
|
+
@tier "internal"
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
config {
|
|
239
|
+
title : string = Tree
|
|
240
|
+
@label "Section title"
|
|
241
|
+
@description "Heading shown above the tree"
|
|
242
|
+
@tier "presentation"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
page "/tree" as TreePage -> TreeBrowse
|
|
247
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
app std-version-history "1.0.0"
|
|
2
|
-
"std-version-history — wiki/CMS revision history with diff + rollback. Browses revisions; opens detail in `viewing_single`; compares two revisions in `comparing` with intrinsic version-diff; persists rollback."
|
|
2
|
+
"std-version-history — wiki/CMS revision history with diff + rollback. Browses revisions; opens detail in `viewing_single`; compares two revisions in `comparing` with intrinsic version-diff; persists rollback. `RevisionManage` is a rebindable single-entity trait: a consumer rebinds it to its own entity via `linkedEntity`. `config.scopeField` names the Revision field holding the parent document id; a page-mounted `{id}` route param scopes INIT's own fetch, and a consumer forwards SHOW_HISTORY { key } (via a `listens` override) to rescope the feed to one document — empty scopeField (default) or no id keeps today's unfiltered global feed. Rollback and retry refetches stay scoped."
|
|
3
3
|
orbital RevisionOrbital {
|
|
4
4
|
type RevisionLoaded = Event { data : [Revision] } "Fired when the revision collection finishes loading"
|
|
5
5
|
|
|
@@ -20,14 +20,17 @@ orbital RevisionOrbital {
|
|
|
20
20
|
summary : string @description "A brief explanation of the revision's changes." @synonyms "description, note, comment, explanation"
|
|
21
21
|
searchTerm : string @description "The current search query the user submitted." @synonyms "query, term, q" = ""
|
|
22
22
|
createdAt : string
|
|
23
|
+
scopeKey : string @intrinsic @description "The parent document id the feed is currently scoped to, set by SHOW_HISTORY. Empty when browsing the unfiltered global feed." @synonyms "scope, filter key, document scope" = ""
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
trait RevisionManage -> Revision [interaction, collection] {
|
|
26
|
+
trait RevisionManage -> @rebindable Revision [interaction, collection] {
|
|
26
27
|
initial: loading
|
|
27
28
|
|
|
28
29
|
state loading {
|
|
29
30
|
INIT -> loading
|
|
31
|
+
(set @entity.scopeKey (str/default ?id ""))
|
|
30
32
|
(fetch Revision {
|
|
33
|
+
filter: (or ["=", @config.scopeField, ""] ["=", (str/default ?id ""), ""] ["=", (object/get @entity @config.scopeField), ?id])
|
|
31
34
|
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
32
35
|
})
|
|
33
36
|
(render-ui main {
|
|
@@ -95,7 +98,9 @@ orbital RevisionOrbital {
|
|
|
95
98
|
type: stack
|
|
96
99
|
})
|
|
97
100
|
RevisionRolledBack -> loading
|
|
101
|
+
(set @entity.scopeKey (object/get ?row @config.scopeField ""))
|
|
98
102
|
(fetch Revision {
|
|
103
|
+
filter: (or ["=", @config.scopeField, ""] ["=", (object/get ?row @config.scopeField ""), ""] ["=", (object/get @entity @config.scopeField), (object/get ?row @config.scopeField "")])
|
|
99
104
|
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
100
105
|
})
|
|
101
106
|
RevisionRollbackFailed -> error
|
|
@@ -110,11 +115,32 @@ orbital RevisionOrbital {
|
|
|
110
115
|
type: alert
|
|
111
116
|
variant: error
|
|
112
117
|
})
|
|
118
|
+
SHOW_HISTORY -> loading
|
|
119
|
+
(set @entity.scopeKey ?key)
|
|
120
|
+
(fetch Revision {
|
|
121
|
+
filter: ["=", (object/get @entity @config.scopeField), ?key]
|
|
122
|
+
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
123
|
+
})
|
|
124
|
+
(render-ui main {
|
|
125
|
+
align: center
|
|
126
|
+
children: [{ type: spinner }, {
|
|
127
|
+
color: muted
|
|
128
|
+
content: "Loading version history…"
|
|
129
|
+
type: typography
|
|
130
|
+
variant: caption
|
|
131
|
+
}]
|
|
132
|
+
className: py-12
|
|
133
|
+
direction: vertical
|
|
134
|
+
gap: md
|
|
135
|
+
type: stack
|
|
136
|
+
})
|
|
113
137
|
}
|
|
114
138
|
|
|
115
139
|
state browsing {
|
|
116
140
|
INIT -> loading
|
|
141
|
+
(set @entity.scopeKey (str/default ?id ""))
|
|
117
142
|
(fetch Revision {
|
|
143
|
+
filter: (or ["=", @config.scopeField, ""] ["=", (str/default ?id ""), ""] ["=", (object/get @entity @config.scopeField), ?id])
|
|
118
144
|
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
119
145
|
})
|
|
120
146
|
(render-ui main {
|
|
@@ -270,6 +296,25 @@ orbital RevisionOrbital {
|
|
|
270
296
|
gap: md
|
|
271
297
|
type: stack
|
|
272
298
|
})
|
|
299
|
+
SHOW_HISTORY -> loading
|
|
300
|
+
(set @entity.scopeKey ?key)
|
|
301
|
+
(fetch Revision {
|
|
302
|
+
filter: ["=", (object/get @entity @config.scopeField), ?key]
|
|
303
|
+
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
304
|
+
})
|
|
305
|
+
(render-ui main {
|
|
306
|
+
align: center
|
|
307
|
+
children: [{ type: spinner }, {
|
|
308
|
+
color: muted
|
|
309
|
+
content: "Loading version history…"
|
|
310
|
+
type: typography
|
|
311
|
+
variant: caption
|
|
312
|
+
}]
|
|
313
|
+
className: py-12
|
|
314
|
+
direction: vertical
|
|
315
|
+
gap: md
|
|
316
|
+
type: stack
|
|
317
|
+
})
|
|
273
318
|
}
|
|
274
319
|
|
|
275
320
|
state viewing_single {
|
|
@@ -350,6 +395,25 @@ orbital RevisionOrbital {
|
|
|
350
395
|
gap: md
|
|
351
396
|
type: stack
|
|
352
397
|
})
|
|
398
|
+
SHOW_HISTORY -> loading
|
|
399
|
+
(set @entity.scopeKey ?key)
|
|
400
|
+
(fetch Revision {
|
|
401
|
+
filter: ["=", (object/get @entity @config.scopeField), ?key]
|
|
402
|
+
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
403
|
+
})
|
|
404
|
+
(render-ui main {
|
|
405
|
+
align: center
|
|
406
|
+
children: [{ type: spinner }, {
|
|
407
|
+
color: muted
|
|
408
|
+
content: "Loading version history…"
|
|
409
|
+
type: typography
|
|
410
|
+
variant: caption
|
|
411
|
+
}]
|
|
412
|
+
className: py-12
|
|
413
|
+
direction: vertical
|
|
414
|
+
gap: md
|
|
415
|
+
type: stack
|
|
416
|
+
})
|
|
353
417
|
}
|
|
354
418
|
|
|
355
419
|
state comparing {
|
|
@@ -388,11 +452,39 @@ orbital RevisionOrbital {
|
|
|
388
452
|
gap: md
|
|
389
453
|
type: stack
|
|
390
454
|
})
|
|
455
|
+
SHOW_HISTORY -> loading
|
|
456
|
+
(set @entity.scopeKey ?key)
|
|
457
|
+
(fetch Revision {
|
|
458
|
+
filter: ["=", (object/get @entity @config.scopeField), ?key]
|
|
459
|
+
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
460
|
+
})
|
|
461
|
+
(render-ui main {
|
|
462
|
+
align: center
|
|
463
|
+
children: [{ type: spinner }, {
|
|
464
|
+
color: muted
|
|
465
|
+
content: "Loading version history…"
|
|
466
|
+
type: typography
|
|
467
|
+
variant: caption
|
|
468
|
+
}]
|
|
469
|
+
className: py-12
|
|
470
|
+
direction: vertical
|
|
471
|
+
gap: md
|
|
472
|
+
type: stack
|
|
473
|
+
})
|
|
391
474
|
}
|
|
392
475
|
|
|
393
476
|
state error {
|
|
394
477
|
INIT -> loading
|
|
478
|
+
(set @entity.scopeKey (str/default ?id ""))
|
|
395
479
|
(fetch Revision {
|
|
480
|
+
filter: (or ["=", @config.scopeField, ""] ["=", (str/default ?id ""), ""] ["=", (object/get @entity @config.scopeField), ?id])
|
|
481
|
+
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
482
|
+
})
|
|
483
|
+
(render-ui main { size: sm, type: spinner })
|
|
484
|
+
SHOW_HISTORY -> loading
|
|
485
|
+
(set @entity.scopeKey ?key)
|
|
486
|
+
(fetch Revision {
|
|
487
|
+
filter: ["=", (object/get @entity @config.scopeField), ?key]
|
|
396
488
|
emit: { failure: RevisionLoadFailed, success: RevisionLoaded }
|
|
397
489
|
})
|
|
398
490
|
(render-ui main { size: sm, type: spinner })
|
|
@@ -454,6 +546,12 @@ orbital RevisionOrbital {
|
|
|
454
546
|
}
|
|
455
547
|
|
|
456
548
|
listens {
|
|
549
|
+
INIT {
|
|
550
|
+
id : string
|
|
551
|
+
}
|
|
552
|
+
@description "Optional route param delivered on mount (e.g. an :id page segment); scopes INIT's own fetch to rows whose scopeField equals id. Absent id or empty scopeField config keeps the unfiltered global feed."
|
|
553
|
+
@synonyms "route id, deep link, initial scope"
|
|
554
|
+
@tier "domain"
|
|
457
555
|
OPEN_REVISION {
|
|
458
556
|
id : string!
|
|
459
557
|
row : Revision
|
|
@@ -506,6 +604,12 @@ orbital RevisionOrbital {
|
|
|
506
604
|
@description "Indicates that a revision rollback operation has failed."
|
|
507
605
|
@synonyms "rollback error, revert failure, undo failed"
|
|
508
606
|
@tier "internal"
|
|
607
|
+
SHOW_HISTORY {
|
|
608
|
+
key : string!
|
|
609
|
+
}
|
|
610
|
+
@description "Requests the revision feed scoped to one parent document; stores the key and refetches filtered by config.scopeField."
|
|
611
|
+
@synonyms "view history, doc history, filter revisions"
|
|
612
|
+
@tier "domain"
|
|
509
613
|
}
|
|
510
614
|
|
|
511
615
|
config {
|
|
@@ -521,6 +625,10 @@ orbital RevisionOrbital {
|
|
|
521
625
|
@label "Stat display look"
|
|
522
626
|
@description "Layer 2 visual treatment for stat / KPI cards."
|
|
523
627
|
@tier "presentation"
|
|
628
|
+
scopeField : string = ""
|
|
629
|
+
@label "Scope field"
|
|
630
|
+
@description "Revision entity field holding the parent document's id. When set, a page-mounted {id} route param scopes INIT's fetch, and a SHOW_HISTORY { key } event rescopes the feed, to rows whose scopeField equals the id/key; rollback and retry refetches stay scoped too. Empty (default) or no id = unfiltered global feed, unchanged from prior behavior."
|
|
631
|
+
@tier "domain"
|
|
524
632
|
}
|
|
525
633
|
}
|
|
526
634
|
|
|
@@ -9,6 +9,12 @@ orbital FileTreeOrbital {
|
|
|
9
9
|
size : number
|
|
10
10
|
language : string
|
|
11
11
|
}
|
|
12
|
+
type FileTreeItemsItem = {
|
|
13
|
+
id : string!
|
|
14
|
+
label : string!
|
|
15
|
+
parentId : string
|
|
16
|
+
icon : string
|
|
17
|
+
}
|
|
12
18
|
|
|
13
19
|
entity FileTreeItem [runtime] {
|
|
14
20
|
id : string!
|
|
@@ -21,8 +27,10 @@ orbital FileTreeOrbital {
|
|
|
21
27
|
INIT -> idle
|
|
22
28
|
(render-ui main {
|
|
23
29
|
tree: @config.tree
|
|
30
|
+
items: @config.items
|
|
24
31
|
selectedPath: @config.selectedPath
|
|
25
32
|
onFileSelect: @config.onFileSelect
|
|
33
|
+
onNodeSelect: @config.onNodeSelect
|
|
26
34
|
className: @config.className
|
|
27
35
|
indent: @config.indent
|
|
28
36
|
type: file-tree
|
|
@@ -38,9 +46,13 @@ orbital FileTreeOrbital {
|
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
config {
|
|
41
|
-
tree : [FileTreeTreeItem] = [
|
|
49
|
+
tree : [FileTreeTreeItem] = []
|
|
42
50
|
@label "Tree"
|
|
43
|
-
@description "The tree data"
|
|
51
|
+
@description "The tree data (pre-nested). Ignored when `items` is provided."
|
|
52
|
+
@tier "presentation"
|
|
53
|
+
items : [FileTreeItemsItem] = []
|
|
54
|
+
@label "Items"
|
|
55
|
+
@description "Flat node list, nested by `parentId` at render time — takes precedence over `tree` when provided. A `parentId` with no matching row renders that node as a root rather than dropping it."
|
|
44
56
|
@tier "presentation"
|
|
45
57
|
selectedPath : string
|
|
46
58
|
@label "Selected Path"
|
|
@@ -50,6 +62,10 @@ orbital FileTreeOrbital {
|
|
|
50
62
|
@label "On File Select"
|
|
51
63
|
@description "Called when a file is clicked"
|
|
52
64
|
@tier "presentation"
|
|
65
|
+
onNodeSelect : string = ""
|
|
66
|
+
@label "On Node Select"
|
|
67
|
+
@description "Called when a node is clicked, in flat `items` mode; carries the selected node's id. Presence-gated: binding this prop is what turns on the click-to-select affordance, mirroring Badge's `onRemove`."
|
|
68
|
+
@tier "presentation"
|
|
53
69
|
className : string
|
|
54
70
|
@label "Class Name"
|
|
55
71
|
@description "CSS class"
|
|
@@ -41,7 +41,11 @@ orbital DetailPanelOrbital {
|
|
|
41
41
|
header : string
|
|
42
42
|
type : string
|
|
43
43
|
values : [string]
|
|
44
|
-
relation :
|
|
44
|
+
relation : DetailPanelFieldsItemRelation
|
|
45
|
+
}
|
|
46
|
+
type DetailPanelFieldsItemRelation = {
|
|
47
|
+
entity : string!
|
|
48
|
+
cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
|
|
45
49
|
}
|
|
46
50
|
type DetailPanelRelationsDataValueItem = {
|
|
47
51
|
value : string!
|
|
@@ -224,7 +228,7 @@ orbital DetailPanelOrbital {
|
|
|
224
228
|
@label "Slide Over"
|
|
225
229
|
@description "slideOver prop"
|
|
226
230
|
@tier "presentation"
|
|
227
|
-
fields : [DetailPanelFieldsItem] = [{ key: "Key", header: "Header", type: "Type", values: ["Item", "Item 2"], relation: "
|
|
231
|
+
fields : [DetailPanelFieldsItem] = [{ key: "Key", header: "Header", type: "Type", values: ["Item", "Item 2"], relation: { entity: "Entity", cardinality: one } }, { key: "Key 2", header: "Header 2", type: "Type 2", values: ["Item", "Item 2"], relation: { entity: "Entity 2", cardinality: many } }]
|
|
228
232
|
@label "Fields"
|
|
229
233
|
@description "Fields to display - accepts string[], {key, header}[], or DetailField[]"
|
|
230
234
|
@tier "presentation"
|
|
@@ -29,7 +29,7 @@ orbital FormSectionOrbital {
|
|
|
29
29
|
type FormSectionFieldsItemRelation = {
|
|
30
30
|
entity : string!
|
|
31
31
|
displayField : string
|
|
32
|
-
cardinality : "one" | "many"
|
|
32
|
+
cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
|
|
33
33
|
}
|
|
34
34
|
type FormSectionFieldsItemValidation = {
|
|
35
35
|
enum : [string]
|
|
@@ -108,7 +108,7 @@ orbital FormSectionOrbital {
|
|
|
108
108
|
type FormSectionSectionsItemFieldsItemRelation = {
|
|
109
109
|
entity : string!
|
|
110
110
|
displayField : string
|
|
111
|
-
cardinality : "one" | "many"
|
|
111
|
+
cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
|
|
112
112
|
}
|
|
113
113
|
type FormSectionSectionsItemFieldsItemValidation = {
|
|
114
114
|
enum : [string]
|
|
@@ -29,7 +29,7 @@ orbital FormOrbital {
|
|
|
29
29
|
type FormFieldsItemRelation = {
|
|
30
30
|
entity : string!
|
|
31
31
|
displayField : string
|
|
32
|
-
cardinality : "one" | "many"
|
|
32
|
+
cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
|
|
33
33
|
}
|
|
34
34
|
type FormFieldsItemValidation = {
|
|
35
35
|
enum : [string]
|
|
@@ -108,7 +108,7 @@ orbital FormOrbital {
|
|
|
108
108
|
type FormSectionsItemFieldsItemRelation = {
|
|
109
109
|
entity : string!
|
|
110
110
|
displayField : string
|
|
111
|
-
cardinality : "one" | "many"
|
|
111
|
+
cardinality : "one" | "many" | "one-to-many" | "many-to-one" | "many-to-many"
|
|
112
112
|
}
|
|
113
113
|
type FormSectionsItemFieldsItemValidation = {
|
|
114
114
|
enum : [string]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
app std-fx-trail "1.0.0"
|
|
2
|
+
"Headless motion-trail mechanic: records the moving body's recent positions as timestamped dots on a [runtime, shared] entity so the render layer can draw a fading comet trail. Rides the body authority's BODY_MOVED — appends a dot only when the body's speed exceeds minSpeed (standing still leaves no trail) and prunes dots older than ttl on the same pass, so no decay tick is needed and a stopped body's trail simply stops growing (the render side fades each dot by bornAt/ttl). RESTART clears. Renders nothing."
|
|
3
|
+
orbital FxTrailOrbital {
|
|
4
|
+
type TrailDot = {
|
|
5
|
+
id : string!
|
|
6
|
+
x : number!
|
|
7
|
+
y : number!
|
|
8
|
+
bornAt : number!
|
|
9
|
+
ttl : number!
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
entity FxTrailData [runtime, shared] {
|
|
13
|
+
id : string!
|
|
14
|
+
trail : [TrailDot] = []
|
|
15
|
+
seq : number = 0
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
trait FxTrail -> @rebindable FxTrailData [lifecycle] {
|
|
19
|
+
initial: active
|
|
20
|
+
|
|
21
|
+
state active {
|
|
22
|
+
INIT -> active
|
|
23
|
+
(set @entity.trail [])
|
|
24
|
+
(set @entity.seq 0)
|
|
25
|
+
|
|
26
|
+
BODY_MOVED -> active when @config.running
|
|
27
|
+
(set @entity.trail
|
|
28
|
+
(array/filter
|
|
29
|
+
(if (> @payload.speed @config.minSpeed)
|
|
30
|
+
(array/concat @entity.trail [ { id: (str/concat "trail-" (+ @entity.seq 1)), x: @payload.x, y: @payload.y, bornAt: (time/now), ttl: @config.ttl } ])
|
|
31
|
+
@entity.trail)
|
|
32
|
+
(fn d (< (- (time/now) (object/get @d bornAt)) (object/get @d ttl)))))
|
|
33
|
+
(if (> @payload.speed @config.minSpeed)
|
|
34
|
+
(set @entity.seq (+ @entity.seq 1))
|
|
35
|
+
null)
|
|
36
|
+
|
|
37
|
+
RESTART -> active
|
|
38
|
+
(set @entity.trail [])
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
listens {
|
|
42
|
+
BODY_MOVED { x : number!, y : number!, vx : number!, vy : number!, grounded : boolean!, skating : boolean!, speed : number! }
|
|
43
|
+
RESTART { id : string }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
config {
|
|
47
|
+
running : boolean = true
|
|
48
|
+
@label "Running"
|
|
49
|
+
@description "When true, BODY_MOVED appends trail dots; toggle to freeze the trail (existing dots still age out)."
|
|
50
|
+
@tier "domain"
|
|
51
|
+
ttl : number = 600
|
|
52
|
+
@label "Trail Ttl (ms)"
|
|
53
|
+
@description "Milliseconds a trail dot lives; at a 33ms move cadence ~600ms keeps the last eighteen positions. The ttl is also the natural length cap — no separate limit needed."
|
|
54
|
+
@tier "presentation"
|
|
55
|
+
minSpeed : number = 0.5
|
|
56
|
+
@label "Min Speed"
|
|
57
|
+
@description "Body speed (units/s, from BODY_MOVED) below which no dot is appended, so a resting body doesn't pile dots on one spot."
|
|
58
|
+
@tier "domain"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
page "/fx-trail" as FxTrailPage -> FxTrail
|
|
63
|
+
}
|