@almadar/std 16.187.0 → 16.189.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 (102) hide show
  1. package/behaviors/lolo/ui/core/.hand-authored.json +4 -4
  2. package/behaviors/lolo/ui/core/atoms/std-board.lolo +138 -4
  3. package/behaviors/lolo/ui/core/atoms/std-browse.lolo +148 -8
  4. package/behaviors/lolo/ui/core/atoms/std-calendar.lolo +161 -11
  5. package/behaviors/lolo/ui/core/atoms/std-event-log.lolo +255 -2
  6. package/behaviors/lolo/ui/core/atoms/std-gallery.lolo +148 -1
  7. package/behaviors/lolo/ui/core/atoms/std-list.lolo +193 -1
  8. package/behaviors/lolo/ui/core/atoms/std-record-detail.lolo +731 -0
  9. package/behaviors/lolo/ui/core/atoms/std-related.lolo +5 -1
  10. package/behaviors/lolo/ui/core/atoms/std-selection.lolo +182 -1
  11. package/behaviors/lolo/ui/core/atoms/std-tree.lolo +113 -3
  12. package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +1 -1
  13. package/behaviors/lolo/ui/core/molecules/ui-document-details.lolo +80 -0
  14. package/behaviors/lolo/ui/core/molecules/ui-document-panel.lolo +213 -0
  15. package/behaviors/lolo/ui/core/molecules/{ui-rich-block-editor.lolo → ui-rich-text-editor.lolo} +25 -25
  16. package/behaviors/lolo/ui/game/atoms/std-area-fill.lolo +93 -0
  17. package/behaviors/lolo/ui/game/atoms/std-choice-gate.lolo +100 -0
  18. package/behaviors/lolo/ui/game/atoms/std-coef-pad.lolo +114 -0
  19. package/behaviors/lolo/ui/game/atoms/std-curve-fog.lolo +50 -0
  20. package/behaviors/lolo/ui/game/atoms/std-loop-lock.lolo +79 -0
  21. package/behaviors/lolo/ui/game/atoms/std-pad-lock.lolo +97 -0
  22. package/behaviors/lolo/ui/game/atoms/std-patrol-hazard.lolo +14 -7
  23. package/behaviors/lolo/ui/game/atoms/std-platformer-body.lolo +48 -5
  24. package/behaviors/lolo/ui/game/atoms/std-velocity-gate.lolo +101 -0
  25. package/behaviors/lolo/ui/game/atoms/std-zone-card.lolo +95 -0
  26. package/behaviors/lolo/ui/game/organisms/std-platformer-board-2d.lolo +9 -0
  27. package/behaviors/registry/infra/atoms/std-approval-gate.orb +16 -8
  28. package/behaviors/registry/infra/atoms/std-cache-aside.orb +62 -31
  29. package/behaviors/registry/infra/atoms/std-circuit-breaker.orb +32 -16
  30. package/behaviors/registry/infra/atoms/std-data-erasure.orb +16 -8
  31. package/behaviors/registry/infra/atoms/std-mod-queue.orb +16 -8
  32. package/behaviors/registry/infra/atoms/std-rate-limiter.orb +28 -14
  33. package/behaviors/registry/infra/organisms/std-status-lifecycle-control.orb +2 -1
  34. package/behaviors/registry/ml/organisms/std-escalating-decision.orb +10 -5
  35. package/behaviors/registry/ml/organisms/std-knowledge-tracing.orb +4 -2
  36. package/behaviors/registry/ui/core/atoms/std-billable-hour.orb +2 -1
  37. package/behaviors/registry/ui/core/atoms/std-board.orb +355 -2
  38. package/behaviors/registry/ui/core/atoms/std-browse.orb +304 -31
  39. package/behaviors/registry/ui/core/atoms/std-calendar.orb +393 -25
  40. package/behaviors/registry/ui/core/atoms/std-dashboard-grid-embedded.orb +2 -1
  41. package/behaviors/registry/ui/core/atoms/std-esign-flow.orb +4 -2
  42. package/behaviors/registry/ui/core/atoms/std-esign-request.orb +6 -3
  43. package/behaviors/registry/ui/core/atoms/std-event-log.orb +773 -0
  44. package/behaviors/registry/ui/core/atoms/std-export.orb +4 -2
  45. package/behaviors/registry/ui/core/atoms/std-gallery.orb +390 -0
  46. package/behaviors/registry/ui/core/atoms/std-import.orb +4 -2
  47. package/behaviors/registry/ui/core/atoms/std-list.orb +451 -0
  48. package/behaviors/registry/ui/core/atoms/std-record-detail.orb +3360 -0
  49. package/behaviors/registry/ui/core/atoms/std-related.orb +23 -1
  50. package/behaviors/registry/ui/core/atoms/std-selection.orb +436 -0
  51. package/behaviors/registry/ui/core/atoms/std-tree.orb +292 -1
  52. package/behaviors/registry/ui/core/atoms/std-version-history.orb +1 -1
  53. package/behaviors/registry/ui/core/molecules/ui-document-details.orb +342 -0
  54. package/behaviors/registry/ui/core/molecules/ui-document-panel.orb +655 -0
  55. package/behaviors/registry/ui/core/molecules/{ui-rich-block-editor.orb → ui-rich-text-editor.orb} +84 -97
  56. package/behaviors/registry/ui/game/atoms/std-area-fill.orb +955 -0
  57. package/behaviors/registry/ui/game/atoms/std-choice-gate.orb +855 -0
  58. package/behaviors/registry/ui/game/atoms/std-coef-pad.orb +928 -0
  59. package/behaviors/registry/ui/game/atoms/std-curve-fog.orb +337 -0
  60. package/behaviors/registry/ui/game/atoms/std-fx-trail.orb +1 -1
  61. package/behaviors/registry/ui/game/atoms/std-gate-lock.orb +1 -1
  62. package/behaviors/registry/ui/game/atoms/std-lives.orb +1 -1
  63. package/behaviors/registry/ui/game/atoms/std-loop-lock.orb +785 -0
  64. package/behaviors/registry/ui/game/atoms/std-pad-lock.orb +933 -0
  65. package/behaviors/registry/ui/game/atoms/std-patrol-hazard.orb +190 -44
  66. package/behaviors/registry/ui/game/atoms/std-platformer-body.orb +1330 -653
  67. package/behaviors/registry/ui/game/atoms/std-velocity-gate.orb +1040 -0
  68. package/behaviors/registry/ui/game/atoms/std-zone-card.orb +642 -0
  69. package/behaviors/registry/ui/game/organisms/std-arcade-board-3d.orb +8 -4
  70. package/behaviors/registry/ui/game/organisms/std-crew-board-2d.orb +6 -3
  71. package/behaviors/registry/ui/game/organisms/std-dungeon-board-2d.orb +10 -5
  72. package/behaviors/registry/ui/game/organisms/std-market-board-3d.orb +8 -4
  73. package/behaviors/registry/ui/game/organisms/std-objective-board-3d.orb +8 -4
  74. package/behaviors/registry/ui/game/organisms/std-platformer-board-2d.orb +36 -1
  75. package/behaviors/registry/ui/game/organisms/std-survival-board-3d.orb +8 -4
  76. package/behaviors/registry/ui/game/organisms/std-tactics-board-2d.orb +12 -6
  77. package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +8 -4
  78. package/behaviors/registry/ui/game/organisms/std-worldmap-board-2d.orb +6 -3
  79. package/behaviors/registry/ui/learning/atoms/std-learn-slope-probe.orb +1 -1
  80. package/behaviors/registry/ui/marketing/atoms/std-marketing-article.orb +2 -1
  81. package/behaviors/registry/ui/marketing/atoms/std-marketing-footer.orb +2 -1
  82. package/behaviors/registry/ui/marketing/atoms/std-marketing-split.orb +2 -1
  83. package/behaviors/registry/ui/marketing/atoms/std-marketing-stats.orb +2 -1
  84. package/behaviors/registry/ui/marketing/atoms/std-marketing-steps.orb +2 -1
  85. package/behaviors/registry/ui/marketing/atoms/std-marketing-team.orb +2 -1
  86. package/dist/behaviors/exports-reader.js +10971 -6255
  87. package/dist/behaviors/functions/index.d.ts +1205 -256
  88. package/dist/behaviors/functions/index.js +10932 -6245
  89. package/dist/behaviors/index.d.ts +1 -1
  90. package/dist/behaviors/index.js +10972 -6256
  91. package/dist/behaviors/query.js +10971 -6255
  92. package/dist/behaviors-embeddings.hash.json +3 -3
  93. package/dist/behaviors-embeddings.json +485 -469
  94. package/dist/behaviors-registry.json +6125 -2940
  95. package/dist/index.d.ts +1 -1
  96. package/dist/index.js +10972 -6256
  97. package/dist/knob-embeddings.hash.json +3 -3
  98. package/dist/knob-embeddings.json +1 -1
  99. package/dist/registry/factory-signatures.json +1 -1
  100. package/package.json +4 -4
  101. package/behaviors/lolo/ui/core/atoms/std-rich-editor.lolo +0 -790
  102. package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +0 -2225
