@mosaicajs/components 0.3.0 → 0.4.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 +2 -0
- package/dist/aggregate.d.ts +4 -10
- package/dist/aggregate.js +7 -13
- package/dist/artifact-card.d.ts +21 -7
- package/dist/artifact-card.js +136 -79
- package/dist/base.d.ts +44 -5
- package/dist/base.js +54 -5
- package/dist/cluster-filter.d.ts +29 -25
- package/dist/cluster-filter.js +123 -106
- package/dist/colour-editor.d.ts +15 -4
- package/dist/colour-editor.js +107 -34
- package/dist/colour-picker.d.ts +12 -5
- package/dist/colour-picker.js +119 -32
- package/dist/display.js +77 -9
- package/dist/events.d.ts +21 -7
- package/dist/explorer.d.ts +116 -37
- package/dist/explorer.js +476 -210
- package/dist/field-card.d.ts +304 -48
- package/dist/field-card.js +1364 -244
- package/dist/filter-panel.d.ts +54 -10
- package/dist/filter-panel.js +242 -42
- package/dist/filter.d.ts +22 -4
- package/dist/filter.js +113 -34
- package/dist/hierarchy.d.ts +68 -45
- package/dist/hierarchy.js +320 -243
- package/dist/item-card.d.ts +47 -16
- package/dist/item-card.js +241 -108
- package/dist/key-picker.d.ts +2 -1
- package/dist/key-picker.js +4 -3
- package/dist/layer-picker.d.ts +4 -2
- package/dist/layer-picker.js +16 -7
- package/dist/lineage.d.ts +132 -0
- package/dist/lineage.js +307 -0
- package/dist/map.d.ts +135 -24
- package/dist/map.js +387 -117
- package/dist/mosaica-components.js +1837 -833
- package/dist/mosaica-components.js.sri +1 -1
- package/dist/mosaica-components.json +2 -2
- package/dist/parts.d.ts +4 -4
- package/dist/parts.js +18 -4
- package/dist/paths.d.ts +34 -12
- package/dist/paths.js +84 -46
- package/dist/selection.d.ts +22 -3
- package/dist/selection.js +125 -59
- package/dist/states.d.ts +72 -0
- package/dist/states.js +135 -26
- package/dist/status.d.ts +63 -5
- package/dist/status.js +215 -36
- package/dist/tokens.d.ts +8 -4
- package/dist/tokens.js +144 -14
- package/dist/view-picker.js +5 -0
- package/package.json +4 -3
package/dist/status.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { nothing, type TemplateResult } from 'lit';
|
|
1
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
2
2
|
import { MosaicaElement } from './base.js';
|
|
3
3
|
import './count.js';
|
|
4
4
|
/**
|
|
@@ -10,25 +10,50 @@ import './count.js';
|
|
|
10
10
|
*
|
|
11
11
|
* While the view is up to date, the first cell is a dot alone. When something goes wrong, the cell
|
|
12
12
|
* names the state and offers a button if the viewer can act, such as Retry when the server is busy.
|
|
13
|
-
* Sign in appears when the session expires only if you have set `reauthorise`.
|
|
13
|
+
* Sign in appears when the session expires only if you have set `reauthorise`. If the viewer may see
|
|
14
|
+
* no item in the view at all, the cell says so.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* Where the strip is short of room, its cells wrap onto further lines.
|
|
17
|
+
*
|
|
18
|
+
* After a change of filters, highlight or selection, the cell reads Running query once the answer
|
|
19
|
+
* has taken more than a quarter of a second, until the map, the layers and the counts have all
|
|
20
|
+
* loaded. Its Cancel button goes back to the filters, highlight and selection that last finished
|
|
21
|
+
* loading.
|
|
22
|
+
*
|
|
23
|
+
* Screen readers announce the states the cell names in words, because the words are a live region.
|
|
24
|
+
* A pan announces nothing: up to date and updating are read but not announced, the counts sit
|
|
25
|
+
* outside the region, and Nothing in view is announced only as the answer to a change of filters,
|
|
26
|
+
* highlight or selection, not where a pan went. After such a change the region announces the counts
|
|
27
|
+
* once they have loaded, such as `3,923 of 50,000 match`, or that the view is up to date where there
|
|
28
|
+
* are no counts to say. After any state it announced, it announces that the view is up to date
|
|
29
|
+
* again. A state's button sits outside the region. When the button goes with its state while it has
|
|
30
|
+
* the focus, the state cell takes the focus. With `quiet`, the strip shows the same and announces
|
|
31
|
+
* nothing.
|
|
17
32
|
*
|
|
18
33
|
* @summary A status line showing whether the map is up to date and how many items it shows.
|
|
19
34
|
* @tagname mosaica-status
|
|
20
35
|
* @category Elements
|
|
21
36
|
* @fires {CustomEvent<MosaicaEventDetails['mosaica-statechange']>} mosaica-statechange - The panel
|
|
22
37
|
* state changed, including on the first render.
|
|
38
|
+
* @fires {CustomEvent<MosaicaEventDetails['mosaica-filterchange']>} mosaica-filterchange - Cancel
|
|
39
|
+
* went back to other filters or another highlight, once for each that changed, with `column` null.
|
|
40
|
+
* @fires {CustomEvent<MosaicaEventDetails['mosaica-clausechange']>} mosaica-clausechange - Cancel
|
|
41
|
+
* put back or took away a `member_of` clause, once for each.
|
|
42
|
+
* @fires {CustomEvent<MosaicaEventDetails['mosaica-selectchange']>} mosaica-selectchange - Cancel
|
|
43
|
+
* went back to another selected region, or to none, and once with `view` for each other view
|
|
44
|
+
* whose held region it put back or took away.
|
|
23
45
|
* @fires {CustomEvent<MosaicaEventDetails['mosaica-expired']>} mosaica-expired - The session expired.
|
|
24
46
|
* Fires once each time.
|
|
25
|
-
* @csspart strip - The
|
|
47
|
+
* @csspart strip - The strip of cells.
|
|
26
48
|
* @csspart state - The state's dot and words, with `data-state` set to the panel state.
|
|
27
49
|
* @csspart refusal - The words "View refused", or "Server busy", with `data-code` set to the
|
|
28
50
|
* refusal's code.
|
|
29
51
|
* @csspart reason - The server's reason for a refusal, under "View refused".
|
|
30
52
|
* @csspart refresh - The Refresh button, shown when the data has changed.
|
|
31
53
|
* @csspart retry - The Retry button, after a refusal, no answer or a busy server.
|
|
54
|
+
* @csspart cancel - The Cancel button, while a query runs.
|
|
55
|
+
* @csspart spinner - The spinner beside the words Running query. The state part carries
|
|
56
|
+
* `data-querying` while it shows.
|
|
32
57
|
* @csspart reauthorise - The Sign in button, shown on expiry if `reauthorise` is set.
|
|
33
58
|
* @csspart count-shown - The `<mosaica-count>` of marks shown.
|
|
34
59
|
* @csspart count-matched - The `<mosaica-count>` of items the filters match.
|
|
@@ -46,11 +71,44 @@ export declare class MosaicaStatus extends MosaicaElement {
|
|
|
46
71
|
accessor compact: boolean;
|
|
47
72
|
/** A function the Sign in button calls when the session has expired. Without it there is no Sign in button. */
|
|
48
73
|
accessor reauthorise: (() => void) | null;
|
|
74
|
+
/**
|
|
75
|
+
* Announces nothing: every state and result is still shown, and none is put in a live region. Set
|
|
76
|
+
* it when another element on the page says the same things.
|
|
77
|
+
*/
|
|
78
|
+
accessor quiet: boolean;
|
|
79
|
+
private readonly query;
|
|
80
|
+
private readonly actionFocus;
|
|
81
|
+
private readonly emptyAnswer;
|
|
49
82
|
private lastState;
|
|
50
83
|
private expiryFired;
|
|
84
|
+
/** What the strip shows now, decided before each render: `bare` is a dot alone, and `unsaid` what {@link liveLine} takes. */
|
|
85
|
+
private shown;
|
|
86
|
+
/** What the live region says while the strip shows a dot alone: a query's result, or that the view is back up to date. */
|
|
87
|
+
private heard;
|
|
88
|
+
/** The dot-alone state `heard` was last decided under. */
|
|
89
|
+
private bareState;
|
|
90
|
+
private wasQuerying;
|
|
91
|
+
/** Whether a query has finished and its result is still to be said. */
|
|
92
|
+
private resultDue;
|
|
93
|
+
/** Whether the strip has left a state it announced and has not yet said the view is up to date again. */
|
|
94
|
+
private recoveryDue;
|
|
51
95
|
private get status();
|
|
52
96
|
private get view();
|
|
97
|
+
disconnectedCallback(): void;
|
|
98
|
+
protected willUpdate(changed: PropertyValues<this>): void;
|
|
99
|
+
/**
|
|
100
|
+
* Decide what the live region says while the strip shows a dot alone. A pan moves between up to
|
|
101
|
+
* date and updating and says nothing. A query that finishes says its result once the counts are
|
|
102
|
+
* in, or that the view is up to date where there are no counts to say, and a return from a
|
|
103
|
+
* state the strip announced says the view is up to date. Either is taken away at the next
|
|
104
|
+
* change, so that it is said again when it next holds.
|
|
105
|
+
*/
|
|
106
|
+
private hear;
|
|
107
|
+
/** The counts as the cells show them, in full figures, or `null` where there are none to show. */
|
|
108
|
+
private result;
|
|
53
109
|
protected updated(): void;
|
|
110
|
+
/** Cancel the query, and tell the page what it went back to, as the controls that set those do. */
|
|
111
|
+
private cancel;
|
|
54
112
|
render(): TemplateResult | typeof nothing;
|
|
55
113
|
/**
|
|
56
114
|
* The count cells: current in the shown state, greyed out while a new answer is awaited or the
|
package/dist/status.js
CHANGED
|
@@ -34,10 +34,10 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
34
34
|
};
|
|
35
35
|
import { css, html, nothing } from 'lit';
|
|
36
36
|
import { property } from 'lit/decorators.js';
|
|
37
|
-
import { NO_COUNT, NO_MASKED } from '@mosaicajs/client';
|
|
38
|
-
import { MosaicaElement, emit } from './base.js';
|
|
37
|
+
import { NO_COUNT, NO_MASKED, formatMasked } from '@mosaicajs/client';
|
|
38
|
+
import { MosaicaElement, emit, idString, shapeDetail } from './base.js';
|
|
39
39
|
import { attachContextRoot, defineOnce } from './define.js';
|
|
40
|
-
import { NOTHING_VISIBLE,
|
|
40
|
+
import { ActionFocus, EmptyAnswer, NOTHING_VISIBLE, NamedQuery, UNSAID, liveLine, seesNothing, showsContent, stateLine, stateOf, stateWord } from './states.js';
|
|
41
41
|
import { chrome, tokens } from './tokens.js';
|
|
42
42
|
import './count.js';
|
|
43
43
|
/**
|
|
@@ -49,25 +49,50 @@ import './count.js';
|
|
|
49
49
|
*
|
|
50
50
|
* While the view is up to date, the first cell is a dot alone. When something goes wrong, the cell
|
|
51
51
|
* names the state and offers a button if the viewer can act, such as Retry when the server is busy.
|
|
52
|
-
* Sign in appears when the session expires only if you have set `reauthorise`.
|
|
52
|
+
* Sign in appears when the session expires only if you have set `reauthorise`. If the viewer may see
|
|
53
|
+
* no item in the view at all, the cell says so.
|
|
53
54
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
55
|
+
* Where the strip is short of room, its cells wrap onto further lines.
|
|
56
|
+
*
|
|
57
|
+
* After a change of filters, highlight or selection, the cell reads Running query once the answer
|
|
58
|
+
* has taken more than a quarter of a second, until the map, the layers and the counts have all
|
|
59
|
+
* loaded. Its Cancel button goes back to the filters, highlight and selection that last finished
|
|
60
|
+
* loading.
|
|
61
|
+
*
|
|
62
|
+
* Screen readers announce the states the cell names in words, because the words are a live region.
|
|
63
|
+
* A pan announces nothing: up to date and updating are read but not announced, the counts sit
|
|
64
|
+
* outside the region, and Nothing in view is announced only as the answer to a change of filters,
|
|
65
|
+
* highlight or selection, not where a pan went. After such a change the region announces the counts
|
|
66
|
+
* once they have loaded, such as `3,923 of 50,000 match`, or that the view is up to date where there
|
|
67
|
+
* are no counts to say. After any state it announced, it announces that the view is up to date
|
|
68
|
+
* again. A state's button sits outside the region. When the button goes with its state while it has
|
|
69
|
+
* the focus, the state cell takes the focus. With `quiet`, the strip shows the same and announces
|
|
70
|
+
* nothing.
|
|
56
71
|
*
|
|
57
72
|
* @summary A status line showing whether the map is up to date and how many items it shows.
|
|
58
73
|
* @tagname mosaica-status
|
|
59
74
|
* @category Elements
|
|
60
75
|
* @fires {CustomEvent<MosaicaEventDetails['mosaica-statechange']>} mosaica-statechange - The panel
|
|
61
76
|
* state changed, including on the first render.
|
|
77
|
+
* @fires {CustomEvent<MosaicaEventDetails['mosaica-filterchange']>} mosaica-filterchange - Cancel
|
|
78
|
+
* went back to other filters or another highlight, once for each that changed, with `column` null.
|
|
79
|
+
* @fires {CustomEvent<MosaicaEventDetails['mosaica-clausechange']>} mosaica-clausechange - Cancel
|
|
80
|
+
* put back or took away a `member_of` clause, once for each.
|
|
81
|
+
* @fires {CustomEvent<MosaicaEventDetails['mosaica-selectchange']>} mosaica-selectchange - Cancel
|
|
82
|
+
* went back to another selected region, or to none, and once with `view` for each other view
|
|
83
|
+
* whose held region it put back or took away.
|
|
62
84
|
* @fires {CustomEvent<MosaicaEventDetails['mosaica-expired']>} mosaica-expired - The session expired.
|
|
63
85
|
* Fires once each time.
|
|
64
|
-
* @csspart strip - The
|
|
86
|
+
* @csspart strip - The strip of cells.
|
|
65
87
|
* @csspart state - The state's dot and words, with `data-state` set to the panel state.
|
|
66
88
|
* @csspart refusal - The words "View refused", or "Server busy", with `data-code` set to the
|
|
67
89
|
* refusal's code.
|
|
68
90
|
* @csspart reason - The server's reason for a refusal, under "View refused".
|
|
69
91
|
* @csspart refresh - The Refresh button, shown when the data has changed.
|
|
70
92
|
* @csspart retry - The Retry button, after a refusal, no answer or a busy server.
|
|
93
|
+
* @csspart cancel - The Cancel button, while a query runs.
|
|
94
|
+
* @csspart spinner - The spinner beside the words Running query. The state part carries
|
|
95
|
+
* `data-querying` while it shows.
|
|
71
96
|
* @csspart reauthorise - The Sign in button, shown on expiry if `reauthorise` is set.
|
|
72
97
|
* @csspart count-shown - The `<mosaica-count>` of marks shown.
|
|
73
98
|
* @csspart count-matched - The `<mosaica-count>` of items the filters match.
|
|
@@ -88,15 +113,20 @@ let MosaicaStatus = (() => {
|
|
|
88
113
|
let _reauthorise_decorators;
|
|
89
114
|
let _reauthorise_initializers = [];
|
|
90
115
|
let _reauthorise_extraInitializers = [];
|
|
116
|
+
let _quiet_decorators;
|
|
117
|
+
let _quiet_initializers = [];
|
|
118
|
+
let _quiet_extraInitializers = [];
|
|
91
119
|
return class MosaicaStatus extends _classSuper {
|
|
92
120
|
static {
|
|
93
121
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
94
122
|
_expanded_decorators = [property({ type: Boolean })];
|
|
95
123
|
_compact_decorators = [property({ type: Boolean, reflect: true })];
|
|
96
124
|
_reauthorise_decorators = [property({ attribute: false })];
|
|
125
|
+
_quiet_decorators = [property({ type: Boolean, reflect: true })];
|
|
97
126
|
__esDecorate(this, null, _expanded_decorators, { kind: "accessor", name: "expanded", static: false, private: false, access: { has: obj => "expanded" in obj, get: obj => obj.expanded, set: (obj, value) => { obj.expanded = value; } }, metadata: _metadata }, _expanded_initializers, _expanded_extraInitializers);
|
|
98
127
|
__esDecorate(this, null, _compact_decorators, { kind: "accessor", name: "compact", static: false, private: false, access: { has: obj => "compact" in obj, get: obj => obj.compact, set: (obj, value) => { obj.compact = value; } }, metadata: _metadata }, _compact_initializers, _compact_extraInitializers);
|
|
99
128
|
__esDecorate(this, null, _reauthorise_decorators, { kind: "accessor", name: "reauthorise", static: false, private: false, access: { has: obj => "reauthorise" in obj, get: obj => obj.reauthorise, set: (obj, value) => { obj.reauthorise = value; } }, metadata: _metadata }, _reauthorise_initializers, _reauthorise_extraInitializers);
|
|
129
|
+
__esDecorate(this, null, _quiet_decorators, { kind: "accessor", name: "quiet", static: false, private: false, access: { has: obj => "quiet" in obj, get: obj => obj.quiet, set: (obj, value) => { obj.quiet = value; } }, metadata: _metadata }, _quiet_initializers, _quiet_extraInitializers);
|
|
100
130
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
101
131
|
}
|
|
102
132
|
static styles = [
|
|
@@ -108,8 +138,11 @@ let MosaicaStatus = (() => {
|
|
|
108
138
|
max-width: 100%;
|
|
109
139
|
vertical-align: top;
|
|
110
140
|
}
|
|
141
|
+
/* The cells wrap onto further lines where the strip is short of room, and a cell wider than
|
|
142
|
+
the strip wraps its own words. */
|
|
111
143
|
[part='strip'] {
|
|
112
144
|
display: inline-flex;
|
|
145
|
+
flex-wrap: wrap;
|
|
113
146
|
align-items: stretch;
|
|
114
147
|
max-width: 100%;
|
|
115
148
|
min-height: 32px;
|
|
@@ -121,17 +154,19 @@ let MosaicaStatus = (() => {
|
|
|
121
154
|
font-size: 12px;
|
|
122
155
|
color: var(--_mosaica-ink-2);
|
|
123
156
|
font-variant-numeric: tabular-nums;
|
|
124
|
-
white-space: nowrap;
|
|
125
157
|
}
|
|
126
158
|
[part='strip'][data-state='detached'] {
|
|
127
159
|
display: none;
|
|
128
160
|
}
|
|
129
161
|
.cell {
|
|
130
162
|
display: flex;
|
|
163
|
+
flex-wrap: wrap;
|
|
131
164
|
align-items: center;
|
|
132
|
-
gap: 4px;
|
|
165
|
+
gap: 0 4px;
|
|
166
|
+
min-height: 30px;
|
|
133
167
|
padding: 7px 12px;
|
|
134
|
-
flex:
|
|
168
|
+
flex: 0 1 auto;
|
|
169
|
+
min-width: 0;
|
|
135
170
|
}
|
|
136
171
|
.cell mosaica-count {
|
|
137
172
|
font-size: inherit;
|
|
@@ -139,8 +174,11 @@ let MosaicaStatus = (() => {
|
|
|
139
174
|
.cell + .cell {
|
|
140
175
|
border-left: 1px solid var(--_mosaica-line-2);
|
|
141
176
|
}
|
|
177
|
+
/* Figures that wait for an answer, or stand from before a refusal, are all drawn in the
|
|
178
|
+
faint ink, which keeps a text's contrast. The state cell says why, by its dot's shape
|
|
179
|
+
or in words. */
|
|
142
180
|
.cell.dim {
|
|
143
|
-
|
|
181
|
+
color: var(--_mosaica-ink-3);
|
|
144
182
|
}
|
|
145
183
|
.cell.state {
|
|
146
184
|
padding: 0 5px 0 12px;
|
|
@@ -148,8 +186,12 @@ let MosaicaStatus = (() => {
|
|
|
148
186
|
.cell.state.bare {
|
|
149
187
|
padding: 0 12px;
|
|
150
188
|
}
|
|
189
|
+
.cell.state:focus-visible {
|
|
190
|
+
outline-offset: -2px;
|
|
191
|
+
}
|
|
151
192
|
[part='state'] {
|
|
152
193
|
gap: 7px;
|
|
194
|
+
min-width: 0;
|
|
153
195
|
color: inherit;
|
|
154
196
|
}
|
|
155
197
|
[part='state'] .skel {
|
|
@@ -161,6 +203,7 @@ let MosaicaStatus = (() => {
|
|
|
161
203
|
[part='state']:not(:has(.btn)) {
|
|
162
204
|
padding-right: 7px;
|
|
163
205
|
}
|
|
206
|
+
|
|
164
207
|
.cell mosaica-count::part(count) {
|
|
165
208
|
font-weight: 600;
|
|
166
209
|
}
|
|
@@ -179,6 +222,10 @@ let MosaicaStatus = (() => {
|
|
|
179
222
|
.cell mosaica-count.lit::part(count) {
|
|
180
223
|
color: var(--_mosaica-highlight);
|
|
181
224
|
}
|
|
225
|
+
.cell.dim mosaica-count::part(count),
|
|
226
|
+
.cell.dim mosaica-count::part(label) {
|
|
227
|
+
color: var(--_mosaica-ink-3);
|
|
228
|
+
}
|
|
182
229
|
.cell mosaica-count::part(label) {
|
|
183
230
|
margin-left: 0.3em;
|
|
184
231
|
}
|
|
@@ -198,6 +245,10 @@ let MosaicaStatus = (() => {
|
|
|
198
245
|
box-shadow: var(--_mosaica-shadow);
|
|
199
246
|
font-size: 12px;
|
|
200
247
|
}
|
|
248
|
+
[part='card'] dl,
|
|
249
|
+
[part='card'] dd {
|
|
250
|
+
margin: 0;
|
|
251
|
+
}
|
|
201
252
|
`
|
|
202
253
|
];
|
|
203
254
|
#expanded_accessor_storage = __runInitializers(this, _expanded_initializers, false);
|
|
@@ -212,15 +263,122 @@ let MosaicaStatus = (() => {
|
|
|
212
263
|
/** A function the Sign in button calls when the session has expired. Without it there is no Sign in button. */
|
|
213
264
|
get reauthorise() { return this.#reauthorise_accessor_storage; }
|
|
214
265
|
set reauthorise(value) { this.#reauthorise_accessor_storage = value; }
|
|
215
|
-
|
|
266
|
+
#quiet_accessor_storage = (__runInitializers(this, _reauthorise_extraInitializers), __runInitializers(this, _quiet_initializers, false));
|
|
267
|
+
/**
|
|
268
|
+
* Announces nothing: every state and result is still shown, and none is put in a live region. Set
|
|
269
|
+
* it when another element on the page says the same things.
|
|
270
|
+
*/
|
|
271
|
+
get quiet() { return this.#quiet_accessor_storage; }
|
|
272
|
+
set quiet(value) { this.#quiet_accessor_storage = value; }
|
|
273
|
+
query = (__runInitializers(this, _quiet_extraInitializers), new NamedQuery(this));
|
|
274
|
+
actionFocus = new ActionFocus();
|
|
275
|
+
emptyAnswer = new EmptyAnswer();
|
|
276
|
+
lastState = null;
|
|
216
277
|
expiryFired = false;
|
|
278
|
+
/** What the strip shows now, decided before each render: `bare` is a dot alone, and `unsaid` what {@link liveLine} takes. */
|
|
279
|
+
shown = { state: 'detached', running: false, bare: false, line: stateLine('detached', null), unsaid: null };
|
|
280
|
+
/** What the live region says while the strip shows a dot alone: a query's result, or that the view is back up to date. */
|
|
281
|
+
heard = '';
|
|
282
|
+
/** The dot-alone state `heard` was last decided under. */
|
|
283
|
+
bareState = null;
|
|
284
|
+
wasQuerying = false;
|
|
285
|
+
/** Whether a query has finished and its result is still to be said. */
|
|
286
|
+
resultDue = false;
|
|
287
|
+
/** Whether the strip has left a state it announced and has not yet said the view is up to date again. */
|
|
288
|
+
recoveryDue = false;
|
|
217
289
|
get status() {
|
|
218
290
|
return this.resolvedStore?.get('status') ?? null;
|
|
219
291
|
}
|
|
220
292
|
get view() {
|
|
221
293
|
return this.resolvedStore?.get('view') ?? null;
|
|
222
294
|
}
|
|
295
|
+
disconnectedCallback() {
|
|
296
|
+
this.query.stop();
|
|
297
|
+
super.disconnectedCallback();
|
|
298
|
+
}
|
|
299
|
+
willUpdate(changed) {
|
|
300
|
+
super.willUpdate(changed);
|
|
301
|
+
this.actionFocus.note(this.renderRoot);
|
|
302
|
+
const status = this.status;
|
|
303
|
+
const state = stateOf(status);
|
|
304
|
+
const querying = status?.querying === true;
|
|
305
|
+
const refresh = () => this.resolvedStore?.refresh();
|
|
306
|
+
const nothingVisible = seesNothing(this.resolvedStore, state);
|
|
307
|
+
// A query that has run long enough to name. The map may have drawn its answer while the
|
|
308
|
+
// counts still load, and a refusal, an expiry or a lost server is said in its own words.
|
|
309
|
+
const running = querying && this.query.named && (state === 'loading' || state === 'shown' || state === 'empty' || state === 'stale');
|
|
310
|
+
// Up to date and updating, the two states a pan moves between, are each a dot alone, so the
|
|
311
|
+
// strip keeps its width through a gesture; every other state names itself beside its dot.
|
|
312
|
+
const bare = !running && !nothingVisible && (state === 'shown' || (state === 'loading' && status?.sessionWarm === true));
|
|
313
|
+
// Nothing in view is announced as a query's answer. Where a pan went, it is shown and not said.
|
|
314
|
+
const answered = this.emptyAnswer.note(state, querying);
|
|
315
|
+
const panned = state === 'empty' && !running && !nothingVisible && !answered;
|
|
316
|
+
this.hear(state, bare, panned);
|
|
317
|
+
const words = stateWord(state, status);
|
|
318
|
+
const line = running
|
|
319
|
+
? { dot: null, words: 'Running query', action: html `<button part="cancel" class="btn small" type="button" @click=${() => this.cancel()}>Cancel</button>` }
|
|
320
|
+
: bare
|
|
321
|
+
? // Read and not drawn, and left out while the live region is saying the same words.
|
|
322
|
+
{ dot: state === 'shown' ? 'dot' : 'dot quiet', title: words, words: this.heard === words && !this.quiet ? nothing : html `<span class="sr-only">${words}</span>`, action: nothing }
|
|
323
|
+
: state === 'empty'
|
|
324
|
+
? { dot: 'dot quiet', words: nothingVisible ? NOTHING_VISIBLE : words, action: nothing }
|
|
325
|
+
: stateLine(state, status, { onRefresh: refresh, onRetry: refresh, onReauthorise: this.reauthorise });
|
|
326
|
+
this.shown = { state, running, bare, line, unsaid: this.quiet || panned ? UNSAID : bare ? { heard: this.heard } : null };
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Decide what the live region says while the strip shows a dot alone. A pan moves between up to
|
|
330
|
+
* date and updating and says nothing. A query that finishes says its result once the counts are
|
|
331
|
+
* in, or that the view is up to date where there are no counts to say, and a return from a
|
|
332
|
+
* state the strip announced says the view is up to date. Either is taken away at the next
|
|
333
|
+
* change, so that it is said again when it next holds.
|
|
334
|
+
*/
|
|
335
|
+
hear(state, bare, panned) {
|
|
336
|
+
const querying = this.status?.querying === true;
|
|
337
|
+
if (querying)
|
|
338
|
+
this.resultDue = false;
|
|
339
|
+
else if (this.wasQuerying)
|
|
340
|
+
this.resultDue = true;
|
|
341
|
+
this.wasQuerying = querying;
|
|
342
|
+
if (!bare) {
|
|
343
|
+
// The words shown are the answer. Where a pan went is not announced, so leaving it is not.
|
|
344
|
+
this.heard = '';
|
|
345
|
+
this.bareState = null;
|
|
346
|
+
this.resultDue = false;
|
|
347
|
+
if (!panned)
|
|
348
|
+
this.recoveryDue = state !== 'detached';
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (state !== this.bareState || querying)
|
|
352
|
+
this.heard = '';
|
|
353
|
+
this.bareState = state;
|
|
354
|
+
if (state !== 'shown' || querying)
|
|
355
|
+
return;
|
|
356
|
+
if (this.resultDue) {
|
|
357
|
+
// Counts still loading are waited for; refused or absent, the state is said in their place.
|
|
358
|
+
if (this.view?.inView?.status === 'loading')
|
|
359
|
+
return;
|
|
360
|
+
this.heard = this.result() ?? stateWord(state, this.status);
|
|
361
|
+
}
|
|
362
|
+
else if (this.recoveryDue)
|
|
363
|
+
this.heard = stateWord(state, this.status);
|
|
364
|
+
this.resultDue = false;
|
|
365
|
+
this.recoveryDue = false;
|
|
366
|
+
}
|
|
367
|
+
/** The counts as the cells show them, in full figures, or `null` where there are none to show. */
|
|
368
|
+
result() {
|
|
369
|
+
const v = this.view;
|
|
370
|
+
const n = v?.inView;
|
|
371
|
+
if (!v || !n || n.status !== 'shown')
|
|
372
|
+
return null;
|
|
373
|
+
const match = `${formatMasked(n.matched)} of ${formatMasked(n.visible)} match`;
|
|
374
|
+
if (!v.highlighting)
|
|
375
|
+
return match;
|
|
376
|
+
const lit = `${formatMasked(n.highlighted)} highlighted of ${formatMasked(n.matched)}`;
|
|
377
|
+
return this.resolvedStore?.requestFilters() != null ? `${match}, ${lit}` : lit;
|
|
378
|
+
}
|
|
223
379
|
updated() {
|
|
380
|
+
this.actionFocus.keep(this.renderRoot.querySelector('.cell.state'));
|
|
381
|
+
this.query.track(this.status?.querying ?? false);
|
|
224
382
|
const state = stateOf(this.status);
|
|
225
383
|
if (state !== this.lastState) {
|
|
226
384
|
const from = this.lastState;
|
|
@@ -235,29 +393,50 @@ let MosaicaStatus = (() => {
|
|
|
235
393
|
this.expiryFired = false;
|
|
236
394
|
}
|
|
237
395
|
}
|
|
396
|
+
/** Cancel the query, and tell the page what it went back to, as the controls that set those do. */
|
|
397
|
+
cancel() {
|
|
398
|
+
const s = this.resolvedStore;
|
|
399
|
+
if (!s)
|
|
400
|
+
return;
|
|
401
|
+
const was = { ...s.get('filters'), shape: s.get('region')?.shape ?? null };
|
|
402
|
+
s.cancelQuery();
|
|
403
|
+
const now = s.get('filters');
|
|
404
|
+
const differ = (a, b) => JSON.stringify(a) !== JSON.stringify(b);
|
|
405
|
+
if (differ(was.expr, now.expr))
|
|
406
|
+
emit(this, 'mosaica-filterchange', { column: null, verb: 'filter', expr: now.expr });
|
|
407
|
+
if (differ(was.highlight, now.highlight))
|
|
408
|
+
emit(this, 'mosaica-filterchange', { column: null, verb: 'highlight', expr: now.highlight });
|
|
409
|
+
const keyed = (clauses) => new Map(clauses.map((c) => [`${c.verb} ${c.outside} ${c.artifact} ${c.layer}`, c]));
|
|
410
|
+
const [before, after] = [keyed(was.members), keyed(now.members)];
|
|
411
|
+
const told = (c, on) => emit(this, 'mosaica-clausechange', { id: idString(c.artifact), layer: c.layer, outside: c.outside, verb: c.verb, on });
|
|
412
|
+
for (const [key, clause] of before)
|
|
413
|
+
if (!after.has(key))
|
|
414
|
+
told(clause, false);
|
|
415
|
+
for (const [key, clause] of after)
|
|
416
|
+
if (!before.has(key))
|
|
417
|
+
told(clause, true);
|
|
418
|
+
const shape = s.get('region')?.shape ?? null;
|
|
419
|
+
if (shape !== was.shape)
|
|
420
|
+
emit(this, 'mosaica-selectchange', { shape: shapeDetail(shape), status: shape ? 'loading' : 'cleared' });
|
|
421
|
+
const heldIn = (regions) => new Map(regions.map((r) => [r.view, r.shape]));
|
|
422
|
+
const [heldBefore, heldAfter] = [heldIn(was.regions), heldIn(now.regions)];
|
|
423
|
+
for (const view of heldBefore.keys())
|
|
424
|
+
if (!heldAfter.has(view))
|
|
425
|
+
emit(this, 'mosaica-selectchange', { shape: null, view, status: 'cleared' });
|
|
426
|
+
for (const [view, held] of heldAfter)
|
|
427
|
+
if (heldBefore.get(view) !== held)
|
|
428
|
+
emit(this, 'mosaica-selectchange', { shape: shapeDetail(held), view, status: 'loading' });
|
|
429
|
+
}
|
|
238
430
|
render() {
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
const stale = status?.stale ?? false;
|
|
431
|
+
const { state, running, bare, line, unsaid } = this.shown;
|
|
432
|
+
const stale = this.status?.stale ?? false;
|
|
242
433
|
const v = this.view;
|
|
243
|
-
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const dotAlone = state === 'shown' || (state === 'loading' && status?.sessionWarm === true) || nothingVisible;
|
|
250
|
-
const inner = state === 'shown'
|
|
251
|
-
? bare('dot', 'Up to date')
|
|
252
|
-
: nothingVisible
|
|
253
|
-
? bare('dot quiet', NOTHING_VISIBLE)
|
|
254
|
-
: dotAlone
|
|
255
|
-
? bare('dot quiet', 'Updating')
|
|
256
|
-
: state === 'empty'
|
|
257
|
-
? html `<span part="state" data-state="empty"><span class="dot quiet"></span>Nothing in view</span>`
|
|
258
|
-
: renderState(state, status, { onRefresh: refresh, onRetry: refresh, onReauthorise: this.reauthorise });
|
|
259
|
-
// One live element across every state, so each change of state is announced from it.
|
|
260
|
-
const first = html `<div class=${`cell state${dotAlone ? ' bare' : ''}`} role="status" aria-live="polite">${inner}</div>`;
|
|
434
|
+
// One template for every state, so the live element stays and each change of its words is
|
|
435
|
+
// announced. The state's button sits outside it, and the cell takes the focus when the
|
|
436
|
+
// button goes.
|
|
437
|
+
const first = html `<div class=${`cell state${bare ? ' bare' : ''}`} tabindex="-1">
|
|
438
|
+
<span part="state" data-state=${state} ?data-querying=${running}>${running ? html `<span part="spinner" class="spinner" aria-hidden="true"></span>` : nothing}${liveLine(line, unsaid)}</span>
|
|
439
|
+
</div>`;
|
|
261
440
|
return html `<div part="strip" data-state=${state}>${first}${this.counts(state, v, stale)}</div>
|
|
262
441
|
${this.expanded && showsContent(state) && v ? this.card(v, stale) : nothing}`;
|
|
263
442
|
}
|
|
@@ -293,14 +472,14 @@ let MosaicaStatus = (() => {
|
|
|
293
472
|
${this.compact ? nothing : html `<div class=${cls}><mosaica-count part="count-shown" .count=${{ shown: n.shown, total: n.matched.value, exact: true }} figure="shown" label="shown"></mosaica-count></div>`}`;
|
|
294
473
|
}
|
|
295
474
|
card(v, stale) {
|
|
296
|
-
const row = (label, value) => html `<
|
|
475
|
+
const row = (label, value) => html `<dt class="k">${label}</dt><dd class="v">${value}</dd>`;
|
|
297
476
|
const n = v.inView;
|
|
298
|
-
return html `<div part="card"><
|
|
477
|
+
return html `<div part="card"><dl class="kv">
|
|
299
478
|
${row('Shown', html `<mosaica-count .count=${n ? { shown: n.shown, total: n.matched.value, exact: true } : NO_COUNT} .stale=${stale}></mosaica-count>`)}
|
|
300
479
|
${row('Match the filters', html `<mosaica-count .masked=${n?.matched ?? NO_MASKED} .stale=${stale}></mosaica-count>`)}
|
|
301
480
|
${v.highlighting ? row('Highlighted', html `<mosaica-count .masked=${n?.highlighted ?? NO_MASKED} .stale=${stale}></mosaica-count>`) : nothing}
|
|
302
481
|
${row('In this view', html `<mosaica-count .masked=${n?.visible ?? NO_MASKED} .stale=${stale}></mosaica-count>`)}
|
|
303
|
-
</
|
|
482
|
+
</dl></div>`;
|
|
304
483
|
}
|
|
305
484
|
};
|
|
306
485
|
})();
|
package/dist/tokens.d.ts
CHANGED
|
@@ -19,16 +19,18 @@
|
|
|
19
19
|
* @cssprop --mosaica-ink - The colour of body text, values and map tools.
|
|
20
20
|
* @cssprop --mosaica-ink-2 - The colour of labels, section headings and secondary text.
|
|
21
21
|
* @cssprop --mosaica-ink-3 - The colour of faint text: placeholders, hints and disabled controls,
|
|
22
|
-
* and of the
|
|
22
|
+
* and of the ring in the loading states.
|
|
23
23
|
* @cssprop --mosaica-line - The colour of borders around panels, cards, buttons, chips and
|
|
24
24
|
* the map toolbar.
|
|
25
25
|
* @cssprop --mosaica-line-2 - The colour of the rules between sections and between the status
|
|
26
26
|
* strip's cells.
|
|
27
|
-
* @cssprop --mosaica-line-control - The colour of borders around inputs
|
|
28
|
-
* track, at 3:1 against the surface.
|
|
27
|
+
* @cssprop --mosaica-line-control - The colour of borders around inputs, of a slider's unfilled
|
|
28
|
+
* track and of a switch's track when it is off, at 3:1 against the surface.
|
|
29
29
|
* @cssprop --mosaica-accent - The colour of the active map tool, primary buttons, badges, checked
|
|
30
|
-
* boxes and
|
|
30
|
+
* boxes, a switch that is on, and the bar on a pressed segment and a chosen row.
|
|
31
31
|
* @cssprop --mosaica-accent-ink - The text colour on an accent background.
|
|
32
|
+
* @cssprop --mosaica-focus - The colour of the focus ring, at 3:1 or more against each surface and
|
|
33
|
+
* the map's background.
|
|
32
34
|
* @cssprop --mosaica-highlight - The colour of a highlight chip, a highlighted row's text and its ×.
|
|
33
35
|
* @cssprop --mosaica-highlight-soft - The background of a highlight chip and a highlighted row.
|
|
34
36
|
* @cssprop --mosaica-bar - The colour of a field card's bars for the items in view.
|
|
@@ -50,6 +52,8 @@
|
|
|
50
52
|
* @cssprop --mosaica-space - The gap between the content in the map's corners and the map's edges.
|
|
51
53
|
* Half of it separates items in one corner.
|
|
52
54
|
* @cssprop --mosaica-density - A multiplier on `--mosaica-space`'s default.
|
|
55
|
+
* @cssprop --mosaica-long-text - What a title or a name too long for its line does: `nowrap`, the
|
|
56
|
+
* default, cuts it with an ellipsis; `normal` wraps it.
|
|
53
57
|
* @cssprop --mosaica-map-height - The map's height.
|
|
54
58
|
*/
|
|
55
59
|
export declare const tokens: import("lit").CSSResult;
|