@stonecrop/desktop 0.33.0 → 0.34.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/README.md CHANGED
@@ -7,7 +7,7 @@ Desktop reads through Stonecrop: on navigating to a list or a record it calls `S
7
7
  ## Features
8
8
 
9
9
  - **Three-view layout**: doctypes → records → record form, navigated by route or adapter
10
- - **ActionSet toolbar**: FSM transitions become action buttons/dropdowns automatically from the doctype workflow
10
+ - **ActionSet tile column**: expandable tile UI with Search, host slots, and an Actions drawer; FSM transitions populate the actions list automatically from the doctype workflow
11
11
  - **CommandPalette**: `Ctrl+K` / `Cmd+K` search across doctypes and records
12
12
  - **SheetNav**: tabbed navigation between open records, with a toolbar for host controls in the footer (see [Slots](#slots))
13
13
  - **Event-driven**: all significant interactions emit typed events for the host to respond to
@@ -67,6 +67,8 @@ const { run } = useClientAction()
67
67
  |------|------|---------|-------------|
68
68
  | `availableDoctypes` | `string[]` | `[]` | Doctype slugs to display in the doctypes list |
69
69
  | `routeAdapter` | `RouteAdapter` | none | Custom routing layer (required for Nuxt/custom hosts) |
70
+ | `actionSetSlots` | `ActionSetSlot[]` | `[]` | Host drawer slots shown as tiles in ActionSet |
71
+ | `hostActions` | `ActionElements[]` | none | Actions listed in the Actions drawer in place of those derived from the doctype; `[]` lists none |
70
72
 
71
73
  Record identity is not a prop. It is declared per doctype (`primaryKey`, falling back to `id`) and resolved through `Doctype.getRecordId`, so a row's link always matches the key the record is stored under. One shell renders many doctypes, so a single prop could never answer this correctly.
72
74
 
@@ -106,7 +108,7 @@ See [api.md](./api.md) for payload type definitions.
106
108
 
107
109
  ### Event Handling Notes
108
110
 
109
- - **action**: Desktop merges `Doctype.getAvailableTransitions` and `Doctype.getAvailableCommands`, both resolved against `Stonecrop.getRecordState`, into one Actions dropdown. **Desktop never dispatches**: that is the host application's responsibility.
111
+ - **action**: Desktop merges `Doctype.getAvailableTransitions` and `Doctype.getAvailableCommands`, both resolved against `Stonecrop.getRecordState`, into the ActionSet Actions drawer. **Desktop never dispatches**: that is the host application's responsibility.
110
112
  - **load-records / load-record**: notifications, not fetch requests. Desktop reads through `Stonecrop.getRecords` / `Stonecrop.getRecord` itself, using the registered `DataClient`; these events announce that read so a host can hang analytics off it. A host that fetches here races Desktop's own read into the same HST key. `load-record` is not emitted for a draft, which has nothing to fetch.
111
113
 
112
114
  ## Router Adapter
@@ -1,125 +1,4 @@
1
1
 
2
- #cross[data-v-8e18f635] {
3
- position: relative;
4
- transform: rotate(45deg);
5
- cursor: pointer;
6
- transition: all 0.2s ease-in-out;
7
- user-select: none;
8
- line-height: 1rem;
9
- }
10
- #cross.rotated[data-v-8e18f635],
11
- .cross.rotated[data-v-8e18f635] {
12
- transform: rotate(0deg);
13
- }
14
- #cross svg[data-v-8e18f635] {
15
- width: 1.5em;
16
- height: 1.5em;
17
- }
18
- .action-set[data-v-8e18f635] {
19
- position: fixed;
20
- top: 300px;
21
- right: 10px;
22
- padding: 10px;
23
- display: flex;
24
- flex-direction: column;
25
- align-items: flex-end;
26
- background: var(--sc-form-background);
27
- border: 1px solid var(--sc-gray-20);
28
- border-left: 4px solid var(--sc-gray-20);
29
- border-radius: 0;
30
- overflow: hidden;
31
- z-index: 1001; /* Above SheetNav (100) and operation log button (999) */
32
- -webkit-transition: all 0.5s ease-in-out;
33
- -moz-transition: all 0.5s ease-in-out;
34
- -o-transition: all 0.5s ease-in-out;
35
- transition: all 0.5s ease-in-out;
36
- }
37
- .action-menu-icon[data-v-8e18f635] {
38
- position: relative;
39
- font-size: 2rem;
40
- display: inline-block;
41
- color: var(--sc-gray-60);
42
- transition: all 0.2s ease-in-out;
43
- }
44
- .action-set.collapsed[data-v-8e18f635] {
45
- max-width: 46px;
46
- max-height: 40px;
47
- overflow: hidden;
48
- }
49
- .action-set.collapsed .action-element[data-v-8e18f635] {
50
- opacity: 0;
51
- -webkit-transition: opacity 0.25s ease-in-out;
52
- -moz-transition: opacity 0.25s ease-in-out;
53
- -o-transition: opacity 0.25s ease-in-out;
54
- transition: opacity 0.25s ease-in-out;
55
- }
56
- .action-element[data-v-8e18f635] {
57
- width: 100%;
58
- text-align: right;
59
- border: 1px solid var(--sc-gray-20);
60
- background: none;
61
- font-size: 1.5rem;
62
- font-family: var(--sc-font-family);
63
- font-weight: 600;
64
- margin-top: 10px;
65
- position: relative; /* Make this the positioning context for absolute children */
66
- }
67
- .action-element-header[data-v-8e18f635] {
68
- display: flex;
69
- justify-content: end;
70
- }
71
- button.button-default[data-v-8e18f635] {
72
- background-color: transparent;
73
- padding: 5px 12px;
74
- border-radius: 0px;
75
- box-shadow: none;
76
- border: none;
77
- cursor: pointer;
78
- white-space: nowrap;
79
- font-weight: bold;
80
- font-size: 1rem;
81
- text-align: right;
82
- color: var(--sc-gray-80);
83
- padding-left: 50px;
84
- font-family: var(--sc-font-family);
85
- }
86
- .dropdown-header:hover button.button-default[data-v-8e18f635],
87
- .dropdown-header[data-v-8e18f635]:hover,
88
- .action-element-header[data-v-8e18f635]:hover {
89
- background-color: #f2f2f2;
90
- }
91
- .dropdown-title[data-v-8e18f635] {
92
- position: relative;
93
- }
94
- .dropdown-header[data-v-8e18f635] {
95
- display: flex;
96
- align-items: center;
97
- }
98
- .cross[data-v-8e18f635] {
99
- pointer-events: all;
100
- margin-left: 5px;
101
- font-family: var(--sc-font-family);
102
- color: var(--sc-gray-60);
103
- cursor: pointer;
104
- transform: rotate(45deg);
105
- user-select: none;
106
- transition: all 0.2s ease-in-out;
107
- line-height: 1rem;
108
- }
109
- button.dropdown-item[data-v-8e18f635] {
110
- width: 100%;
111
- padding: 5px 12px;
112
- text-align: right;
113
- border: none;
114
- background-color: #ffffff;
115
- cursor: pointer;
116
- border-radius: 5px;
117
- font-size: 1rem;
118
- }
119
- button.dropdown-item[data-v-8e18f635]:hover {
120
- background-color: #f2f2f2;
121
- }
122
-
123
2
  .fade-enter-active,
124
3
  .fade-leave-active {
125
4
  transition: opacity 0.2s ease;
@@ -210,6 +89,202 @@ button.dropdown-item[data-v-8e18f635]:hover {
210
89
  color: #666;
211
90
  }
212
91
 
92
+ .action-set[data-v-40295597] {
93
+ /* Right offset + tile column width + gap: the strip the drawer keeps clear for the tile column. */
94
+ --action-set-rail-inset: calc(10px + 2.75rem + 18px + 8px);
95
+ position: fixed;
96
+ top: var(--sc-action-set-offset-top);
97
+ right: 10px;
98
+ z-index: 1001;
99
+ display: flex;
100
+ flex-direction: row-reverse;
101
+ align-items: flex-start;
102
+ gap: 0;
103
+ }
104
+
105
+ /* Positioned above the drawer, which is a later sibling in the same stacking context. */
106
+ .action-set__tile[data-v-40295597] {
107
+ position: relative;
108
+ z-index: 1;
109
+ display: flex;
110
+ flex-direction: column;
111
+ align-items: center;
112
+ padding: 8px;
113
+ background: var(--sc-form-background);
114
+ border: 1px solid var(--sc-gray-20);
115
+ }
116
+ .action-set__toggle[data-v-40295597] {
117
+ display: flex;
118
+ align-items: center;
119
+ justify-content: center;
120
+ width: 2.75rem;
121
+ height: 2.75rem;
122
+ padding: 0;
123
+ border: none;
124
+ background: transparent;
125
+ font-size: 1.5rem;
126
+ font-weight: 300;
127
+ line-height: 1;
128
+ color: var(--sc-gray-60);
129
+ cursor: pointer;
130
+ transition: transform 0.2s ease-in-out;
131
+ }
132
+ @media (prefers-reduced-motion: reduce) {
133
+ .action-set__toggle[data-v-40295597] {
134
+ transition: none;
135
+ }
136
+ }
137
+ .action-set__toggle--expanded[data-v-40295597] {
138
+ transform: rotate(45deg);
139
+ }
140
+ .action-set__toggle[data-v-40295597]:focus-visible,
141
+ .action-set__item[data-v-40295597]:focus-visible,
142
+ .action-set__drawer-close[data-v-40295597]:focus-visible,
143
+ .action-set__actions-list-item[data-v-40295597]:focus-visible {
144
+ outline: 2px solid var(--sc-primary-color);
145
+ outline-offset: 2px;
146
+ }
147
+ .action-set__item[data-v-40295597] {
148
+ position: relative;
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ width: 2.75rem;
153
+ height: 2.75rem;
154
+ margin-top: 8px;
155
+ padding: 0;
156
+ border: 1px solid var(--sc-gray-20);
157
+ background: transparent;
158
+ cursor: pointer;
159
+ font-family: var(--sc-font-family);
160
+ color: var(--sc-gray-80);
161
+ }
162
+ .action-set__item[data-v-40295597]:hover,
163
+ .action-set__item--active[data-v-40295597] {
164
+ background: var(--sc-btn-hover);
165
+ }
166
+ .action-set__item-icon[data-v-40295597] {
167
+ display: block;
168
+ width: 1rem;
169
+ height: 1rem;
170
+ flex-shrink: 0;
171
+ }
172
+ .action-set__item-fallback[data-v-40295597] {
173
+ font-size: 0.85rem;
174
+ font-weight: 600;
175
+ line-height: 1;
176
+ }
177
+ .action-set__item-badge[data-v-40295597] {
178
+ position: absolute;
179
+ top: 2px;
180
+ right: 2px;
181
+ min-width: 14px;
182
+ height: 14px;
183
+ padding: 0 3px;
184
+ border-radius: 7px;
185
+ background: var(--sc-badge-danger-accent);
186
+ color: var(--sc-primary-text-color);
187
+ font-size: 10px;
188
+ font-weight: 600;
189
+ line-height: 14px;
190
+ text-align: center;
191
+ pointer-events: none;
192
+ }
193
+ .action-set__drawer[data-v-40295597] {
194
+ position: fixed;
195
+ top: 0;
196
+ right: 0;
197
+ bottom: 0;
198
+ box-sizing: border-box;
199
+ width: var(--sc-action-set-drawer-width);
200
+ padding-right: var(--action-set-rail-inset);
201
+ background: var(--sc-form-background);
202
+ border-left: 1px solid var(--sc-gray-20);
203
+ display: flex;
204
+ flex-direction: column;
205
+ z-index: 0;
206
+ }
207
+ .action-set__drawer-header[data-v-40295597] {
208
+ display: flex;
209
+ align-items: center;
210
+ justify-content: flex-end;
211
+ padding: 8px 12px;
212
+ flex-shrink: 0;
213
+ }
214
+ .action-set__drawer-close[data-v-40295597] {
215
+ flex-shrink: 0;
216
+ border: none;
217
+ background: transparent;
218
+ font-size: 1.25rem;
219
+ line-height: 1;
220
+ cursor: pointer;
221
+ color: var(--sc-gray-60);
222
+ padding: 0.5rem;
223
+ min-width: 2.75rem;
224
+ min-height: 2.75rem;
225
+ }
226
+ .action-set__drawer-body[data-v-40295597] {
227
+ flex: 1;
228
+ min-height: 0;
229
+ overflow: auto;
230
+ }
231
+ .action-set__drawer-empty[data-v-40295597] {
232
+ padding: 16px 12px;
233
+ margin: 0;
234
+ color: var(--sc-gray-60);
235
+ font-style: italic;
236
+ }
237
+ .action-set__actions-list[data-v-40295597] {
238
+ padding: 8px;
239
+ }
240
+ .action-set__actions-list-item[data-v-40295597] {
241
+ display: block;
242
+ box-sizing: border-box;
243
+ width: 100%;
244
+ padding: 10px 12px;
245
+ margin-bottom: 4px;
246
+ border: 1px solid var(--sc-gray-20);
247
+ background: transparent;
248
+ text-align: left;
249
+ font-size: 0.9rem;
250
+ font-family: var(--sc-font-family);
251
+ font-weight: 500;
252
+ color: var(--sc-gray-80);
253
+ text-decoration: none;
254
+ cursor: pointer;
255
+ }
256
+ .action-set__actions-list-item[data-v-40295597]:hover {
257
+ background: var(--sc-btn-hover);
258
+ }
259
+ .action-set__actions-list-item[data-v-40295597]:disabled {
260
+ opacity: 0.5;
261
+ cursor: not-allowed;
262
+ }
263
+ .action-set__actions-list-item--nested[data-v-40295597] {
264
+ margin-left: 0;
265
+ width: 100%;
266
+ font-weight: 400;
267
+ }
268
+ .action-set__actions-group[data-v-40295597] {
269
+ margin-bottom: 8px;
270
+ }
271
+ .action-set__actions-group-label[data-v-40295597] {
272
+ margin: 4px 0 6px;
273
+ padding: 0 2px;
274
+ font-family: var(--sc-font-family);
275
+ font-size: 0.75rem;
276
+ font-weight: 600;
277
+ letter-spacing: 0.04em;
278
+ text-transform: uppercase;
279
+ color: var(--sc-gray-60);
280
+ }
281
+ .action-set__actions-empty[data-v-40295597] {
282
+ padding: 16px 12px;
283
+ margin: 0;
284
+ color: var(--sc-gray-60);
285
+ font-style: italic;
286
+ }
287
+
213
288
  /* Pinned to both edges: without `left`, a fixed box takes its container's offset and overflows the
214
289
  viewport. Only the toolbar and the tabs take pointer events; the empty strip passes clicks through. */
215
290
  footer[data-v-7c905747] {
@@ -408,3 +483,81 @@ a[data-v-7c905747]:focus {
408
483
  opacity: 1;
409
484
  transition-delay: 0.15s;
410
485
  }
486
+
487
+ .desktop[data-v-378bae6b] {
488
+ position: relative;
489
+ height: 100%;
490
+ display: flex;
491
+ flex-direction: column;
492
+ min-height: 0;
493
+ overflow: hidden;
494
+ }
495
+ .desktop__workspace[data-v-378bae6b] {
496
+ display: flex;
497
+ flex: 1;
498
+ min-height: 0;
499
+ min-width: 0;
500
+ margin-right: 0;
501
+ transition: margin-right 0.25s ease-out;
502
+ }
503
+ .desktop--action-set-open .desktop__workspace[data-v-378bae6b] {
504
+ margin-right: var(--sc-action-set-drawer-width);
505
+ }
506
+
507
+ /* SheetNav is fixed to the viewport, so the workspace margin does not move it clear of the drawer. */
508
+ .desktop__sheetnav[data-v-378bae6b] {
509
+ transition: right 0.25s ease-out;
510
+ }
511
+ .desktop--action-set-open .desktop__sheetnav[data-v-378bae6b] {
512
+ right: var(--sc-action-set-drawer-width);
513
+ }
514
+ .desktop__main[data-v-378bae6b] {
515
+ flex: 1;
516
+ min-width: 0;
517
+ min-height: 0;
518
+ overflow: auto;
519
+ }
520
+ .desktop--preview-open .desktop__main[data-v-378bae6b] {
521
+ flex: 0 0 calc(50% - 10px);
522
+ max-width: calc(50% - 10px);
523
+ }
524
+ .desktop__preview[data-v-378bae6b] {
525
+ flex: 0 0 50%;
526
+ max-width: 50%;
527
+ min-width: 0;
528
+ min-height: 0;
529
+ display: flex;
530
+ flex-direction: column;
531
+ border-left: 1px solid var(--sc-gray-20);
532
+ background: var(--sc-form-background);
533
+ overflow: hidden;
534
+ }
535
+ .desktop__preview-header[data-v-378bae6b] {
536
+ display: flex;
537
+ justify-content: flex-end;
538
+ align-items: center;
539
+ height: 40px;
540
+ padding: 0 8px;
541
+ border-bottom: 1px solid var(--sc-gray-20);
542
+ flex-shrink: 0;
543
+ }
544
+ .desktop__preview-close[data-v-378bae6b] {
545
+ border: none;
546
+ background: transparent;
547
+ font-size: 1.25rem;
548
+ line-height: 1;
549
+ cursor: pointer;
550
+ color: var(--sc-gray-60);
551
+ }
552
+ .desktop__preview-body[data-v-378bae6b] {
553
+ flex: 1;
554
+ min-height: 0;
555
+ overflow: auto;
556
+ }
557
+ .loading[data-v-378bae6b] {
558
+ display: flex;
559
+ align-items: center;
560
+ justify-content: center;
561
+ min-height: 50vh;
562
+ color: var(--sc-gray-60);
563
+ }