@@ -1,6 +1,7 @@
1
1
  app std-calendar "1.4.0"
2
2
  "std-calendar as a Function — owns the fetch + SELECT_DAY state machine; default bodyContent renders the month-grid + upcoming-events tree. `config.calendarLook` switches the body between the default month-grid ('month'), a day-grouped agenda list ('agenda-list'), and a 7-column week timeline ('week-timeline') while inheriting the same trait, state machine, emits, and listens."
3
3
  type ItemAction = { label : string!, event : string, navigatesTo : string, variant : primary | secondary | ghost | danger, icon : string }
4
+ type FilterSpec = { field : string!, label : string, options : [string] }
4
5
  orbital CalendarEventOrbital {
5
6
  type CalendarEventLoaded = Event { data : [CalendarEvent] } "Fired when CalendarEvent finishes loading; payload.data holds the events"
6
7
 
@@ -27,6 +28,7 @@ orbital CalendarEventOrbital {
27
28
  (set @entity.weekAnchor (time/now))
28
29
  (fetch CalendarEvent {
29
30
  emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
31
+ include: @config.include
30
32
  })
31
33
  (render-ui main {
32
34
  align: center
@@ -81,6 +83,7 @@ orbital CalendarEventOrbital {
81
83
  INIT -> loading
82
84
  (fetch CalendarEvent {
83
85
  emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
86
+ include: @config.include
84
87
  })
85
88
  (render-ui main { type: spinner })
86
89
  SELECT_DAY -> loading
@@ -89,17 +92,36 @@ orbital CalendarEventOrbital {
89
92
  ;; hardcoded `date`, which retargeted consumers (startField=startTime) lack
90
93
  (fetch CalendarEvent {
91
94
  emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
95
+ include: @config.include
92
96
  filter: (time/isAfter (time/parse (object/get @entity @config.startField)) (if ["=", ?value, week] (time/subtract (time/now) 1 week) (if ["=", ?value, "3months"] (time/subtract (time/now) 3 month) (if ["=", ?value, year] (time/subtract (time/now) 1 year) (time/subtract (time/now) 1 month)))))
93
97
  })
94
98
  CALENDAR_PREV_WEEK -> loading
95
99
  (set @entity.weekAnchor (time/subtract @entity.weekAnchor 1 week))
96
100
  (fetch CalendarEvent {
97
101
  emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
102
+ include: @config.include
98
103
  })
99
104
  CALENDAR_NEXT_WEEK -> loading
100
105
  (set @entity.weekAnchor (time/add @entity.weekAnchor 1 week))
101
106
  (fetch CalendarEvent {
102
107
  emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
108
+ include: @config.include
109
+ })
110
+ ;; Same no-render-ui shape as SELECT_DAY/CALENDAR_*_WEEK above: transition
111
+ ;; to `loading` without repainting, so the current grid/agenda/timeline
112
+ ;; stays mounted until CalendarEventLoaded's own render-ui fires — a
113
+ ;; repaint here would flicker the toolbar's search-input every keystroke.
114
+ REFETCH_QUERY -> loading
115
+ (fetch CalendarEvent {
116
+ emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
117
+ include: @config.include
118
+ filter: (or ["=", ?searchTerm, ""] (str/includes (object/get @entity name) ?searchTerm))
119
+ })
120
+ REFETCH_FILTER -> loading
121
+ (fetch CalendarEvent {
122
+ emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
123
+ include: @config.include
124
+ filter: (or ["=", ?value, ""] ["=", (object/get @entity ?field), ?value])
103
125
  })
104
126
  }
105
127
 
@@ -107,6 +129,7 @@ orbital CalendarEventOrbital {
107
129
  INIT -> loading
108
130
  (fetch CalendarEvent {
109
131
  emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
132
+ include: @config.include
110
133
  })
111
134
  (render-ui main { type: spinner })
112
135
  ;; the error screen's Retry button: INIT is lifecycle-only and the bus never
@@ -114,6 +137,7 @@ orbital CalendarEventOrbital {
114
137
  RETRY -> loading
115
138
  (fetch CalendarEvent {
116
139
  emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
140
+ include: @config.include
117
141
  })
118
142
  (render-ui main { type: spinner })
119
143
  }
@@ -128,9 +152,11 @@ orbital CalendarEventOrbital {
128
152
  @synonyms "error, failed, problem, loading issue"
129
153
  @tier "internal"
130
154
  @config.onEventClick -> external {
131
- event : object
155
+ event : @entity
156
+ id : string
157
+ row : @entity
132
158
  }
133
- @description "Emitted when a calendar chip is clicked: UI:{onEventClick} with { event } carrying the clicked row."
159
+ @description "Emitted when a calendar chip is clicked ({ event } carries the clicked row) or an agenda/upcoming row action fires ({ id, row }). Consumers routing it should read the row from ?event or ?row, whichever the payload carries."
134
160
  @tier "presentation"
135
161
  }
136
162
 
@@ -162,6 +188,19 @@ orbital CalendarEventOrbital {
162
188
  @description "Move the week timeline one week later."
163
189
  @synonyms "next week, forward a week, later week, following week"
164
190
  @tier "domain"
191
+ REFETCH_QUERY {
192
+ searchTerm : string!
193
+ }
194
+ @description "Triggers a data refresh based on the current query."
195
+ @synonyms "refresh, reload, update, re-query"
196
+ @tier "domain"
197
+ REFETCH_FILTER {
198
+ field : string!
199
+ value : string!
200
+ }
201
+ @description "Triggers a data refresh based on current filter criteria."
202
+ @synonyms "refresh, filter, update, reload"
203
+ @tier "domain"
165
204
  }
166
205
 
167
206
  config {
@@ -185,6 +224,11 @@ orbital CalendarEventOrbital {
185
224
  @label "Description binding"
186
225
  @description "Per-row binding for the event description slot."
187
226
  @tier "presentation"
227
+ include : [string] = []
228
+ @label "Which relation fields to hydrate?"
229
+ @description "Entity relation field names to hydrate on fetch (e.g. a `category : Category` field named `category`), so chip bindings can use dot-paths like @item.category.name. Empty = no hydration, the default."
230
+ @synonyms "relation hydration, populate relations, joined fields, hydrate relations"
231
+ @tier "internal"
188
232
  startField : string = "date"
189
233
  @label "Start field"
190
234
  @description "Row column holding the timestamp the calendar grid places each chip by. Rebound hosts point this at their own column (e.g. startTime, startsAt, dueAt); the chip's LABEL comes from titleBinding, not from here."
@@ -203,7 +247,7 @@ orbital CalendarEventOrbital {
203
247
  @label "Title"
204
248
  @description "Header text shown above the calendar body."
205
249
  @tier "presentation"
206
- agendaItemActions : [ItemAction] = [{ event: SELECT_DAY, icon: eye, label: View }]
250
+ agendaItemActions : [ItemAction] = []
207
251
  @label "Agenda item actions"
208
252
  @description "Per-item action buttons on agenda-list rows — data-list itemActions descriptors (label/event/icon/variant). Consumers override to wire their own row actions (View/Edit/Delete) so agenda hosts never need a second table for actions."
209
253
  @synonyms "agenda actions, row actions, event actions, list actions"
@@ -213,6 +257,26 @@ orbital CalendarEventOrbital {
213
257
  @description "Row field the agenda list groups its day sections by. Rebound hosts point this at their own timestamp column (e.g. startTime, scheduledAt)."
214
258
  @synonyms "group field, section field, day field"
215
259
  @tier "presentation"
260
+ bodySearch : boolean = false
261
+ @label "Show the calendar's own search box?"
262
+ @description "Embeds a title search box in the toolbar above the calendar body (all three calendarLook trees). Defaults false: std-calendar has never had a search box, so an untouched consumer's surface is unchanged; the primary path is composing std-search beside this atom and wiring XSearch.SEARCH -> REFETCH_QUERY. Set true only for a standalone calendar with no page-level search affordance."
263
+ @synonyms "inline search, calendar search, built-in search, show search, duplicate search"
264
+ @tier "presentation"
265
+ searchPlaceholder : string = "Search…"
266
+ @label "Search box placeholder text"
267
+ @description "Hint text inside the calendar's search box (e.g. 'Search events…')."
268
+ @synonyms "search hint, placeholder, search box text, search label"
269
+ @tier "presentation"
270
+ filters : [FilterSpec] = []
271
+ @label "Which filters should appear above the calendar?"
272
+ @description "Dropdown filter facets by field, rendered as an embedded filter bar above the calendar body (all three calendarLook trees); each selection fires REFETCH_FILTER on this trait. Empty (the default) = no filter bar, which is the right setting whenever the page already composes std-filter beside this calendar and routes XFilter.FILTER -> REFETCH_FILTER — that is the wired owner and remains the primary path. Use this knob only for a standalone calendar with no page-level filter affordance."
273
+ @synonyms "filter bar, faceted filters, field filters, dropdowns"
274
+ @tier "presentation"
275
+ filterBarLook : "toolbar" | "chips" | "pills" | "popover-trigger" | "inline-column-header" = toolbar
276
+ @label "Filter bar look"
277
+ @description "Visual treatment for the embedded filter bar, mirroring std-filter's own enum. Only applies when `filters` is non-empty."
278
+ @synonyms "filter bar style, facet style, chips, pills"
279
+ @tier "presentation"
216
280
  bodyContent : render-ui = {
217
281
  children: [{
218
282
  align: center
@@ -235,7 +299,37 @@ orbital CalendarEventOrbital {
235
299
  gap: md
236
300
  justify: between
237
301
  type: stack
238
- }, { type: divider }, {
302
+ }, (if @config.bodySearch {
303
+ children: [{
304
+ className: "w-full max-w-md"
305
+ clearable: true
306
+ event: REFETCH_QUERY
307
+ placeholder: @config.searchPlaceholder
308
+ type: search-input
309
+ }]
310
+ direction: horizontal
311
+ gap: sm
312
+ type: stack
313
+ } {
314
+ children: []
315
+ gap: none
316
+ type: stack
317
+ }), (if [">", (array/len @config.filters), 0] {
318
+ children: [{
319
+ entity: CalendarEvent
320
+ event: REFETCH_FILTER
321
+ filters: @config.filters
322
+ look: @config.filterBarLook
323
+ type: filter-group
324
+ }]
325
+ direction: horizontal
326
+ gap: sm
327
+ type: stack
328
+ } {
329
+ children: []
330
+ gap: none
331
+ type: stack
332
+ }), { type: divider }, {
239
333
  events: ?data
240
334
  onEventClick: @config.onEventClick
241
335
  renderItem: (fn item {
@@ -270,11 +364,7 @@ orbital CalendarEventOrbital {
270
364
  name: status
271
365
  variant: badge
272
366
  }]
273
- itemActions: [{
274
- event: SELECT_DAY
275
- icon: eye
276
- label: View
277
- }]
367
+ itemActions: @config.agendaItemActions
278
368
  look: @config.tableLook
279
369
  type: data-list
280
370
  }]
@@ -307,7 +397,37 @@ orbital CalendarEventOrbital {
307
397
  gap: md
308
398
  justify: between
309
399
  type: stack
310
- }, { type: divider }, {
400
+ }, (if @config.bodySearch {
401
+ children: [{
402
+ className: "w-full max-w-md"
403
+ clearable: true
404
+ event: REFETCH_QUERY
405
+ placeholder: @config.searchPlaceholder
406
+ type: search-input
407
+ }]
408
+ direction: horizontal
409
+ gap: sm
410
+ type: stack
411
+ } {
412
+ children: []
413
+ gap: none
414
+ type: stack
415
+ }), (if [">", (array/len @config.filters), 0] {
416
+ children: [{
417
+ entity: CalendarEvent
418
+ event: REFETCH_FILTER
419
+ filters: @config.filters
420
+ look: @config.filterBarLook
421
+ type: filter-group
422
+ }]
423
+ direction: horizontal
424
+ gap: sm
425
+ type: stack
426
+ } {
427
+ children: []
428
+ gap: none
429
+ type: stack
430
+ }), { type: divider }, {
311
431
  entity: ?data
312
432
  fields: []
313
433
  gap: md
@@ -429,7 +549,37 @@ orbital CalendarEventOrbital {
429
549
  gap: md
430
550
  justify: between
431
551
  type: stack
432
- }, { type: divider }, {
552
+ }, (if @config.bodySearch {
553
+ children: [{
554
+ className: "w-full max-w-md"
555
+ clearable: true
556
+ event: REFETCH_QUERY
557
+ placeholder: @config.searchPlaceholder
558
+ type: search-input
559
+ }]
560
+ direction: horizontal
561
+ gap: sm
562
+ type: stack
563
+ } {
564
+ children: []
565
+ gap: none
566
+ type: stack
567
+ }), (if [">", (array/len @config.filters), 0] {
568
+ children: [{
569
+ entity: CalendarEvent
570
+ event: REFETCH_FILTER
571
+ filters: @config.filters
572
+ look: @config.filterBarLook
573
+ type: filter-group
574
+ }]
575
+ direction: horizontal
576
+ gap: sm
577
+ type: stack
578
+ } {
579
+ children: []
580
+ gap: none
581
+ type: stack
582
+ }), { type: divider }, {
433
583
  className: w-full
434
584
  dayWindow: 7
435
585
  events: ?data
@@ -2,6 +2,7 @@ app std-event-log "2.1.0"
2
2
  "std-event-log — generic chronological event feed (Stripe activity log / GitHub PR timeline / Linear event feed style). Renders a vertical `timeline` with type-coded dots, a single horizontal chip-bar of kind filters (All + per-kind), reverse-chronological sort, and an inline form for logging events that weren't auto-captured. `config.kindOptions` maps each kind → status/icon/label so consuming molecules/organisms get type-coded visuals without re-implementing topology. Topology = loading / viewing / backfilling / error."
3
3
  type ObjectSpec = { id : string, label : string, value : string }
4
4
  type KindOption = { label : string!, value : string! }
5
+ type FilterSpec = { field : string!, label : string, options : [string] }
5
6
  orbital EventLogOrbital {
6
7
  type LogEntry = { id : string!, title : string!, description : string, date : string, status : "complete" | "active" | "pending" | "error", kind : "created" | "updated" | "approved" | "rejected" }
7
8
 
@@ -89,7 +90,37 @@ orbital EventLogOrbital {
89
90
  direction: horizontal
90
91
  gap: sm
91
92
  type: stack
92
- }, {
93
+ }, (if @config.bodySearch {
94
+ children: [{
95
+ className: "w-full max-w-md"
96
+ clearable: true
97
+ event: REFETCH_QUERY
98
+ placeholder: @config.searchPlaceholder
99
+ type: search-input
100
+ }]
101
+ direction: horizontal
102
+ gap: sm
103
+ type: stack
104
+ } {
105
+ children: []
106
+ gap: none
107
+ type: stack
108
+ }), (if [">", (array/len @config.filters), 0] {
109
+ children: [{
110
+ entity: EventLogView
111
+ event: REFETCH_FILTER
112
+ filters: @config.filters
113
+ look: @config.filterBarLook
114
+ type: filter-group
115
+ }]
116
+ direction: horizontal
117
+ gap: sm
118
+ type: stack
119
+ } {
120
+ children: []
121
+ gap: none
122
+ type: stack
123
+ }), {
93
124
  activeTab: @entity.filterKind
94
125
  tabChangeEvent: APPLY_FILTER
95
126
  tabs: @entity.filterChips
@@ -155,7 +186,150 @@ orbital EventLogOrbital {
155
186
  direction: horizontal
156
187
  gap: sm
157
188
  type: stack
189
+ }, (if @config.bodySearch {
190
+ children: [{
191
+ className: "w-full max-w-md"
192
+ clearable: true
193
+ event: REFETCH_QUERY
194
+ placeholder: @config.searchPlaceholder
195
+ type: search-input
196
+ }]
197
+ direction: horizontal
198
+ gap: sm
199
+ type: stack
200
+ } {
201
+ children: []
202
+ gap: none
203
+ type: stack
204
+ }), (if [">", (array/len @config.filters), 0] {
205
+ children: [{
206
+ entity: EventLogView
207
+ event: REFETCH_FILTER
208
+ filters: @config.filters
209
+ look: @config.filterBarLook
210
+ type: filter-group
211
+ }]
212
+ direction: horizontal
213
+ gap: sm
214
+ type: stack
215
+ } {
216
+ children: []
217
+ gap: none
218
+ type: stack
219
+ }), {
220
+ activeTab: @entity.filterKind
221
+ tabChangeEvent: APPLY_FILTER
222
+ tabs: @entity.filterChips
223
+ type: tabs
158
224
  }, {
225
+ entity: @entity.entries
226
+ fields: (title description date status)
227
+ look: @config.timelineLook
228
+ type: timeline
229
+ }]
230
+ direction: vertical
231
+ gap: md
232
+ type: stack
233
+ })
234
+ ;; REFETCH_* stays in `viewing` and DOES NOT replace the timeline with a
235
+ ;; skeleton — same reasoning as std-browse's REFETCH_* arms: a skeleton
236
+ ;; on refetch unmounts the timeline and flickers every keystroke. The
237
+ ;; fetch fires in the background; the EventLogLoaded arm below re-renders
238
+ ;; in place once it lands. Each refetch also honours the current kind
239
+ ;; tab (@entity.filterKind) so search/generic-filter compound with it
240
+ ;; instead of resetting it.
241
+ REFETCH_QUERY -> viewing
242
+ (fetch EventLogView {
243
+ emit: { failure: EventLogLoadFailed, success: EventLogLoaded }
244
+ filter: (and (or ["=", @entity.filterKind, ""] ["=", (object/get @entity kind), @entity.filterKind]) (or ["=", ?searchTerm, ""] (str/includes (object/get @entity title) ?searchTerm)))
245
+ })
246
+ REFETCH_FILTER -> viewing
247
+ (fetch EventLogView {
248
+ emit: { failure: EventLogLoadFailed, success: EventLogLoaded }
249
+ filter: (and (or ["=", @entity.filterKind, ""] ["=", (object/get @entity kind), @entity.filterKind]) (or ["=", ?value, ""] ["=", (object/get @entity ?field), ?value]))
250
+ })
251
+ ;; No filter carried over on REFETCH_PAGE, mirroring std-browse exactly —
252
+ ;; the reference page arm does not preserve query/filter either.
253
+ REFETCH_PAGE -> viewing
254
+ (fetch EventLogView {
255
+ emit: { failure: EventLogLoadFailed, success: EventLogLoaded }
256
+ limit: @config.pageSize
257
+ offset: ["*", ["-", ?page, 1], @config.pageSize]
258
+ })
259
+ EventLogLoaded -> viewing
260
+ (set @entity.filterChips (array/prepend (array/map @config.kindOptions (fn k {
261
+ icon: (object/get @k icon circle)
262
+ id: (object/get @k key)
263
+ label: (object/get @k label)
264
+ })) {
265
+ icon: list
266
+ id: ""
267
+ label: All
268
+ }))
269
+ (set @entity.allEntries (array/sort (array/map ?data (fn row {
270
+ date: (object/get @row createdAt (object/get @row date ""))
271
+ description: (object/get @row description "")
272
+ id: (object/get @row id "")
273
+ kind: (object/get @row kind "")
274
+ status: (object/get (or (array/find @config.kindOptions (fn k ["=", (object/get @k key), (object/get @row kind "")])) {}) status pending)
275
+ title: (object/get @row title "")
276
+ })) date desc))
277
+ (set @entity.entries (array/sort (array/map ?data (fn row {
278
+ date: (object/get @row createdAt (object/get @row date ""))
279
+ description: (object/get @row description "")
280
+ id: (object/get @row id "")
281
+ kind: (object/get @row kind "")
282
+ status: (object/get (or (array/find @config.kindOptions (fn k ["=", (object/get @k key), (object/get @row kind "")])) {}) status pending)
283
+ title: (object/get @row title "")
284
+ })) date desc))
285
+ (render-ui main {
286
+ children: [{
287
+ align: center
288
+ children: [{ name: history, type: icon }, {
289
+ content: @config.title
290
+ type: typography
291
+ variant: h3
292
+ }, {
293
+ action: OPEN_BACKFILL
294
+ icon: plus
295
+ label: "Log event"
296
+ type: button
297
+ variant: primary
298
+ }]
299
+ direction: horizontal
300
+ gap: sm
301
+ type: stack
302
+ }, (if @config.bodySearch {
303
+ children: [{
304
+ className: "w-full max-w-md"
305
+ clearable: true
306
+ event: REFETCH_QUERY
307
+ placeholder: @config.searchPlaceholder
308
+ type: search-input
309
+ }]
310
+ direction: horizontal
311
+ gap: sm
312
+ type: stack
313
+ } {
314
+ children: []
315
+ gap: none
316
+ type: stack
317
+ }), (if [">", (array/len @config.filters), 0] {
318
+ children: [{
319
+ entity: EventLogView
320
+ event: REFETCH_FILTER
321
+ filters: @config.filters
322
+ look: @config.filterBarLook
323
+ type: filter-group
324
+ }]
325
+ direction: horizontal
326
+ gap: sm
327
+ type: stack
328
+ } {
329
+ children: []
330
+ gap: none
331
+ type: stack
332
+ }), {
159
333
  activeTab: @entity.filterKind
160
334
  tabChangeEvent: APPLY_FILTER
161
335
  tabs: @entity.filterChips
@@ -237,7 +411,37 @@ orbital EventLogOrbital {
237
411
  direction: horizontal
238
412
  gap: sm
239
413
  type: stack
240
- }, {
414
+ }, (if @config.bodySearch {
415
+ children: [{
416
+ className: "w-full max-w-md"
417
+ clearable: true
418
+ event: REFETCH_QUERY
419
+ placeholder: @config.searchPlaceholder
420
+ type: search-input
421
+ }]
422
+ direction: horizontal
423
+ gap: sm
424
+ type: stack
425
+ } {
426
+ children: []
427
+ gap: none
428
+ type: stack
429
+ }), (if [">", (array/len @config.filters), 0] {
430
+ children: [{
431
+ entity: EventLogView
432
+ event: REFETCH_FILTER
433
+ filters: @config.filters
434
+ look: @config.filterBarLook
435
+ type: filter-group
436
+ }]
437
+ direction: horizontal
438
+ gap: sm
439
+ type: stack
440
+ } {
441
+ children: []
442
+ gap: none
443
+ type: stack
444
+ }), {
241
445
  activeTab: @entity.filterKind
242
446
  tabChangeEvent: APPLY_FILTER
243
447
  tabs: @entity.filterChips
@@ -354,6 +558,25 @@ orbital EventLogOrbital {
354
558
  @description "Indicates an attempt to save an event failed."
355
559
  @synonyms "error, failure, save failed"
356
560
  @tier "internal"
561
+ REFETCH_QUERY {
562
+ searchTerm : string!
563
+ }
564
+ @description "Triggers an activity feed refresh based on the current search term."
565
+ @synonyms "refresh, reload, update, re-query, search"
566
+ @tier "domain"
567
+ REFETCH_FILTER {
568
+ field : string!
569
+ value : string!
570
+ }
571
+ @description "Triggers an activity feed refresh based on a field/value filter, in addition to the built-in kind tabs."
572
+ @synonyms "refresh, filter, update, reload"
573
+ @tier "domain"
574
+ REFETCH_PAGE {
575
+ page : number!
576
+ }
577
+ @description "Triggers an activity feed page refresh."
578
+ @synonyms "reload, refresh, update, paginate"
579
+ @tier "domain"
357
580
  }
358
581
 
359
582
  config {
@@ -397,6 +620,36 @@ orbital EventLogOrbital {
397
620
  @label "Timeline look"
398
621
  @description "Layer 2 visual treatment for the timeline."
399
622
  @tier "presentation"
623
+ bodySearch : boolean = false
624
+ @label "Show the log's own search box?"
625
+ @description "Embeds a search box above the activity feed. Set true only when the page has no other search affordance (e.g. no page-level std-search), so the surface shows one search box instead of two. False is the default — no consumer of this atom has ever had a search box."
626
+ @synonyms "inline search, log search, built-in search, show search"
627
+ @tier "presentation"
628
+ searchPlaceholder : string = "Search activity…"
629
+ @label "Search box placeholder text"
630
+ @description "Hint text inside the log's search box."
631
+ @synonyms "search hint, placeholder, search box text"
632
+ @tier "presentation"
633
+ filters : [FilterSpec] = []
634
+ @label "Which filters should appear above the feed?"
635
+ @description "Dropdown filter facets by field, rendered as an embedded filter bar above the timeline; each selection fires REFETCH_FILTER on this trait, ANDed with the current kind tab. Empty (the default) = no filter bar — the right setting whenever the page already composes std-filter beside this atom and routes XFilter.FILTER -> REFETCH_FILTER, or relies solely on the built-in kind-filter chips (driven by kindOptions, which this knob does not duplicate or replace). Use this knob only for an extra facet beyond kind (e.g. actor, priority)."
636
+ @synonyms "filter bar, faceted filters, field filters, dropdowns"
637
+ @tier "presentation"
638
+ filterBarLook : "toolbar" | "chips" | "pills" | "popover-trigger" | "inline-column-header" = toolbar
639
+ @label "Filter bar look"
640
+ @description "Visual treatment for the embedded filter bar, mirroring std-filter's own enum. Only applies when `filters` is non-empty."
641
+ @synonyms "filter bar style, facet style, chips, pills"
642
+ @tier "presentation"
643
+ pageSize : number = 20
644
+ @label "How many entries per page when paging?"
645
+ @description "Records fetched from the server per REFETCH_PAGE request. The initial load and every search/kind/filter refetch stay unpaginated (load everything that matches) so the default unlimited activity feed is unchanged; only an explicit REFETCH_PAGE from a composed std-pagination control applies this limit."
646
+ @synonyms "fetch limit, records per page, page limit"
647
+ @tier "presentation"
648
+ displayPageSize : number = 20
649
+ @label "How many entries per page should a pager show?"
650
+ @description "Page size a consumer-composed std-pagination control should use to compute total pages (e.g. from totalCount). This atom's own timeline pattern has no built-in pager UI, so this knob is informational for the composed control, not consumed by the timeline itself."
651
+ @synonyms "visible rows, items per page, display limit"
652
+ @tier "presentation"
400
653
  }
401
654
  }
402
655