@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
@@ -37,8 +37,9 @@ import { property, state } from 'lit/decorators.js';
37
37
  import { repeat } from 'lit/directives/repeat.js';
38
38
  import { CLUSTER_PREFIX, PALETTES, artifactColour, colourLayers } from '@mosaicajs/client';
39
39
  import { CATEGORY_PALETTES } from '@mosaicajs/deck';
40
+ import { levelOfLayer } from '@mosaicajs/client/internal';
40
41
  import { hexOf } from '@mosaicajs/deck/internal';
41
- import { HeldAggregate, artifactGroupings, isTree, levelOf, listedGroups, rankedGrouping } from './aggregate.js';
42
+ import { HeldAggregate, artifactGroupings, isTree, listedGroups, rankedGrouping } from './aggregate.js';
42
43
  import { MosaicaElement, UNNAMED, columnCaption, countText, emit, idString, keyTitle } from './base.js';
43
44
  import { ColourPicker, pickerStyles } from './colour-picker.js';
44
45
  import { clusterColour, colouringOf, holdColours, paletteValueColour, setClusterColours, setValueColours, valueColour, valueMet, watchChoices } from './colouring.js';
@@ -49,8 +50,6 @@ import { ClusterPaths } from './paths.js';
49
50
  import { chrome, tokens } from './tokens.js';
50
51
  import './filter.js';
51
52
  import './cluster-filter.js';
52
- /** The height of a row in pixels, from which the rows in sight are worked out. */
53
- const ROW_HEIGHT = 40;
54
53
  /** The rows whose paths are asked for before the list has been measured. */
55
54
  const FIRST_ROWS = 8;
