@stonecrop/desktop 0.32.0 → 0.33.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 +39 -31
- package/dist/assets/index.css +66 -50
- package/dist/desktop.js +36 -19
- package/dist/desktop.js.map +1 -1
- package/dist/src/components/Desktop.vue.d.ts +11 -1
- package/dist/src/components/Desktop.vue.d.ts.map +1 -1
- package/dist/src/components/SheetNav.vue.d.ts +11 -1
- package/dist/src/components/SheetNav.vue.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/sheet-nav-toolbar.d.ts +5 -0
- package/dist/src/sheet-nav-toolbar.d.ts.map +1 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
A three-view UI shell for Stonecrop applications. Renders a doctype list → records list → record form layout driven by the host application's Registry and HST state.
|
|
4
4
|
|
|
5
|
-
Desktop reads through Stonecrop
|
|
5
|
+
Desktop reads through Stonecrop: on navigating to a list or a record it calls `Stonecrop.getRecords` / `Stonecrop.getRecord`, which fetch through the host's registered `DataClient` and write into HST. Writes are the host's: Desktop emits `action` and the host dispatches it.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- **Three-view layout**: doctypes → records → record form, navigated by route or adapter
|
|
10
10
|
- **ActionSet toolbar**: FSM transitions become action buttons/dropdowns automatically from the doctype workflow
|
|
11
11
|
- **CommandPalette**: `Ctrl+K` / `Cmd+K` search across doctypes and records
|
|
12
|
-
- **SheetNav**: tabbed navigation between open records
|
|
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
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
@@ -28,7 +28,7 @@ import planDoctype from './doctypes/plan.json'
|
|
|
28
28
|
|
|
29
29
|
const app = createApp(App)
|
|
30
30
|
|
|
31
|
-
// The plugin constructs the Registry itself and provides it as `$registry
|
|
31
|
+
// The plugin constructs the Registry itself and provides it as `$registry`; it does not
|
|
32
32
|
// accept one. Register doctypes on that instance, after install.
|
|
33
33
|
app.use(Stonecrop, { router, client: new RestDataClient() })
|
|
34
34
|
|
|
@@ -38,8 +38,7 @@ registry.addDoctype(Doctype.fromObject(planDoctype))
|
|
|
38
38
|
app.mount('#app')
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
`client` is the `DataClient` Desktop reads through. It can also be supplied later with
|
|
42
|
-
`stonecrop.setClient(client)` — Nuxt hosts do this from a plugin via `useStonecropSetup().registerClient`.
|
|
41
|
+
`client` is the `DataClient` Desktop reads through. It can also be supplied later with `stonecrop.setClient(client)`; Nuxt hosts do this from a plugin via `useStonecropSetup().registerClient`.
|
|
43
42
|
|
|
44
43
|
## Basic Usage
|
|
45
44
|
|
|
@@ -50,7 +49,7 @@ import { useClientAction } from '@stonecrop/stonecrop'
|
|
|
50
49
|
|
|
51
50
|
// Runs an action's clientHandler when the doctype declares one, dispatches to the server
|
|
52
51
|
// otherwise, and reconciles the store and the route with the identity the server settled on.
|
|
53
|
-
// In a Nuxt host this is auto-imported
|
|
52
|
+
// In a Nuxt host this is auto-imported, so drop the import line.
|
|
54
53
|
const { run } = useClientAction()
|
|
55
54
|
</script>
|
|
56
55
|
|
|
@@ -67,27 +66,47 @@ const { run } = useClientAction()
|
|
|
67
66
|
| Prop | Type | Default | Description |
|
|
68
67
|
|------|------|---------|-------------|
|
|
69
68
|
| `availableDoctypes` | `string[]` | `[]` | Doctype slugs to display in the doctypes list |
|
|
70
|
-
| `routeAdapter` | `RouteAdapter` |
|
|
69
|
+
| `routeAdapter` | `RouteAdapter` | none | Custom routing layer (required for Nuxt/custom hosts) |
|
|
71
70
|
|
|
72
|
-
Record identity is not a prop. It is declared per doctype (`primaryKey`, falling back to `id`) and
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
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
|
+
|
|
73
|
+
## Slots
|
|
74
|
+
|
|
75
|
+
| Slot | Renders |
|
|
76
|
+
|------|---------|
|
|
77
|
+
| `sheetnav-toolbar` | Host controls in the footer, immediately left of the navigation tabs |
|
|
78
|
+
|
|
79
|
+
A control deeper in the page than this slot can reach, such as a custom field inside the record form, teleports into the same place:
|
|
80
|
+
|
|
81
|
+
```vue
|
|
82
|
+
<script setup lang="ts">
|
|
83
|
+
import { SHEET_NAV_TOOLBAR_SELECTOR } from '@stonecrop/desktop'
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<template>
|
|
87
|
+
<Teleport :to="SHEET_NAV_TOOLBAR_SELECTOR">
|
|
88
|
+
<MyToolbar />
|
|
89
|
+
</Teleport>
|
|
90
|
+
</template>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Mount one SheetNav per page: with two, teleported content lands in the first and SheetNav logs a warning. When the toolbar and the tabs do not fit on one row, the toolbar moves to a row above the tabs. The Nuxt playground's country records (`/country/US`) carry a working example.
|
|
75
94
|
|
|
76
95
|
## Emitted Events
|
|
77
96
|
|
|
78
97
|
| Event | When |
|
|
79
98
|
|-------|------|
|
|
80
|
-
| `action` | User triggers a declared action
|
|
99
|
+
| `action` | User triggers a declared action: an FSM transition or a Command |
|
|
81
100
|
| `navigate` | Desktop wants to change views |
|
|
82
101
|
| `record:open` | User opens a specific record |
|
|
83
|
-
| `load-records` | Desktop is about to read a records list (notification
|
|
84
|
-
| `load-record` | Desktop is about to read a single record (notification
|
|
102
|
+
| `load-records` | Desktop is about to read a records list (a notification: Desktop performs the read) |
|
|
103
|
+
| `load-record` | Desktop is about to read a single record (a notification: Desktop performs the read) |
|
|
85
104
|
|
|
86
105
|
See [api.md](./api.md) for payload type definitions.
|
|
87
106
|
|
|
88
107
|
### Event Handling Notes
|
|
89
108
|
|
|
90
|
-
- **action**: Desktop merges `Doctype.getAvailableTransitions` and `Doctype.getAvailableCommands`, both resolved against `Stonecrop.getRecordState`, into one Actions dropdown. **Desktop never dispatches
|
|
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.
|
|
91
110
|
- **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.
|
|
92
111
|
|
|
93
112
|
## Router Adapter
|
|
@@ -125,13 +144,9 @@ function useCustomRouteAdapter(): RouteAdapter {
|
|
|
125
144
|
|
|
126
145
|
## Handling `action` Events
|
|
127
146
|
|
|
128
|
-
Dispatching is not the whole job: the result has to land in HST under the identity the *server*
|
|
129
|
-
settled on, which for a newly created record is not the id that was dispatched.
|
|
147
|
+
Dispatching is not the whole job: the result has to land in HST under the identity the *server* settled on, which for a newly created record is not the id that was dispatched.
|
|
130
148
|
|
|
131
|
-
Bind `@action` to `useClientAction`'s `run`, as in Basic Usage above. It runs an action's
|
|
132
|
-
`clientHandler` when it has one, dispatches otherwise, and reconciles the store and the route. It
|
|
133
|
-
lives in `@stonecrop/stonecrop`, so every Vue 3 host gets the same one; Nuxt hosts also get it as an
|
|
134
|
-
auto-import from `@stonecrop/nuxt`.
|
|
149
|
+
Bind `@action` to `useClientAction`'s `run`, as in Basic Usage above. It runs an action's `clientHandler` when it has one, dispatches otherwise, and reconciles the store and the route. It lives in `@stonecrop/stonecrop`, so every Vue 3 host gets the same one; Nuxt hosts also get it as an auto-import from `@stonecrop/nuxt`.
|
|
135
150
|
|
|
136
151
|
Three things are adjustable, for the cases that genuinely differ between applications:
|
|
137
152
|
|
|
@@ -141,18 +156,11 @@ Three things are adjustable, for the cases that genuinely differ between applica
|
|
|
141
156
|
| `followRecord` | `router.replace('/{doctype}/{id}')` | a locale prefix, a nested route, or staying put |
|
|
142
157
|
| `onError` | a blocking `window.alert` | your own notification system |
|
|
143
158
|
|
|
144
|
-
`args` is an opaque JSON array: nothing validates it, so both ends of your own stack have to agree.
|
|
145
|
-
A backend taking positional `[recordId, data]` supplies `buildArgs` to say so.
|
|
159
|
+
`args` is an opaque JSON array: nothing validates it, so both ends of your own stack have to agree. A backend taking positional `[recordId, data]` supplies `buildArgs` to say so.
|
|
146
160
|
|
|
147
|
-
Resolving a record's identity and keying it into HST are deliberately **not** adjustable. That rule
|
|
148
|
-
is declared on the doctype and re-derived server-side by the adapter, and every host that re-derived
|
|
149
|
-
it client-side got it wrong. If you dispatch through `Stonecrop.dispatchAction` directly instead of
|
|
150
|
-
using this composable, that method still files the returned record under the settled identity — you
|
|
151
|
-
cannot store it under the wrong key by accident. What you lose is the stale-key cleanup and the
|
|
152
|
-
route-follow, which need the id you dispatched.
|
|
161
|
+
Resolving a record's identity and keying it into HST are deliberately **not** adjustable. That rule is declared on the doctype and re-derived server-side by the adapter, and every host that re-derived it client-side got it wrong. If you dispatch through `Stonecrop.dispatchAction` directly instead of using this composable, that method still files the returned record under the settled identity, so you cannot store it under the wrong key by accident. What you lose is the stale-key cleanup and the route-follow, which need the id you dispatched.
|
|
153
162
|
|
|
154
|
-
Do not copy form data into HST before dispatching. Desktop already hands you the current form
|
|
155
|
-
snapshot in `payload.data`, and an unsaved record has no HST node to write to.
|
|
163
|
+
Do not copy form data into HST before dispatching. Desktop already hands you the current form snapshot in `payload.data`, and an unsaved record has no HST node to write to.
|
|
156
164
|
|
|
157
165
|
See the [host integration guide](../nuxt/documentation/content/guides/desktop-integration.md) for the full wiring.
|
|
158
166
|
|
|
@@ -169,4 +177,4 @@ const { navigateToDoctype, openRecord, createNewRecord, emitAction } =
|
|
|
169
177
|
|
|
170
178
|
`emitAction(name, data?)` is a convenience wrapper for emitting an `action` event from deeply nested slot content without passing refs down manually.
|
|
171
179
|
|
|
172
|
-
Desktop blesses no action name. It used to expose a `handleDelete` method and a `confirmFn` prop, which together emitted a hardcoded `DELETE` action and prompted before it
|
|
180
|
+
Desktop blesses no action name. It used to expose a `handleDelete` method and a `confirmFn` prop, which together emitted a hardcoded `DELETE` action and prompted before it; but no doctype declares `DELETE`, so it failed on every click, and only the host knows which of its actions are destructive. Removal is a workflow outcome: declare an action with a `nextState` such as `Archived` or `CANCELLED`, and confirm inside your own `@action` handler before dispatching.
|
package/dist/assets/index.css
CHANGED
|
@@ -210,40 +210,68 @@ button.dropdown-item[data-v-8e18f635]:hover {
|
|
|
210
210
|
color: #666;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
/* Pinned to both edges: without `left`, a fixed box takes its container's offset and overflows the
|
|
214
|
+
viewport. Only the toolbar and the tabs take pointer events; the empty strip passes clicks through. */
|
|
215
|
+
footer[data-v-7c905747] {
|
|
214
216
|
position: fixed;
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
right: 0;
|
|
218
|
+
bottom: 0;
|
|
219
|
+
left: 0;
|
|
220
|
+
pointer-events: none;
|
|
217
221
|
background-color: transparent;
|
|
218
|
-
height: auto;
|
|
219
|
-
min-height: 2.4rem;
|
|
220
222
|
z-index: 100;
|
|
221
223
|
text-align: left;
|
|
222
224
|
font-size: 100%;
|
|
223
225
|
display: flex;
|
|
224
|
-
justify-content:
|
|
226
|
+
justify-content: flex-end;
|
|
227
|
+
align-items: flex-end;
|
|
225
228
|
padding: 0 0.75rem 0 0;
|
|
226
229
|
box-sizing: border-box;
|
|
227
230
|
}
|
|
228
|
-
|
|
231
|
+
|
|
232
|
+
/* When the toolbar and the tabs do not fit on one row, the toolbar wraps onto its own row above. */
|
|
233
|
+
.sheetnav-footer-cluster[data-v-7c905747] {
|
|
234
|
+
display: flex;
|
|
235
|
+
flex-wrap: wrap;
|
|
236
|
+
justify-content: flex-end;
|
|
237
|
+
align-items: flex-end;
|
|
238
|
+
column-gap: 0.5rem;
|
|
239
|
+
max-width: 100%;
|
|
240
|
+
min-width: 0;
|
|
241
|
+
}
|
|
242
|
+
.sheetnav-toolbar[data-v-7c905747] {
|
|
243
|
+
pointer-events: auto;
|
|
244
|
+
min-width: 0;
|
|
245
|
+
min-height: 2.4rem;
|
|
246
|
+
display: flex;
|
|
247
|
+
flex-wrap: wrap;
|
|
248
|
+
justify-content: flex-end;
|
|
249
|
+
align-items: center;
|
|
250
|
+
}
|
|
251
|
+
.tabs[data-v-7c905747] {
|
|
252
|
+
pointer-events: auto;
|
|
253
|
+
flex: 0 0 auto;
|
|
229
254
|
display: flex;
|
|
230
255
|
flex-direction: row-reverse;
|
|
256
|
+
align-items: stretch;
|
|
257
|
+
height: 2.4rem;
|
|
231
258
|
margin: 0;
|
|
232
259
|
padding: 0;
|
|
233
260
|
list-style: none;
|
|
234
261
|
}
|
|
235
|
-
.tabs li[data-v-
|
|
236
|
-
|
|
262
|
+
.tabs li[data-v-7c905747] {
|
|
263
|
+
display: flex;
|
|
264
|
+
align-items: stretch;
|
|
237
265
|
list-style-type: none;
|
|
238
266
|
position: relative;
|
|
239
267
|
margin-left: -1px;
|
|
240
268
|
}
|
|
241
269
|
|
|
242
270
|
/* Base tab styling */
|
|
243
|
-
.tabs a[data-v-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
271
|
+
.tabs a[data-v-7c905747] {
|
|
272
|
+
height: 100%;
|
|
273
|
+
min-height: 2.4rem;
|
|
274
|
+
padding: 0 1rem;
|
|
247
275
|
box-sizing: border-box;
|
|
248
276
|
display: flex;
|
|
249
277
|
align-items: center;
|
|
@@ -260,10 +288,10 @@ ul[data-v-cd118b06] {
|
|
|
260
288
|
border-top-left-radius: 2px;
|
|
261
289
|
border-top-right-radius: 2px;
|
|
262
290
|
}
|
|
263
|
-
.tabs a[data-v-
|
|
291
|
+
.tabs a[data-v-7c905747]:hover {
|
|
264
292
|
background: var(--sc-btn-hover);
|
|
265
293
|
}
|
|
266
|
-
.tabs .router-link-active[data-v-
|
|
294
|
+
.tabs .router-link-active[data-v-7c905747] {
|
|
267
295
|
z-index: 3;
|
|
268
296
|
background: var(--sc-primary-color) !important;
|
|
269
297
|
border-color: var(--sc-primary-color) !important;
|
|
@@ -273,19 +301,15 @@ ul[data-v-cd118b06] {
|
|
|
273
301
|
/* Pseudo-elements removed - minimal ornamentation style */
|
|
274
302
|
|
|
275
303
|
/* Hide breadcrumbs tab */
|
|
276
|
-
.hidebreadcrumbs a[data-v-
|
|
304
|
+
.hidebreadcrumbs a[data-v-7c905747] {
|
|
277
305
|
min-width: 2.4rem;
|
|
278
306
|
width: 2.4rem;
|
|
279
|
-
height: 2.4rem;
|
|
280
307
|
padding: 0.5rem;
|
|
281
|
-
background: var(--sc-btn-color);
|
|
282
|
-
border: 1px solid var(--sc-btn-border);
|
|
283
|
-
color: var(--sc-gray-60);
|
|
284
308
|
}
|
|
285
|
-
.hidebreadcrumbs a div[data-v-
|
|
309
|
+
.hidebreadcrumbs a div[data-v-7c905747] {
|
|
286
310
|
font-size: 1.2rem;
|
|
287
311
|
}
|
|
288
|
-
.rotated[data-v-
|
|
312
|
+
.rotated[data-v-7c905747] {
|
|
289
313
|
transform: rotate(45deg);
|
|
290
314
|
-webkit-transform: rotate(45deg);
|
|
291
315
|
-moz-transform: rotate(45deg);
|
|
@@ -293,7 +317,7 @@ ul[data-v-cd118b06] {
|
|
|
293
317
|
-o-transform: rotate(45deg);
|
|
294
318
|
transition: transform 250ms ease;
|
|
295
319
|
}
|
|
296
|
-
.unrotated[data-v-
|
|
320
|
+
.unrotated[data-v-7c905747] {
|
|
297
321
|
transform: rotate(0deg);
|
|
298
322
|
-webkit-transform: rotate(0deg);
|
|
299
323
|
-moz-transform: rotate(0deg);
|
|
@@ -301,34 +325,30 @@ ul[data-v-cd118b06] {
|
|
|
301
325
|
-o-transform: rotate(0deg);
|
|
302
326
|
transition: transform 250ms ease;
|
|
303
327
|
}
|
|
304
|
-
li[data-v-
|
|
305
|
-
li[data-v-
|
|
306
|
-
li[data-v-
|
|
307
|
-
li > a[data-v-
|
|
308
|
-
li > a[data-v-
|
|
309
|
-
li > a[data-v-
|
|
328
|
+
li[data-v-7c905747]:active,
|
|
329
|
+
li[data-v-7c905747]:hover,
|
|
330
|
+
li[data-v-7c905747]:focus,
|
|
331
|
+
li > a[data-v-7c905747]:active,
|
|
332
|
+
li > a[data-v-7c905747]:hover,
|
|
333
|
+
li > a[data-v-7c905747]:focus {
|
|
310
334
|
z-index: 3;
|
|
311
335
|
}
|
|
312
|
-
a[data-v-
|
|
313
|
-
a[data-v-
|
|
314
|
-
a[data-v-
|
|
336
|
+
a[data-v-7c905747]:active,
|
|
337
|
+
a[data-v-7c905747]:hover,
|
|
338
|
+
a[data-v-7c905747]:focus {
|
|
315
339
|
outline: 2px solid var(--sc-input-active-border-color);
|
|
316
340
|
z-index: 3;
|
|
317
341
|
}
|
|
318
342
|
|
|
319
343
|
/* Home tab */
|
|
320
|
-
.hometab a[data-v-
|
|
344
|
+
.hometab a[data-v-7c905747] {
|
|
321
345
|
min-width: 2.4rem;
|
|
322
346
|
width: 2.4rem;
|
|
323
|
-
height: 2.4rem;
|
|
324
347
|
padding: 0.5rem;
|
|
325
|
-
background: var(--sc-btn-color);
|
|
326
|
-
border: 1px solid var(--sc-btn-border);
|
|
327
|
-
color: var(--sc-gray-60);
|
|
328
348
|
}
|
|
329
349
|
|
|
330
350
|
/* SVG icon styling */
|
|
331
|
-
.icon[data-v-
|
|
351
|
+
.icon[data-v-7c905747] {
|
|
332
352
|
width: 1rem;
|
|
333
353
|
height: 1rem;
|
|
334
354
|
stroke: currentColor;
|
|
@@ -336,16 +356,12 @@ a[data-v-cd118b06]:focus {
|
|
|
336
356
|
}
|
|
337
357
|
|
|
338
358
|
/* Search tab with animation */
|
|
339
|
-
.searchtab[data-v-
|
|
359
|
+
.searchtab[data-v-7c905747] {
|
|
340
360
|
overflow: hidden;
|
|
341
361
|
}
|
|
342
|
-
.searchtab a[data-v-
|
|
362
|
+
.searchtab a[data-v-7c905747] {
|
|
343
363
|
min-width: 2.4rem;
|
|
344
|
-
height: 2.4rem;
|
|
345
364
|
padding: 0.5rem;
|
|
346
|
-
background: var(--sc-btn-color);
|
|
347
|
-
border: 1px solid var(--sc-btn-border);
|
|
348
|
-
color: var(--sc-gray-60);
|
|
349
365
|
overflow: hidden;
|
|
350
366
|
/* Animation for smooth expand/collapse */
|
|
351
367
|
max-width: 2.4rem;
|
|
@@ -354,10 +370,10 @@ a[data-v-cd118b06]:focus {
|
|
|
354
370
|
padding 0.35s ease-in-out,
|
|
355
371
|
background 0.2s ease;
|
|
356
372
|
}
|
|
357
|
-
.searchtab .search-icon[data-v-
|
|
373
|
+
.searchtab .search-icon[data-v-7c905747] {
|
|
358
374
|
cursor: pointer;
|
|
359
375
|
}
|
|
360
|
-
.searchtab input[data-v-
|
|
376
|
+
.searchtab input[data-v-7c905747] {
|
|
361
377
|
outline: none;
|
|
362
378
|
border: 1px solid var(--sc-input-border-color);
|
|
363
379
|
border-radius: 0.25rem;
|
|
@@ -373,22 +389,22 @@ a[data-v-cd118b06]:focus {
|
|
|
373
389
|
transition: opacity 0.2s ease-in-out;
|
|
374
390
|
transition-delay: 0s;
|
|
375
391
|
}
|
|
376
|
-
.searchtab input[data-v-
|
|
392
|
+
.searchtab input[data-v-7c905747]:focus {
|
|
377
393
|
border-color: var(--sc-input-active-border-color);
|
|
378
394
|
outline: none;
|
|
379
395
|
}
|
|
380
|
-
.searchtab input[data-v-
|
|
396
|
+
.searchtab input[data-v-7c905747]::placeholder {
|
|
381
397
|
color: var(--sc-input-label-color);
|
|
382
398
|
}
|
|
383
399
|
|
|
384
400
|
/* Search active state - expanded with animation */
|
|
385
|
-
.searchtab.search-active a[data-v-
|
|
401
|
+
.searchtab.search-active a[data-v-7c905747] {
|
|
386
402
|
max-width: 200px;
|
|
387
403
|
min-width: auto;
|
|
388
404
|
width: auto;
|
|
389
405
|
padding: 0.5rem 0.75rem;
|
|
390
406
|
}
|
|
391
|
-
.searchtab.search-active input[data-v-
|
|
407
|
+
.searchtab.search-active input[data-v-7c905747] {
|
|
392
408
|
opacity: 1;
|
|
393
409
|
transition-delay: 0.15s;
|
|
394
410
|
}
|
package/dist/desktop.js
CHANGED
|
@@ -5,8 +5,8 @@ import './assets/index.css';//#region src/components/ActionSet.vue?vue&type=scri
|
|
|
5
5
|
var _hoisted_1$3 = { class: "action-menu-icon" };
|
|
6
6
|
var _hoisted_2$3 = { class: "action-element-header" };
|
|
7
7
|
var _hoisted_3$2 = ["disabled", "onClick"];
|
|
8
|
-
var _hoisted_4$
|
|
9
|
-
var _hoisted_5$
|
|
8
|
+
var _hoisted_4$2 = { key: 0 };
|
|
9
|
+
var _hoisted_5$2 = { class: "dropdown-header" };
|
|
10
10
|
var _hoisted_6$1 = ["onClick"];
|
|
11
11
|
var _hoisted_7$1 = ["onClick"];
|
|
12
12
|
var _hoisted_8 = { class: "dropdown-container" };
|
|
@@ -61,7 +61,7 @@ var ActionSet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
|
|
|
61
61
|
disabled: el.disabled,
|
|
62
62
|
class: "button-default",
|
|
63
63
|
onClick: ($event) => handleClick(el.action, el.label)
|
|
64
|
-
}, toDisplayString(el.label), 9, _hoisted_3$2)) : createCommentVNode("", true)]), el.type == "dropdown" ? (openBlock(), createElementBlock("div", _hoisted_4$
|
|
64
|
+
}, toDisplayString(el.label), 9, _hoisted_3$2)) : createCommentVNode("", true)]), el.type == "dropdown" ? (openBlock(), createElementBlock("div", _hoisted_4$2, [createElementVNode("div", _hoisted_5$2, [createElementVNode("div", {
|
|
65
65
|
class: normalizeClass(["cross", { rotated: dropdownOpen.value[index] }]),
|
|
66
66
|
onClick: ($event) => toggleDropdown(index)
|
|
67
67
|
}, "×", 10, _hoisted_6$1), createElementVNode("button", {
|
|
@@ -100,8 +100,8 @@ var _hoisted_3$1 = {
|
|
|
100
100
|
key: 0,
|
|
101
101
|
class: "command-palette-results"
|
|
102
102
|
};
|
|
103
|
-
var _hoisted_4 = ["onClick", "onMouseover"];
|
|
104
|
-
var _hoisted_5 = { class: "result-title" };
|
|
103
|
+
var _hoisted_4$1 = ["onClick", "onMouseover"];
|
|
104
|
+
var _hoisted_5$1 = { class: "result-title" };
|
|
105
105
|
var _hoisted_6 = { class: "result-content" };
|
|
106
106
|
var _hoisted_7 = {
|
|
107
107
|
key: 1,
|
|
@@ -187,7 +187,7 @@ var CommandPalette_default = /* @__PURE__ */ defineComponent({
|
|
|
187
187
|
class: normalizeClass(["command-palette-result", { selected: index === selectedIndex.value }]),
|
|
188
188
|
onClick: ($event) => selectResult(result),
|
|
189
189
|
onMouseover: ($event) => selectedIndex.value = index
|
|
190
|
-
}, [createElementVNode("div", _hoisted_5, [renderSlot(_ctx.$slots, "title", { result })]), createElementVNode("div", _hoisted_6, [renderSlot(_ctx.$slots, "content", { result })])], 42, _hoisted_4);
|
|
190
|
+
}, [createElementVNode("div", _hoisted_5$1, [renderSlot(_ctx.$slots, "title", { result })]), createElementVNode("div", _hoisted_6, [renderSlot(_ctx.$slots, "content", { result })])], 42, _hoisted_4$1);
|
|
191
191
|
}), 128))])) : query.value && !results.value.length ? (openBlock(), createElementBlock("div", _hoisted_7, [renderSlot(_ctx.$slots, "empty", {}, () => [createTextVNode(" No results found for \"" + toDisplayString(query.value) + "\" ", 1)])])) : createCommentVNode("", true)])])) : createCommentVNode("", true)]),
|
|
192
192
|
_: 3
|
|
193
193
|
})]);
|
|
@@ -195,16 +195,27 @@ var CommandPalette_default = /* @__PURE__ */ defineComponent({
|
|
|
195
195
|
}
|
|
196
196
|
});
|
|
197
197
|
//#endregion
|
|
198
|
+
//#region src/sheet-nav-toolbar.ts
|
|
199
|
+
/** The id of the element SheetNav renders for footer controls, left of its tabs. */
|
|
200
|
+
var SHEET_NAV_TOOLBAR_ID = "sheetnav-toolbar";
|
|
201
|
+
/** Teleport target for footer controls rendered anywhere on the page: `<Teleport :to="SHEET_NAV_TOOLBAR_SELECTOR">`. */
|
|
202
|
+
var SHEET_NAV_TOOLBAR_SELECTOR = `#${SHEET_NAV_TOOLBAR_ID}`;
|
|
203
|
+
//#endregion
|
|
198
204
|
//#region src/components/SheetNav.vue?vue&type=script&setup=true&lang.ts
|
|
199
|
-
var _hoisted_1$1 = { class: "
|
|
200
|
-
var _hoisted_2$1 =
|
|
201
|
-
var _hoisted_3 = {
|
|
205
|
+
var _hoisted_1$1 = { class: "sheetnav-footer-cluster" };
|
|
206
|
+
var _hoisted_2$1 = ["id"];
|
|
207
|
+
var _hoisted_3 = { class: "tabs" };
|
|
208
|
+
var _hoisted_4 = { tabindex: "0" };
|
|
209
|
+
var _hoisted_5 = { tabindex: "0" };
|
|
202
210
|
//#endregion
|
|
203
211
|
//#region src/components/SheetNav.vue
|
|
204
212
|
var SheetNav_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
205
213
|
__name: "SheetNav",
|
|
206
214
|
props: { breadcrumbs: { default: () => [] } },
|
|
207
215
|
setup(__props) {
|
|
216
|
+
onMounted(() => {
|
|
217
|
+
if (document.querySelectorAll(SHEET_NAV_TOOLBAR_SELECTOR).length > 1) console.warn(`More than one SheetNav is mounted: content teleported to ${SHEET_NAV_TOOLBAR_SELECTOR} lands in the first one only.`);
|
|
218
|
+
});
|
|
208
219
|
const breadcrumbsVisibile = ref(true);
|
|
209
220
|
const searchVisible = ref(false);
|
|
210
221
|
const searchText = ref("");
|
|
@@ -233,15 +244,18 @@ var SheetNav_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
|
|
|
233
244
|
const navigateHome = () => {};
|
|
234
245
|
return (_ctx, _cache) => {
|
|
235
246
|
const _component_router_link = resolveComponent("router-link");
|
|
236
|
-
return openBlock(), createElementBlock("footer", null, [createElementVNode("
|
|
247
|
+
return openBlock(), createElementBlock("footer", null, [createElementVNode("div", _hoisted_1$1, [createElementVNode("div", {
|
|
248
|
+
id: unref(SHEET_NAV_TOOLBAR_ID),
|
|
249
|
+
class: "sheetnav-toolbar"
|
|
250
|
+
}, [renderSlot(_ctx.$slots, "toolbar", {}, void 0, true)], 8, _hoisted_2$1), createElementVNode("ul", _hoisted_3, [
|
|
237
251
|
createElementVNode("li", {
|
|
238
252
|
class: "hidebreadcrumbs",
|
|
239
253
|
onClick: toggleBreadcrumbs,
|
|
240
254
|
onKeydown: withKeys(toggleBreadcrumbs, ["enter"])
|
|
241
|
-
}, [createElementVNode("a",
|
|
255
|
+
}, [createElementVNode("a", _hoisted_4, [createElementVNode("div", { class: normalizeClass(rotateHideTabIcon.value) }, "×", 2)])], 32),
|
|
242
256
|
createElementVNode("li", {
|
|
243
257
|
class: "hometab",
|
|
244
|
-
style: normalizeStyle({ display: breadcrumbsVisibile.value ? "
|
|
258
|
+
style: normalizeStyle({ display: breadcrumbsVisibile.value ? "flex" : "none" }),
|
|
245
259
|
onClick: navigateHome,
|
|
246
260
|
onKeydown: withKeys(navigateHome, ["enter"])
|
|
247
261
|
}, [createVNode(_component_router_link, {
|
|
@@ -260,8 +274,8 @@ var SheetNav_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
|
|
|
260
274
|
})], 36),
|
|
261
275
|
createElementVNode("li", {
|
|
262
276
|
class: normalizeClass(["searchtab", { "search-active": searchVisible.value }]),
|
|
263
|
-
style: normalizeStyle({ display: breadcrumbsVisibile.value ? "
|
|
264
|
-
}, [createElementVNode("a",
|
|
277
|
+
style: normalizeStyle({ display: breadcrumbsVisibile.value ? "flex" : "none" })
|
|
278
|
+
}, [createElementVNode("a", _hoisted_5, [withDirectives((openBlock(), createElementBlock("svg", {
|
|
265
279
|
class: "icon search-icon",
|
|
266
280
|
role: "button",
|
|
267
281
|
"aria-label": "Search",
|
|
@@ -288,7 +302,7 @@ var SheetNav_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
|
|
|
288
302
|
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.breadcrumbs, (breadcrumb) => {
|
|
289
303
|
return openBlock(), createElementBlock("li", {
|
|
290
304
|
key: breadcrumb.title,
|
|
291
|
-
style: normalizeStyle({ display: breadcrumbsVisibile.value ? "
|
|
305
|
+
style: normalizeStyle({ display: breadcrumbsVisibile.value ? "flex" : "none" })
|
|
292
306
|
}, [createVNode(_component_router_link, {
|
|
293
307
|
tabindex: "0",
|
|
294
308
|
to: breadcrumb.to
|
|
@@ -297,10 +311,10 @@ var SheetNav_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
|
|
|
297
311
|
_: 2
|
|
298
312
|
}, 1032, ["to"])], 4);
|
|
299
313
|
}), 128))
|
|
300
|
-
])]);
|
|
314
|
+
])])]);
|
|
301
315
|
};
|
|
302
316
|
}
|
|
303
|
-
}), [["__scopeId", "data-v-
|
|
317
|
+
}), [["__scopeId", "data-v-7c905747"]]);
|
|
304
318
|
//#endregion
|
|
305
319
|
//#region src/components/Desktop.vue?vue&type=script&setup=true&lang.ts
|
|
306
320
|
var _hoisted_1 = {
|
|
@@ -901,7 +915,10 @@ var Desktop_default = /* @__PURE__ */ defineComponent({
|
|
|
901
915
|
"schema",
|
|
902
916
|
"errors"
|
|
903
917
|
])) : !unref(stonecrop) ? (openBlock(), createElementBlock("div", _hoisted_1, [..._cache[2] || (_cache[2] = [createElementVNode("p", null, "Initializing Stonecrop...", -1)])])) : (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("p", null, "Loading " + toDisplayString(currentView.value) + " data...", 1)])),
|
|
904
|
-
createVNode(SheetNav_default, { breadcrumbs: navigationBreadcrumbs.value },
|
|
918
|
+
createVNode(SheetNav_default, { breadcrumbs: navigationBreadcrumbs.value }, {
|
|
919
|
+
toolbar: withCtx(() => [renderSlot(_ctx.$slots, "sheetnav-toolbar")]),
|
|
920
|
+
_: 3
|
|
921
|
+
}, 8, ["breadcrumbs"]),
|
|
905
922
|
createVNode(CommandPalette_default, {
|
|
906
923
|
"is-open": commandPaletteOpen.value,
|
|
907
924
|
search: searchCommands,
|
|
@@ -930,6 +947,6 @@ var plugin = { install: (app) => {
|
|
|
930
947
|
app.component("SheetNav", SheetNav_default);
|
|
931
948
|
} };
|
|
932
949
|
//#endregion
|
|
933
|
-
export { ActionSet_default as ActionSet, CommandPalette_default as CommandPalette, Desktop_default as Desktop, SheetNav_default as SheetNav, plugin as StonecropDesktop };
|
|
950
|
+
export { ActionSet_default as ActionSet, CommandPalette_default as CommandPalette, Desktop_default as Desktop, SHEET_NAV_TOOLBAR_SELECTOR, SheetNav_default as SheetNav, plugin as StonecropDesktop };
|
|
934
951
|
|
|
935
952
|
//# sourceMappingURL=desktop.js.map
|