@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.
Files changed (52) hide show
  1. package/README.md +2 -0
  2. package/dist/aggregate.d.ts +4 -10
  3. package/dist/aggregate.js +7 -13
  4. package/dist/artifact-card.d.ts +21 -7
  5. package/dist/artifact-card.js +136 -79
  6. package/dist/base.d.ts +44 -5
  7. package/dist/base.js +54 -5
  8. package/dist/cluster-filter.d.ts +29 -25
  9. package/dist/cluster-filter.js +123 -106
  10. package/dist/colour-editor.d.ts +15 -4
  11. package/dist/colour-editor.js +107 -34
  12. package/dist/colour-picker.d.ts +12 -5
  13. package/dist/colour-picker.js +119 -32
  14. package/dist/display.js +77 -9
  15. package/dist/events.d.ts +21 -7
  16. package/dist/explorer.d.ts +118 -37
  17. package/dist/explorer.js +487 -212
  18. package/dist/field-card.d.ts +304 -48
  19. package/dist/field-card.js +1364 -244
  20. package/dist/filter-panel.d.ts +54 -10
  21. package/dist/filter-panel.js +242 -42
  22. package/dist/filter.d.ts +22 -4
  23. package/dist/filter.js +113 -34
  24. package/dist/hierarchy.d.ts +68 -45
  25. package/dist/hierarchy.js +320 -243
  26. package/dist/item-card.d.ts +62 -14
  27. package/dist/item-card.js +310 -110
  28. package/dist/key-picker.d.ts +2 -1
  29. package/dist/key-picker.js +4 -3
  30. package/dist/layer-picker.d.ts +4 -2
  31. package/dist/layer-picker.js +16 -7
  32. package/dist/lineage.d.ts +132 -0
  33. package/dist/lineage.js +307 -0
  34. package/dist/map.d.ts +135 -24
  35. package/dist/map.js +387 -117
  36. package/dist/mosaica-components.js +1848 -832
  37. package/dist/mosaica-components.js.sri +1 -1
  38. package/dist/mosaica-components.json +2 -2
  39. package/dist/parts.d.ts +4 -4
  40. package/dist/parts.js +18 -4
  41. package/dist/paths.d.ts +34 -12
  42. package/dist/paths.js +84 -46
  43. package/dist/selection.d.ts +22 -3
  44. package/dist/selection.js +125 -59
  45. package/dist/states.d.ts +72 -0
  46. package/dist/states.js +135 -26
  47. package/dist/status.d.ts +63 -5
  48. package/dist/status.js +215 -36
  49. package/dist/tokens.d.ts +8 -4
  50. package/dist/tokens.js +144 -14
  51. package/dist/view-picker.js +5 -0
  52. package/package.json +4 -3
@@ -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, and focus goes into it; Escape, or a press outside it and its swatch, closes
15
- * it, Escape giving focus back to the swatch. A custom colour shows on the map as it is dragged and
16
- * is reported as it is let go; a drag cancelled, or ended by closing the picker, puts back the
17
- * colour from before it.
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
- return html `<div part="colour-popover" class="pop" popover="manual" role="dialog" aria-label=${`Colour of ${p.title}`}
187
- @keydown=${(e) => {
188
- if (e.key !== 'Escape')
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=${`grid-template-columns:repeat(${n}, minmax(0, 1fr))`}>
201
- ${choices.map(({ hex, label }) => html `<button part="choice" type="button" style=${`background:${hex}`} aria-label=${`${label}, ${hex}`} title=${`${label}, ${hex}`}
202
- aria-pressed=${hex === current ? 'true' : 'false'} @click=${() => this.choose(hex)}></button>`)}
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=${custom.toUpperCase()}
217
- @change=${(e) => {
218
- const input = e.target;
219
- const text = input.value.trim();
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
- /** Show the picker in the top layer, beside {@link beside} and level with its swatch; focus goes into it as it opens. */
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
- const height = pop.offsetHeight || 0;
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(a.top - 8, vh - height - 8)))}px`;
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: nowrap;
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: 16px;
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: nowrap;
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
- /* The Size by menu, in the top layer beside the popover. */
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
- /** The Most clusters slider was released. A `nested` or `dag` layer is now cut to at most `budget` clusters. */
122
- 'mosaica-clusterbudgetchange': {
123
- budget: number;
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
- /** The level that clusters are coloured and labelled at is now `level`. Null is the default level. */
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 and for clearing the highlight. `verb` is `filter` or `highlight` (`filter` if absent).
185
- * After an edit, `expr` is the combined expression of every control's clause for that `verb`, or
186
- * null if there are none. When a chip is removed, or Clear all is pressed, `expr` is null.
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': {