56
55
  /**
@@ -108,9 +107,9 @@ let MosaicaColourEditor = (() => {
108
107
  let _field_decorators;
109
108
  let _field_initializers = [];
110
109
  let _field_extraInitializers = [];
111
- let _level_decorators;
112
- let _level_initializers = [];
113
- let _level_extraInitializers = [];
110
+ let _clusterLevels_decorators;
111
+ let _clusterLevels_initializers = [];
112
+ let _clusterLevels_extraInitializers = [];
114
113
  let _isOpen_decorators;
115
114
  let _isOpen_initializers = [];
116
115
  let _isOpen_extraInitializers = [];
@@ -124,12 +123,12 @@ let MosaicaColourEditor = (() => {
124
123
  static {
125
124
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
126
125
  _field_decorators = [property()];
127
- _level_decorators = [property({ type: Number, attribute: 'cluster-level' })];
126
+ _clusterLevels_decorators = [property({ attribute: false })];
128
127
  _isOpen_decorators = [state()];
129
128
  _ticked_decorators = [state()];
130
129
  _found_decorators = [state()];
131
130
  __esDecorate(this, null, _field_decorators, { kind: "accessor", name: "field", static: false, private: false, access: { has: obj => "field" in obj, get: obj => obj.field, set: (obj, value) => { obj.field = value; } }, metadata: _metadata }, _field_initializers, _field_extraInitializers);
132
- __esDecorate(this, null, _level_decorators, { kind: "accessor", name: "level", static: false, private: false, access: { has: obj => "level" in obj, get: obj => obj.level, set: (obj, value) => { obj.level = value; } }, metadata: _metadata }, _level_initializers, _level_extraInitializers);
131
+ __esDecorate(this, null, _clusterLevels_decorators, { kind: "accessor", name: "clusterLevels", static: false, private: false, access: { has: obj => "clusterLevels" in obj, get: obj => obj.clusterLevels, set: (obj, value) => { obj.clusterLevels = value; } }, metadata: _metadata }, _clusterLevels_initializers, _clusterLevels_extraInitializers);
133
132
  __esDecorate(this, null, _isOpen_decorators, { kind: "accessor", name: "isOpen", static: false, private: false, access: { has: obj => "isOpen" in obj, get: obj => obj.isOpen, set: (obj, value) => { obj.isOpen = value; } }, metadata: _metadata }, _isOpen_initializers, _isOpen_extraInitializers);
134
133
  __esDecorate(this, null, _ticked_decorators, { kind: "accessor", name: "ticked", static: false, private: false, access: { has: obj => "ticked" in obj, get: obj => obj.ticked, set: (obj, value) => { obj.ticked = value; } }, metadata: _metadata }, _ticked_initializers, _ticked_extraInitializers);
135
134
  __esDecorate(this, null, _found_decorators, { kind: "accessor", name: "found", static: false, private: false, access: { has: obj => "found" in obj, get: obj => obj.found, set: (obj, value) => { obj.found = value; } }, metadata: _metadata }, _found_initializers, _found_extraInitializers);
@@ -189,7 +188,8 @@ let MosaicaColourEditor = (() => {
189
188
  color: var(--_mosaica-ink);
190
189
  overflow: hidden;
191
190
  text-overflow: ellipsis;
192
- white-space: nowrap;
191
+ white-space: var(--_mosaica-long-text);
192
+ overflow-wrap: anywhere;
193
193
  }
194
194
  [part='sub'] {
195
195
  font-size: 12px;
@@ -227,6 +227,18 @@ let MosaicaColourEditor = (() => {
227
227
  font-weight: 600;
228
228
  margin-right: auto;
229
229
  }
230
+ /* Drawn as a line of text, each with a target 24 px high around it, inside the bar. */
231
+ [part='set-colour'],
232
+ [part='deselect'] {
233
+ position: relative;
234
+ }
235
+ [part='set-colour']::before,
236
+ [part='deselect']::before {
237
+ content: '';
238
+ position: absolute;
239
+ inset: -4px 0;
240
+ min-width: 24px;
241
+ }
230
242
  [part='set-colour'] {
231
243
  display: inline-flex;
232
244
  align-items: center;
@@ -238,6 +250,7 @@ let MosaicaColourEditor = (() => {
238
250
  height: 18px;
239
251
  border: 2px solid currentColor;
240
252
  border-radius: 5px;
253
+ forced-color-adjust: none;
241
254
  }
242
255
  [part='deselect'] {
243
256
  text-decoration: underline;
@@ -256,17 +269,21 @@ let MosaicaColourEditor = (() => {
256
269
  color: var(--_mosaica-ink-3);
257
270
  }
258
271
  [part='columns'] span:last-child,
259
- [part='count'] {
272
+ .n {
260
273
  text-align: right;
261
274
  }
275
+ .n {
276
+ font-size: 12px;
277
+ }
262
278
  [part='rows'] {
263
279
  flex: 1 1 auto;
264
280
  min-height: 0;
265
281
  overflow-y: auto;
266
282
  padding: 2px 8px 8px;
267
283
  }
284
+ /* A row holds a name and a path on a line each, and grows only where a host has long names wrap. */
268
285
  [part~='row'] {
269
- height: ${ROW_HEIGHT}px;
286
+ min-height: 40px;
270
287
  padding: 0 8px;
271
288
  border-radius: 6px;
272
289
  }
@@ -277,21 +294,43 @@ let MosaicaColourEditor = (() => {
277
294
  [part~='row'][data-found] {
278
295
  box-shadow: inset 2px 0 0 var(--_mosaica-ink-3);
279
296
  }
297
+ /* The checkbox's target, 24 px square around the box, which keeps its size and its place. */
298
+ .tick {
299
+ position: relative;
300
+ display: grid;
301
+ align-items: center;
302
+ height: 24px;
303
+ cursor: pointer;
304
+ }
305
+ .tick::before {
306
+ content: '';
307
+ position: absolute;
308
+ inset: 0 -1px 0 -5px;
309
+ }
280
310
  [part='check'] {
281
311
  width: 14px;
282
312
  height: 14px;
283
313
  margin: 0;
284
314
  }
315
+ /* Drawn 22 px square, with a 24 px target around it. */
285
316
  [part='swatch'] {
317
+ position: relative;
286
318
  width: 22px;
287
319
  height: 22px;
288
320
  border: 1px solid rgba(0, 0, 0, 0.12);
289
321
  border-radius: 5px;
290
322
  background: var(--c);
323
+ forced-color-adjust: none;
324
+ }
325
+ [part='swatch']::before {
326
+ content: '';
327
+ position: absolute;
328
+ inset: -2px;
291
329
  }
292
330
  [part='swatch'][data-unmet] {
293
331
  background: none;
294
332
  border-color: var(--_mosaica-line-control);
333
+ forced-color-adjust: auto;
295
334
  }
296
335
  .label {
297
336
  display: flex;
@@ -302,7 +341,8 @@ let MosaicaColourEditor = (() => {
302
341
  [part='path'] {
303
342
  overflow: hidden;
304
343
  text-overflow: ellipsis;
305
- white-space: nowrap;
344
+ white-space: var(--_mosaica-long-text);
345
+ overflow-wrap: anywhere;
306
346
  }
307
347
  [part='path'] {
308
348
  font-size: 12px;
@@ -314,10 +354,13 @@ let MosaicaColourEditor = (() => {
314
354
  font-variant-numeric: tabular-nums;
315
355
  }
316
356
  .none {
317
- padding: 12px 16px;
357
+ padding: 14px 24px 12px;
318
358
  font-size: 12px;
319
359
  color: var(--_mosaica-ink-3);
320
360
  }
361
+ .none:empty {
362
+ padding: 0;
363
+ }
321
364
  .foot {
322
365
  display: flex;
323
366
  align-items: center;
@@ -343,11 +386,15 @@ let MosaicaColourEditor = (() => {
343
386
  /** What the dialog colours: a rendered category column, or `cluster:<layer>`. */
344
387
  get field() { return this.#field_accessor_storage; }
345
388
  set field(value) { this.#field_accessor_storage = value; }
346
- #level_accessor_storage = (__runInitializers(this, _field_extraInitializers), __runInitializers(this, _level_initializers, null));
347
- /** The level of a `stacked` or `tiered` layer whose clusters are listed. `null` is the coarsest level. */
348
- get level() { return this.#level_accessor_storage; }
349
- set level(value) { this.#level_accessor_storage = value; }
350
- #isOpen_accessor_storage = (__runInitializers(this, _level_extraInitializers), __runInitializers(this, _isOpen_initializers, false));
389
+ #clusterLevels_accessor_storage = (__runInitializers(this, _field_extraInitializers), __runInitializers(this, _clusterLevels_initializers, new Map()));
390
+ /**
391
+ * The level each `stacked` or `tiered` layer's clusters are listed at, keyed by layer name. A
392
+ * layer with no entry is listed at the level the map draws it at, which follows the zoom where its
393
+ * levels declare no zoom range. Set it as a property; it has no attribute.
394
+ */
395
+ get clusterLevels() { return this.#clusterLevels_accessor_storage; }
396
+ set clusterLevels(value) { this.#clusterLevels_accessor_storage = value; }
397
+ #isOpen_accessor_storage = (__runInitializers(this, _clusterLevels_extraInitializers), __runInitializers(this, _isOpen_initializers, false));
351
398
  /** Whether the dialog is open. @internal */
352
399
  get isOpen() { return this.#isOpen_accessor_storage; }
353
400
  set isOpen(value) { this.#isOpen_accessor_storage = value; }
@@ -368,6 +415,8 @@ let MosaicaColourEditor = (() => {
368
415
  opener = null;
369
416
  /** The frame the paths of the rows in sight are next asked for in, while one is waiting. */
370
417
  pathFrame = null;
418
+ /** The level the layer was listed at in the last update, chosen or followed. */
419
+ listedAt = undefined;
371
420
  /** Open the dialog. */
372
421
  async show() {
373
422
  this.opener = deepActive();
@@ -426,23 +475,32 @@ let MosaicaColourEditor = (() => {
426
475
  super.disconnectedCallback();
427
476
  }
428
477
  /**
429
- * A change of field or level drops what was found and ticked and closes the picker, since each
430
- * names the last field's values; the dialog closes where the field is now nothing it can edit.
478
+ * A change of field or of the level its layer is listed at, chosen or followed as the map zooms,
479
+ * drops what was found and ticked and closes the picker, since each names the last field's
480
+ * values; the dialog closes where the field is now nothing it can edit.
431
481
  */
432
482
  willUpdate(changed) {
433
483
  super.willUpdate(changed);
434
- if (changed.has('field') || changed.has('level')) {
484
+ const meta = this.resolvedStore?.get('meta') ?? null;
485
+ const layer = meta ? this.layerOf(meta) : null;
486
+ const level = layer ? this.levelOf(layer) : undefined;
487
+ const levelMoved = level !== this.listedAt;
488
+ this.listedAt = level;
489
+ if (changed.has('field') || levelMoved) {
435
490
  this.found = [];
436
491
  this.ticked = new Set();
437
492
  this.picker.close(false);
438
493
  }
439
- const meta = this.resolvedStore?.get('meta') ?? null;
440
494
  if (this.isOpen && (meta === null || !this.editable(meta)))
441
495
  this.close();
442
496
  }
443
497
  get layerName() {
444
498
  return this.field.startsWith(CLUSTER_PREFIX) ? this.field.slice(CLUSTER_PREFIX.length) : null;
445
499
  }
500
+ /** The level `layer` is listed at: its entry in `clusterLevels`, else the level the map draws it at. */
501
+ levelOf(layer) {
502
+ return levelOfLayer(layer, this.clusterLevels.get(layer.name), this.resolvedStore?.get('artifacts').followedLevels);
503
+ }
446
504
  /** The layer listed, where `field` names one the points can be coloured by. */
447
505
  layerOf(meta) {
448
506
  const name = this.layerName;
@@ -461,7 +519,7 @@ let MosaicaColourEditor = (() => {
461
519
  if (this.isCategory(meta))
462
520
  return { groupings: [{ count: true, by: { field: this.field, top } }], subject: 'visible' };
463
521
  const layer = this.layerOf(meta);
464
- return layer ? { groupings: [rankedGrouping(layer, top, levelOf(layer, this.level, this.resolvedStore?.get('artifacts').served ?? []) ?? null)], subject: 'visible' } : null;
522
+ return layer ? { groupings: [rankedGrouping(layer, top, this.levelOf(layer) ?? null)], subject: 'visible' } : null;
465
523
  }
466
524
  /** The aggregate that counts what the search box found. */
467
525
  foundSpec(meta) {
@@ -506,10 +564,18 @@ let MosaicaColourEditor = (() => {
506
564
  if (!s || !meta || !layer || !isTree(layer))
507
565
  return;
508
566
  const list = this.renderRoot.querySelector('[part="rows"]');
509
- const height = list?.clientHeight ?? 0;
510
- const first = height > 0 ? Math.floor(list.scrollTop / ROW_HEIGHT) : 0;
511
- const last = height > 0 ? Math.ceil((list.scrollTop + height) / ROW_HEIGHT) : FIRST_ROWS;
512
- this.paths.ask(s, layer, this.rows(s, meta).slice(first, last).filter((r) => !r.found).map((r) => BigInt(r.key)));
567
+ const rows = this.rows(s, meta);
568
+ const box = list?.getBoundingClientRect();
569
+ // A row is as tall as its name needs, so the rows in sight are those whose boxes are.
570
+ const inSight = list && box && box.height > 0
571
+ ? new Set(Array.from(list.querySelectorAll('[part~="row"]'))
572
+ .filter((el) => {
573
+ const r = el.getBoundingClientRect();
574
+ return r.bottom > box.top && r.top < box.bottom;
575
+ })
576
+ .map((el) => el.dataset.key))
577
+ : new Set(rows.slice(0, FIRST_ROWS).map((r) => r.key));
578
+ this.paths.ask(s, layer, rows.filter((r) => inSight.has(r.key) && !r.found).map((r) => BigInt(r.key)));
513
579
  }
514
580
  /**
515
581
  * The rows: what the search box found, then the field's values or the layer's clusters, largest
@@ -605,6 +671,12 @@ let MosaicaColourEditor = (() => {
605
671
  next.delete(key);
606
672
  this.ticked = next;
607
673
  }
674
+ /** Untick every row. The bar Deselect is on goes with them, so focus moves to the first row's checkbox. */
675
+ async deselect() {
676
+ this.ticked = new Set();
677
+ await this.updateComplete;
678
+ this.renderRoot.querySelector('[part="check"]')?.focus();
679
+ }
608
680
  /** A match the search box found: its row gets focus where the list holds it; else it goes at the top. */
609
681
  onFound(f, listed) {
610
682
  const at = listed.find((r) => r.key === f.key);
@@ -637,7 +709,7 @@ let MosaicaColourEditor = (() => {
637
709
  const rows = this.rows(s, meta);
638
710
  const ranked = this.ranked.entryOf(s, this.rankedSpec(meta));
639
711
  const table = ranked?.result?.tables[0];
640
- const level = layer ? levelOf(layer, this.level, this.resolvedStore?.get('artifacts').served ?? []) : undefined;
712
+ const level = layer ? this.levelOf(layer) : undefined;
641
713
  const levelTitle = layer && level !== undefined && layer.levels.length > 1 ? (layer.levels.find((l) => l.level === level)?.title ?? `Level ${level}`) : null;
642
714
  const where = layer && isTree(layer) ? 'Clusters drawn' : levelTitle;
643
715
  const sub = [where, this.palette(s).title].filter(Boolean).join(' · ');
@@ -655,19 +727,19 @@ let MosaicaColourEditor = (() => {
655
727
  ? html `<div part="selected" role="group" aria-label="Ticked rows">
656
728
  <b>${ticked.length.toLocaleString('en-GB')} selected</b>
657
729
  <button part="set-colour" type="button" aria-haspopup="dialog" @click=${(e) => this.pick(e, `${ticked.length.toLocaleString('en-GB')} selected`, ticked)}>Set colour<span style=${`background:${ticked[0].colour}`}></span></button>
658
- <button part="deselect" type="button" @click=${() => (this.ticked = new Set())}>Deselect</button>
730
+ <button part="deselect" type="button" @click=${() => void this.deselect()}>Deselect</button>
659
731
  </div>`
660
732
  : nothing;
661
733
  const row = (r) => {
662
734
  const on = this.ticked.has(r.key);
663
735
  return html `<div part="row" role="listitem" data-key=${r.key} ?data-found=${r.found} ?data-ticked=${on}>
664
- <input part="check" type="checkbox" .checked=${on} aria-label=${`Select ${r.name}`} @change=${(e) => this.tick(r.key, e.target.checked)} />
665
- <button part="swatch" type="button" style=${`--c:${r.colour}`} ?data-unmet=${r.unmet} aria-haspopup="dialog" aria-label=${`Colour of ${r.name}`} title=${r.unmet ? 'Not drawn yet' : r.colour} @click=${(e) => this.pick(e, r.name, [r])}></button>
736
+ <label class="tick"><input part="check" type="checkbox" .checked=${on} aria-label=${`Select ${r.name}`} @change=${(e) => this.tick(r.key, e.target.checked)} /></label>
737
+ <button part="swatch" type="button" style=${`--c:${r.colour}`} ?data-unmet=${r.unmet} aria-haspopup="dialog" aria-label=${`Colour of ${r.name}${r.unmet ? ', not drawn yet' : ''}`} title=${r.unmet ? 'Not drawn yet' : r.colour} @click=${(e) => this.pick(e, r.name, [r])}></button>
666
738
  <span class="label"><span part="name" title=${r.name} ?data-unnamed=${r.name === UNNAMED}>${r.name}</span>${r.path ? html `<span part="path" title=${r.path}>${r.path}</span>` : nothing}</span>
667
- <span part="count">${r.count === null ? '' : countText(r.count)}</span>
739
+ <span class="n">${r.count === null ? nothing : html `<span part="count">${countText(r.count)}</span><span class="sr-only"> items</span>`}</span>
668
740
  </div>`;
669
741
  };
670
- const empty = rows.length === 0 ? html `<div class="none">${ranked?.status === 'refused' ? `${layer ? 'Clusters' : 'Values'} unavailable` : ranked?.result ? 'Nothing to colour' : 'Loading…'}</div>` : nothing;
742
+ const empty = rows.length > 0 ? nothing : ranked?.status === 'refused' ? `${layer ? 'Clusters' : 'Values'} unavailable` : ranked?.result ? 'Nothing to colour' : 'Loading…';
671
743
  const chosen = this.chosenKeys(s);
672
744
  return dialog(html `<div class="box">
673
745
  <div class="head">
@@ -676,7 +748,8 @@ let MosaicaColourEditor = (() => {
676
748
  </div>
677
749
  ${search}${bar}
678
750
  <div part="columns" aria-hidden="true"><span></span><span></span><span>${layer ? 'Cluster' : 'Value'}</span><span>Items</span></div>
679
- <div part="rows" role="list" aria-label=${`${name}: ${noun} by size`} @scroll=${this.onScroll}>${repeat(rows, (r) => r.key, row)}${empty}</div>
751
+ <div class="none" role="status">${empty}</div>
752
+ <div part="rows" role="list" aria-label=${`${name}: ${noun} by size`} @scroll=${this.onScroll}>${repeat(rows, (r) => r.key, row)}</div>
680
753
  <div class="foot">
681
754
  <button part="reset-all" class="btn" type="button" ?disabled=${chosen.length === 0} @click=${() => this.apply(chosen, null, true)}>Reset to palette</button>
682
755
  <span part="changed" role="status">${chosen.length === 1 ? '1 colour changed' : `${chosen.length.toLocaleString('en-GB')} colours changed`}</span>
@@ -25,10 +25,12 @@ type Host = ReactiveElement & {
25
25
  * The colour picker a swatch opens: the palette's colours and a lighter row of them, a custom area
26
26
  * with a saturation and brightness square, a hue bar and a hex field, and Reset. A choice applies
27
27
  * at once. It is shown in the top layer beside the rectangle `beside` gives, level with the swatch
28
- * it was opened from, and focus goes into it; Escape, or a press outside it and its swatch, closes
29
- * it, Escape giving focus back to the swatch. A custom colour shows on the map as it is dragged and
30
- * is reported as it is let go; a drag cancelled, or ended by closing the picker, puts back the
31
- * colour from before it.
28
+ * it was opened from, or under or over that swatch's row where the window has no room beside, and
29
+ * focus goes into it; Escape, Tab past either end of it, or a press outside
30
+ * it and its swatch, closes it, the keys giving focus back to the swatch. A custom colour shows on
31
+ * the map as it is dragged and is reported as it is let go; a drag cancelled, or ended by closing
32
+ * the picker, puts back the colour from before it. Text in the hex field that is not a colour is
33
+ * kept and marked invalid, and the line under the field says what to write.
32
34
  *
33
35
  * The host renders {@link render} where the picker belongs in its tree and adds
34
36
  * {@link pickerStyles} to its styles. The parts are the host's: `colour-popover`, `choice`, `sv`,
@@ -47,6 +49,8 @@ export declare class ColourPicker implements ReactiveController {
47
49
  private live;
48
50
  /** What puts back the colour from before a drag, while one shows a colour not yet reported. */
49
51
  private restore;
52
+ /** What was typed in the hex field, while it is not a colour. */
53
+ private typed;
50
54
  constructor(host: Host, beside: () => DOMRect);
51
55
  open(from: HTMLElement, target: PickerTarget): void;
52
56
  close(refocus: boolean): void;
@@ -60,7 +64,10 @@ export declare class ColourPicker implements ReactiveController {
60
64
  private applyLive;
61
65
  private choose;
62
66
  render(): TemplateResult | typeof nothing;
63
- /** Show the picker in the top layer, beside {@link beside} and level with its swatch; focus goes into it as it opens. */
67
+ /**
68
+ * Show the picker in the top layer, beside {@link beside} and level with its swatch, or, where
69
+ * neither side has room, under or over its swatch's row; focus goes into it as it opens.
70
+ */
64
71
  private place;
65
72
  }
66
73
  /** The picker's styles, for the element that renders it. */