@mosaicajs/components 0.2.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 +118 -37
- package/dist/explorer.js +487 -212
- 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 +62 -14
- package/dist/item-card.js +310 -110
- 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 +1848 -832
- 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/colour-picker.js
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import { css, html, nothing } from 'lit';
|
|
2
2
|
import { hexOf, lighter, rgbOfHex } from '@mosaicajs/deck/internal';
|
|
3
3
|
import { hsvOf, rgbOfHsv } from './hsv.js';
|
|
4
|
+
import { icon } from './icons.js';
|
|
4
5
|
/** The width of the hue knob, which its travel along the bar allows for. */
|
|
5
6
|
const HUE_KNOB = 12;
|
|
6
7
|
/** How far each lighter colour is taken towards white. */
|
|
7
8
|
const LIGHTER = 0.45;
|
|
9
|
+
/** The most colours a palette is drawn with in one row; a larger one wraps, so each stays large enough to press. */
|
|
10
|
+
const ONE_ROW = 10;
|
|
8
11
|
/** The picker's width before it is measured. */
|
|
9
12
|
const WIDTH = 264;
|
|
10
13
|
/**
|
|
11
14
|
* The colour picker a swatch opens: the palette's colours and a lighter row of them, a custom area
|
|
12
15
|
* with a saturation and brightness square, a hue bar and a hex field, and Reset. A choice applies
|
|
13
16
|
* at once. It is shown in the top layer beside the rectangle `beside` gives, level with the swatch
|
|
14
|
-
* it was opened from,
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* it was opened from, or under or over that swatch's row where the window has no room beside, and
|
|
18
|
+
* focus goes into it; Escape, Tab past either end of it, or a press outside
|
|
19
|
+
* it and its swatch, closes it, the keys giving focus back to the swatch. A custom colour shows on
|
|
20
|
+
* the map as it is dragged and is reported as it is let go; a drag cancelled, or ended by closing
|
|
21
|
+
* the picker, puts back the colour from before it. Text in the hex field that is not a colour is
|
|
22
|
+
* kept and marked invalid, and the line under the field says what to write.
|
|
18
23
|
*
|
|
19
24
|
* The host renders {@link render} where the picker belongs in its tree and adds
|
|
20
25
|
* {@link pickerStyles} to its styles. The parts are the host's: `colour-popover`, `choice`, `sv`,
|
|
@@ -33,6 +38,8 @@ export class ColourPicker {
|
|
|
33
38
|
live = null;
|
|
34
39
|
/** What puts back the colour from before a drag, while one shows a colour not yet reported. */
|
|
35
40
|
restore = null;
|
|
41
|
+
/** What was typed in the hex field, while it is not a colour. */
|
|
42
|
+
typed = null;
|
|
36
43
|
constructor(host, beside) {
|
|
37
44
|
this.host = host;
|
|
38
45
|
this.beside = beside;
|
|
@@ -42,6 +49,7 @@ export class ColourPicker {
|
|
|
42
49
|
this.from = from;
|
|
43
50
|
this.hsv = hsvOf(rgbOfHex(target.current()) ?? [0, 0, 0]);
|
|
44
51
|
this.picking = target;
|
|
52
|
+
this.typed = null;
|
|
45
53
|
this.focusNext = true;
|
|
46
54
|
document.addEventListener('pointerdown', this.onOutside, true);
|
|
47
55
|
this.host.requestUpdate();
|
|
@@ -110,6 +118,7 @@ export class ColourPicker {
|
|
|
110
118
|
if (!target)
|
|
111
119
|
return;
|
|
112
120
|
this.hsv = hsvOf(rgbOfHex(hex ?? target.own) ?? [0, 0, 0]);
|
|
121
|
+
this.typed = null;
|
|
113
122
|
this.restore = null;
|
|
114
123
|
target.apply(hex, true);
|
|
115
124
|
this.host.requestUpdate();
|
|
@@ -129,6 +138,7 @@ export class ColourPicker {
|
|
|
129
138
|
const custom = hexOf(rgbOfHsv(this.hsv));
|
|
130
139
|
const setHsv = (next, final) => {
|
|
131
140
|
this.hsv = next;
|
|
141
|
+
this.typed = null;
|
|
132
142
|
this.host.requestUpdate();
|
|
133
143
|
this.applyLive(hexOf(rgbOfHsv(next)), final);
|
|
134
144
|
};
|
|
@@ -183,51 +193,69 @@ export class ColourPicker {
|
|
|
183
193
|
e.preventDefault();
|
|
184
194
|
setHsv([(next + 360) % 360, sat, val], true);
|
|
185
195
|
};
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
196
|
+
const invalid = this.typed !== null;
|
|
197
|
+
const hexShown = this.typed ?? custom.toUpperCase();
|
|
198
|
+
/** Take the hex field's text as the colour, or keep it as typed where it is not one. */
|
|
199
|
+
const hexChanged = (input) => {
|
|
200
|
+
const text = input.value.trim();
|
|
201
|
+
const c = rgbOfHex(text.startsWith('#') ? text : `#${text}`);
|
|
202
|
+
if (c)
|
|
203
|
+
return this.choose(hexOf(c));
|
|
204
|
+
this.typed = text;
|
|
205
|
+
this.host.requestUpdate();
|
|
206
|
+
};
|
|
207
|
+
const onKey = (e) => {
|
|
208
|
+
const stops = Array.from(e.currentTarget.querySelectorAll('button, input, [tabindex="0"]'));
|
|
209
|
+
const leaves = e.key === 'Tab' && e.target === (e.shiftKey ? stops[0] : stops.at(-1));
|
|
210
|
+
if (e.key !== 'Escape' && !leaves)
|
|
189
211
|
return;
|
|
190
212
|
e.stopPropagation();
|
|
191
213
|
e.preventDefault();
|
|
214
|
+
// Tab out of the hex field takes its text first, and stays where that is not a colour.
|
|
215
|
+
if (leaves && e.target instanceof HTMLInputElement && e.target.value.trim().toUpperCase() !== hexShown.toUpperCase()) {
|
|
216
|
+
hexChanged(e.target);
|
|
217
|
+
if (this.typed !== null)
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
192
220
|
this.close(true);
|
|
193
|
-
}
|
|
221
|
+
};
|
|
222
|
+
const choice = ({ hex, label }) => html `<button part="choice" type="button" style=${`background:${hex}`} aria-label=${`${label}, ${hex}`} title=${`${label}, ${hex}`}
|
|
223
|
+
aria-pressed=${hex === current ? 'true' : 'false'} @click=${() => this.choose(hex)}>${hex === current ? icon('check', 14, 2) : nothing}</button>`;
|
|
224
|
+
return html `<div part="colour-popover" class="pop" popover="manual" role="dialog" aria-label=${`Colour of ${p.title}`}
|
|
225
|
+
@keydown=${onKey}
|
|
194
226
|
@focusout=${(e) => {
|
|
195
227
|
const to = e.relatedTarget;
|
|
196
228
|
if (to && !e.currentTarget.contains(to))
|
|
197
229
|
this.close(false);
|
|
198
230
|
}}>
|
|
199
231
|
<div class="top"><span class="t">${p.title}</span><button part="reset" class="quiet" type="button" @click=${() => this.choose(null)}>Reset</button></div>
|
|
200
|
-
<div class="choices" role="group" aria-label="Palette colours" style=${
|
|
201
|
-
|
|
202
|
-
|
|
232
|
+
<div class="choices" role="group" aria-label="Palette colours" style=${n > ONE_ROW ? nothing : `--columns:repeat(${n}, minmax(0, 1fr))`}>
|
|
233
|
+
<div class="set">${choices.slice(0, n).map(choice)}</div>
|
|
234
|
+
<div class="set">${choices.slice(n).map(choice)}</div>
|
|
203
235
|
</div>
|
|
204
|
-
<div class="hd">Custom</div>
|
|
205
|
-
<div class="custom">
|
|
236
|
+
<div class="hd" id="picker-custom">Custom</div>
|
|
237
|
+
<div class="custom" role="group" aria-labelledby="picker-custom">
|
|
206
238
|
<div part="sv" role="slider" tabindex="0" aria-label="Saturation and brightness" aria-valuemin="0" aria-valuemax="100" aria-valuenow=${Math.round(sat * 100)}
|
|
207
239
|
aria-valuetext=${`Saturation ${Math.round(sat * 100)}%, brightness ${Math.round(val * 100)}%`}
|
|
208
240
|
style=${`background:linear-gradient(to top, #000000, rgba(0, 0, 0, 0)), linear-gradient(to right, #ffffff, hsl(${h.toFixed(0)}, 100%, 50%))`}
|
|
209
241
|
@pointerdown=${sv.down} @pointermove=${sv.move} @pointerup=${sv.up} @pointercancel=${sv.cancel} @keydown=${svKey}>
|
|
210
242
|
<span class="knob" style=${`left:${(sat * 100).toFixed(1)}%;top:${((1 - val) * 100).toFixed(1)}%`}></span>
|
|
211
243
|
</div>
|
|
212
|
-
<div part="hue" role="slider" tabindex="0" aria-label="Hue" aria-valuemin="0" aria-valuemax="359" aria-valuenow=${Math.round(h)}
|
|
244
|
+
<div part="hue" role="slider" tabindex="0" aria-label="Hue" aria-valuemin="0" aria-valuemax="359" aria-valuenow=${Math.round(h)} aria-valuetext=${`${Math.round(h)} degrees`}
|
|
213
245
|
@pointerdown=${hue.down} @pointermove=${hue.move} @pointerup=${hue.up} @pointercancel=${hue.cancel} @keydown=${hueKey}>
|
|
214
246
|
<span class="knob" style=${`left:calc(${HUE_KNOB / 2}px + (100% - ${HUE_KNOB}px) * ${(h / 360).toFixed(4)})`}></span>
|
|
215
247
|
</div>
|
|
216
|
-
<label>Hex<input part="hex" type="text" spellcheck="false" .value=${
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const c = rgbOfHex(text.startsWith('#') ? text : `#${text}`);
|
|
221
|
-
if (!c) {
|
|
222
|
-
input.value = custom.toUpperCase();
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
this.choose(hexOf(c));
|
|
226
|
-
}} /></label>
|
|
248
|
+
<label>Hex<input part="hex" type="text" spellcheck="false" .value=${hexShown}
|
|
249
|
+
aria-invalid=${invalid ? 'true' : 'false'} aria-describedby="picker-hex-format"
|
|
250
|
+
@change=${(e) => hexChanged(e.target)} /></label>
|
|
251
|
+
<span id="picker-hex-format" class=${invalid ? 'format' : 'format sr-only'} role="status">${invalid ? 'Not a colour. Write # and six hex digits, such as #1B9E77.' : '# and six hex digits, such as #1B9E77'}</span>
|
|
227
252
|
</div>
|
|
228
253
|
</div>`;
|
|
229
254
|
}
|
|
230
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* Show the picker in the top layer, beside {@link beside} and level with its swatch, or, where
|
|
257
|
+
* neither side has room, under or over its swatch's row; focus goes into it as it opens.
|
|
258
|
+
*/
|
|
231
259
|
place() {
|
|
232
260
|
const pop = this.host.renderRoot.querySelector('.pop');
|
|
233
261
|
const from = this.from;
|
|
@@ -243,15 +271,29 @@ export class ColourPicker {
|
|
|
243
271
|
}
|
|
244
272
|
const a = from.getBoundingClientRect();
|
|
245
273
|
const own = this.beside();
|
|
274
|
+
pop.style.maxHeight = '';
|
|
246
275
|
const width = pop.offsetWidth || WIDTH;
|
|
247
|
-
|
|
276
|
+
let height = pop.offsetHeight || 0;
|
|
248
277
|
const vw = typeof innerWidth === 'number' ? innerWidth : 1024;
|
|
249
278
|
const vh = typeof innerHeight === 'number' ? innerHeight : 768;
|
|
250
279
|
let left = own.right + 12;
|
|
251
280
|
if (left + width > vw - 8)
|
|
252
281
|
left = own.left - width - 12;
|
|
282
|
+
let top = a.top - 8;
|
|
283
|
+
if (left < 8) {
|
|
284
|
+
// No room on either side: under the row it was opened from, or over it where that has more
|
|
285
|
+
// room, and no taller than the room, so the row stays in sight.
|
|
286
|
+
const row = (from.closest('[part~="row"]') ?? from).getBoundingClientRect();
|
|
287
|
+
const under = vh - row.bottom - 16;
|
|
288
|
+
const over = row.top - 16;
|
|
289
|
+
const below = under >= height || under >= over;
|
|
290
|
+
height = Math.min(height, Math.max(0, below ? under : over));
|
|
291
|
+
pop.style.maxHeight = `${height}px`;
|
|
292
|
+
left = a.left;
|
|
293
|
+
top = below ? row.bottom + 8 : row.top - 8 - height;
|
|
294
|
+
}
|
|
253
295
|
pop.style.left = `${Math.round(Math.max(8, Math.min(left, vw - width - 8)))}px`;
|
|
254
|
-
pop.style.top = `${Math.round(Math.max(8, Math.min(
|
|
296
|
+
pop.style.top = `${Math.round(Math.max(8, Math.min(top, vh - height - 8)))}px`;
|
|
255
297
|
if (this.focusNext) {
|
|
256
298
|
this.focusNext = false;
|
|
257
299
|
(pop.querySelector('[aria-pressed="true"]') ?? pop.querySelector('button'))?.focus();
|
|
@@ -276,9 +318,6 @@ export const pickerStyles = css `
|
|
|
276
318
|
max-height: calc(100vh - 16px);
|
|
277
319
|
overflow-y: auto;
|
|
278
320
|
}
|
|
279
|
-
.pop button:focus-visible {
|
|
280
|
-
outline-offset: -2px;
|
|
281
|
-
}
|
|
282
321
|
.pop .top {
|
|
283
322
|
display: flex;
|
|
284
323
|
align-items: center;
|
|
@@ -287,26 +326,58 @@ export const pickerStyles = css `
|
|
|
287
326
|
padding: 12px 14px 8px;
|
|
288
327
|
}
|
|
289
328
|
.pop .top .t {
|
|
329
|
+
min-width: 0;
|
|
290
330
|
font-weight: 600;
|
|
291
331
|
overflow: hidden;
|
|
292
332
|
text-overflow: ellipsis;
|
|
293
|
-
white-space:
|
|
333
|
+
white-space: var(--_mosaica-long-text);
|
|
334
|
+
overflow-wrap: anywhere;
|
|
335
|
+
}
|
|
336
|
+
/* Drawn as a line of text, with a target 24 px high and at least as wide around it. */
|
|
337
|
+
.pop [part='reset'] {
|
|
338
|
+
position: relative;
|
|
339
|
+
flex: none;
|
|
340
|
+
}
|
|
341
|
+
.pop [part='reset']::before {
|
|
342
|
+
content: '';
|
|
343
|
+
position: absolute;
|
|
344
|
+
inset: -4px 0;
|
|
345
|
+
min-width: 24px;
|
|
294
346
|
}
|
|
295
347
|
.pop .choices {
|
|
296
348
|
display: grid;
|
|
297
349
|
gap: 6px;
|
|
298
350
|
padding: 0 14px 10px;
|
|
299
351
|
}
|
|
352
|
+
/* A palette's colours: in one row for a palette of up to ten, else in as many rows as keep
|
|
353
|
+
each at least 24 px square. */
|
|
354
|
+
.pop .set {
|
|
355
|
+
display: grid;
|
|
356
|
+
grid-template-columns: var(--columns, repeat(auto-fit, minmax(24px, 1fr)));
|
|
357
|
+
gap: 6px;
|
|
358
|
+
}
|
|
300
359
|
[part='choice'] {
|
|
360
|
+
display: grid;
|
|
361
|
+
place-items: center;
|
|
301
362
|
aspect-ratio: 1;
|
|
302
363
|
width: 100%;
|
|
303
364
|
border-radius: 5px;
|
|
365
|
+
forced-color-adjust: none;
|
|
366
|
+
}
|
|
367
|
+
/* The ring stands clear of the colour, on the surface, whatever the colour is. */
|
|
368
|
+
[part='choice']:focus-visible {
|
|
369
|
+
outline-offset: 2px;
|
|
304
370
|
}
|
|
305
371
|
[part='choice'][aria-pressed='true'] {
|
|
306
372
|
box-shadow:
|
|
307
373
|
0 0 0 2px var(--_mosaica-surface),
|
|
308
374
|
0 0 0 3.5px var(--_mosaica-ink);
|
|
309
375
|
}
|
|
376
|
+
/* The chosen colour's tick, light with a dark edge, so it shows on any colour. */
|
|
377
|
+
[part='choice'] svg {
|
|
378
|
+
color: #ffffff;
|
|
379
|
+
filter: drop-shadow(0 0 1px #000000) drop-shadow(0 0 1px #000000);
|
|
380
|
+
}
|
|
310
381
|
.pop .hd {
|
|
311
382
|
margin: 0;
|
|
312
383
|
padding: 10px 14px 4px;
|
|
@@ -323,6 +394,7 @@ export const pickerStyles = css `
|
|
|
323
394
|
position: relative;
|
|
324
395
|
touch-action: none;
|
|
325
396
|
cursor: crosshair;
|
|
397
|
+
forced-color-adjust: none;
|
|
326
398
|
}
|
|
327
399
|
[part='sv'] {
|
|
328
400
|
height: 120px;
|
|
@@ -333,6 +405,12 @@ export const pickerStyles = css `
|
|
|
333
405
|
border-radius: 5px;
|
|
334
406
|
background: linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
|
|
335
407
|
}
|
|
408
|
+
/* The bar's target is 24 px high around it. */
|
|
409
|
+
[part='hue']::before {
|
|
410
|
+
content: '';
|
|
411
|
+
position: absolute;
|
|
412
|
+
inset: -7px 0;
|
|
413
|
+
}
|
|
336
414
|
.pop .knob {
|
|
337
415
|
position: absolute;
|
|
338
416
|
width: 12px;
|
|
@@ -358,4 +436,13 @@ export const pickerStyles = css `
|
|
|
358
436
|
font-size: 12px;
|
|
359
437
|
font-variant-numeric: tabular-nums;
|
|
360
438
|
}
|
|
439
|
+
[part='hex'][aria-invalid='true'] {
|
|
440
|
+
border-color: var(--_mosaica-refuse);
|
|
441
|
+
}
|
|
442
|
+
/* What the hex field takes: read out with the field, and drawn only as what is wrong with an entry. */
|
|
443
|
+
.pop .format {
|
|
444
|
+
font-size: 12px;
|
|
445
|
+
color: var(--_mosaica-refuse);
|
|
446
|
+
font-weight: 500;
|
|
447
|
+
}
|
|
361
448
|
`;
|
package/dist/display.js
CHANGED
|
@@ -88,12 +88,13 @@ export const displayStyles = css `
|
|
|
88
88
|
font-weight: 500;
|
|
89
89
|
}
|
|
90
90
|
/* A slider: a thin track filled to the thumb, as far as its --fill says. */
|
|
91
|
+
/* The slider's box is 24 px high for the pointer and takes 16 px of its row. */
|
|
91
92
|
.slider {
|
|
92
93
|
-webkit-appearance: none;
|
|
93
94
|
appearance: none;
|
|
94
95
|
width: 100%;
|
|
95
|
-
height:
|
|
96
|
-
margin: 0;
|
|
96
|
+
height: 24px;
|
|
97
|
+
margin: -4px 0;
|
|
97
98
|
padding: 0;
|
|
98
99
|
border: 0;
|
|
99
100
|
background: none;
|
|
@@ -148,7 +149,7 @@ export const displayStyles = css `
|
|
|
148
149
|
}
|
|
149
150
|
.modes button[aria-checked='true'] {
|
|
150
151
|
background: var(--_mosaica-surface);
|
|
151
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
|
152
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), inset 0 -2px 0 var(--_mosaica-accent);
|
|
152
153
|
color: var(--_mosaica-ink);
|
|
153
154
|
font-weight: 600;
|
|
154
155
|
}
|
|
@@ -190,9 +191,16 @@ export const displayStyles = css `
|
|
|
190
191
|
color: var(--_mosaica-ink);
|
|
191
192
|
font-weight: 500;
|
|
192
193
|
}
|
|
193
|
-
/* Edit colours sits under the choices, as wide as its words. */
|
|
194
|
-
.edit-colours {
|
|
194
|
+
/* Edit colours sits under the choices, as wide as its words, 22 px high inside a pointer's target of 24. */
|
|
195
|
+
.btn.edit-colours {
|
|
196
|
+
position: relative;
|
|
195
197
|
align-self: flex-start;
|
|
198
|
+
height: 22px;
|
|
199
|
+
}
|
|
200
|
+
.btn.edit-colours::after {
|
|
201
|
+
content: '';
|
|
202
|
+
position: absolute;
|
|
203
|
+
inset: -2px -1px;
|
|
196
204
|
}
|
|
197
205
|
.ramp-choice {
|
|
198
206
|
display: flex;
|
|
@@ -251,12 +259,15 @@ export const displayStyles = css `
|
|
|
251
259
|
.toggle[aria-pressed='true'] {
|
|
252
260
|
border-color: var(--_mosaica-accent);
|
|
253
261
|
background: var(--_mosaica-accent);
|
|
262
|
+
box-shadow: inset 0 -2px 0 var(--_mosaica-accent-ink);
|
|
254
263
|
color: var(--_mosaica-accent-ink);
|
|
255
264
|
}
|
|
256
265
|
.ramp-choice .t {
|
|
257
266
|
overflow: hidden;
|
|
258
267
|
text-overflow: ellipsis;
|
|
259
|
-
white-space:
|
|
268
|
+
white-space: var(--_mosaica-long-text);
|
|
269
|
+
overflow-wrap: anywhere;
|
|
270
|
+
text-align: left;
|
|
260
271
|
}
|
|
261
272
|
.ramp-choice:disabled {
|
|
262
273
|
opacity: 0.4;
|
|
@@ -310,16 +321,20 @@ export const displayStyles = css `
|
|
|
310
321
|
}
|
|
311
322
|
.seg button[aria-checked='true'] {
|
|
312
323
|
background: var(--_mosaica-surface);
|
|
313
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
|
324
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), inset 0 -2px 0 var(--_mosaica-accent);
|
|
314
325
|
color: var(--_mosaica-ink);
|
|
315
326
|
font-weight: 600;
|
|
316
327
|
}
|
|
317
|
-
/*
|
|
328
|
+
/* A choice's menu, in the top layer beside the popover: no larger than the window, scrolling inside. */
|
|
318
329
|
.size-menu {
|
|
319
330
|
position: fixed;
|
|
320
331
|
inset: auto;
|
|
321
332
|
margin: 0;
|
|
322
333
|
width: 220px;
|
|
334
|
+
max-width: calc(100vw - 16px);
|
|
335
|
+
max-height: calc(100dvh - 16px);
|
|
336
|
+
overflow-y: auto;
|
|
337
|
+
overscroll-behavior: contain;
|
|
323
338
|
padding: 6px 0;
|
|
324
339
|
box-sizing: border-box;
|
|
325
340
|
background: var(--_mosaica-surface);
|
|
@@ -402,6 +417,30 @@ export const displayStyles = css `
|
|
|
402
417
|
align-items: center;
|
|
403
418
|
gap: 8px;
|
|
404
419
|
}
|
|
420
|
+
/* The tick on the entry chosen takes no room: in a menu entry's left padding, at the right of a
|
|
421
|
+
palette's title line, and at the right of a density ramp's row. */
|
|
422
|
+
.size-menu [role='menuitemradio'],
|
|
423
|
+
.ramp-list button {
|
|
424
|
+
position: relative;
|
|
425
|
+
}
|
|
426
|
+
.tick {
|
|
427
|
+
position: absolute;
|
|
428
|
+
left: 1px;
|
|
429
|
+
top: 50%;
|
|
430
|
+
display: flex;
|
|
431
|
+
translate: 0 -50%;
|
|
432
|
+
pointer-events: none;
|
|
433
|
+
}
|
|
434
|
+
.size-menu.palettes .tick {
|
|
435
|
+
left: auto;
|
|
436
|
+
right: 10px;
|
|
437
|
+
top: 12px;
|
|
438
|
+
translate: none;
|
|
439
|
+
}
|
|
440
|
+
.ramp-list .tick {
|
|
441
|
+
left: auto;
|
|
442
|
+
right: 6px;
|
|
443
|
+
}
|
|
405
444
|
.size-menu .kind {
|
|
406
445
|
font-size: 12px;
|
|
407
446
|
font-weight: 400;
|
|
@@ -431,8 +470,37 @@ export const displayStyles = css `
|
|
|
431
470
|
font-size: 12px;
|
|
432
471
|
color: var(--_mosaica-ink);
|
|
433
472
|
}
|
|
434
|
-
.ramp-list button:hover
|
|
473
|
+
.ramp-list button:hover {
|
|
474
|
+
background: var(--_mosaica-surface-2);
|
|
475
|
+
}
|
|
435
476
|
.ramp-list button[aria-checked='true'] {
|
|
436
477
|
background: var(--_mosaica-surface-2);
|
|
437
478
|
}
|
|
479
|
+
/* A palette's or a ramp's colours are what it is, so they keep them under forced colours; a
|
|
480
|
+
slider's track and thumb are drawn in backgrounds, and take system colours. */
|
|
481
|
+
@media (forced-colors: active) {
|
|
482
|
+
.bar,
|
|
483
|
+
.strip span,
|
|
484
|
+
.swatches span {
|
|
485
|
+
forced-color-adjust: none;
|
|
486
|
+
}
|
|
487
|
+
.slider::-webkit-slider-runnable-track {
|
|
488
|
+
forced-color-adjust: none;
|
|
489
|
+
background: linear-gradient(to right, Highlight var(--fill, 0%), GrayText var(--fill, 0%));
|
|
490
|
+
}
|
|
491
|
+
.slider::-moz-range-track {
|
|
492
|
+
forced-color-adjust: none;
|
|
493
|
+
background: linear-gradient(to right, Highlight var(--fill, 0%), GrayText var(--fill, 0%));
|
|
494
|
+
}
|
|
495
|
+
.slider::-webkit-slider-thumb {
|
|
496
|
+
forced-color-adjust: none;
|
|
497
|
+
border-color: ButtonText;
|
|
498
|
+
background: ButtonFace;
|
|
499
|
+
}
|
|
500
|
+
.slider::-moz-range-thumb {
|
|
501
|
+
forced-color-adjust: none;
|
|
502
|
+
border-color: ButtonText;
|
|
503
|
+
background: ButtonFace;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
438
506
|
`;
|
package/dist/events.d.ts
CHANGED
|
@@ -80,9 +80,13 @@ export type MosaicaEventDetails = {
|
|
|
80
80
|
* selection was cleared. It fires with `status` `loading` when a shape is selected or `cleared`
|
|
81
81
|
* when it is cleared, then again with `shown` or `refused` when the server answers. Then `visible`, `matched` and
|
|
82
82
|
* `served` carry the region's counts, and `verdict` says whether they are exact for the shape.
|
|
83
|
+
* `view` names the view whose selection changed where it is not the current one, as when the
|
|
84
|
+
* filter panel's chip for a selection held in another view is removed, or the status strip's
|
|
85
|
+
* Cancel puts one back.
|
|
83
86
|
*/
|
|
84
87
|
'mosaica-selectchange': {
|
|
85
88
|
shape: SelectionShapeDetail | null;
|
|
89
|
+
view?: string;
|
|
86
90
|
status?: RegionProjection['status'] | 'cleared';
|
|
87
91
|
visible?: Masked | null;
|
|
88
92
|
matched?: Masked;
|
|
@@ -118,12 +122,21 @@ export type MosaicaEventDetails = {
|
|
|
118
122
|
'mosaica-budgetchange': {
|
|
119
123
|
budget: number;
|
|
120
124
|
};
|
|
121
|
-
/**
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
/**
|
|
126
|
+
* The Cluster density slider was released. Each cluster is now given a square `spacing` CSS pixels
|
|
127
|
+
* on a side of the map, so a `nested` or `dag` layer is cut to as many clusters as such squares
|
|
128
|
+
* fit the map, and a level that follows the zoom is one with no more than that many in view.
|
|
129
|
+
*/
|
|
130
|
+
'mosaica-clusterspacingchange': {
|
|
131
|
+
spacing: number;
|
|
124
132
|
};
|
|
125
|
-
/**
|
|
133
|
+
/**
|
|
134
|
+
* The level that the clusters of the layer `layer` are counted, coloured and labelled at is now
|
|
135
|
+
* `level`. Null is that layer's default level, which follows the zoom on a layer whose levels
|
|
136
|
+
* declare no zoom range. Other layers keep theirs.
|
|
137
|
+
*/
|
|
126
138
|
'mosaica-levelchange': {
|
|
139
|
+
layer: string;
|
|
127
140
|
level: number | null;
|
|
128
141
|
};
|
|
129
142
|
/**
|
|
@@ -181,9 +194,10 @@ export type MosaicaEventDetails = {
|
|
|
181
194
|
};
|
|
182
195
|
/**
|
|
183
196
|
* A filter or highlight changed. `column` is the column whose control changed, or null for Clear
|
|
184
|
-
* all
|
|
185
|
-
* After an edit, `expr` is the combined expression of
|
|
186
|
-
* null if there are none. When a chip is removed, or
|
|
197
|
+
* all, for clearing the highlight and for a cancelled query. `verb` is `filter` or `highlight`
|
|
198
|
+
* (`filter` if absent). After an edit or a cancelled query, `expr` is the combined expression of
|
|
199
|
+
* every control's clause for that `verb`, or null if there are none. When a chip is removed, or
|
|
200
|
+
* Clear all is pressed, `expr` is null.
|
|
187
201
|
* `member_of` clauses are reported by `mosaica-clausechange`.
|
|
188
202
|
*/
|
|
189
203
|
'mosaica-filterchange': {
|