@theseam/ui-common 2.0.1-beta.114 → 2.0.1-beta.119

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.
@@ -58,6 +58,19 @@ interface FeatureGroupRegistryOptions {
58
58
  newGroupKeyFactory?: () => string;
59
59
  }
60
60
 
61
+ /** A file the map tried to import and could not read. */
62
+ interface TheSeamMapFileImportError {
63
+ /** The file as the consumer's user chose or dropped it. */
64
+ file: File;
65
+ /**
66
+ * Whatever `readGeoFile` rejected with. Usually an `Error` carrying one of
67
+ * its messages — `Shape data not found.`, `Unable to parse as GeoJSON.` —
68
+ * but a malformed file can surface anything a parser throws, so it is not
69
+ * narrowed.
70
+ */
71
+ error: unknown;
72
+ }
73
+
61
74
  /** Which interaction model a map uses. */
62
75
  type TheSeamMapInteractionMode = 'legacy' | 'grouped';
63
76
 
@@ -101,7 +114,7 @@ declare class GoogleMapsService implements OnDestroy {
101
114
  * delay-free discriminator: a stale click's timestamp should predate the
102
115
  * moment the draw finished. It does not hold up empirically. Driving real
103
116
  * mouse draws against the live Storybook and logging both the map `click`
104
- * listener and `stopDrawing()` (see .superpowers/closing-click-report.md)
117
+ * listener and `stopDrawing()` (see docs/superpowers/reports/closing-click-report.md)
105
118
  * caught the echo repeatedly, and every single time its `domEvent.timeStamp`
106
119
  * was a few milliseconds AFTER `stopDrawing()`'s own timestamp, not before
107
120
  * — indistinguishable from a genuinely fresh click by timestamp alone.
@@ -127,6 +140,21 @@ declare class GoogleMapsService implements OnDestroy {
127
140
  private _labelProperty;
128
141
  private _labelsOverlay?;
129
142
  private _warnedAboutLabelDisagreement;
143
+ private _canDelete;
144
+ private readonly _deleteBlockedSubject;
145
+ /**
146
+ * A delete that was attempted and refused. Fires only from the three delete
147
+ * commands, never from their `canDelete*` queries — rendering a menu is not
148
+ * an attempt.
149
+ */
150
+ readonly deleteBlocked$: Observable<TheSeamMapGroupTarget>;
151
+ /**
152
+ * A file reached one of the import paths and could not be read. Plain
153
+ * `Subject`, not `BehaviorSubject`: a consumer subscribing later should not
154
+ * be handed a failure from before it was listening.
155
+ */
156
+ private readonly _fileImportErrorSubject;
157
+ readonly fileImportError$: Observable<TheSeamMapFileImportError>;
130
158
  private readonly _selectionSubject;
131
159
  /**
132
160
  * `distinctUntilChanged` collapses repeated `null`s. Several paths clear the
@@ -176,6 +204,70 @@ declare class GoogleMapsService implements OnDestroy {
176
204
  /**
177
205
  * Iterates the map's features and removes any that are selected.
178
206
  */
207
+ private _removeSelection;
208
+ /**
209
+ * The consumer's veto. Consulted for every delete on every path, and for
210
+ * whether to offer a delete at all.
211
+ */
212
+ setCanDelete(predicate: ((target: TheSeamMapGroupTarget) => boolean) | undefined | null): void;
213
+ /**
214
+ * Pair a set of features to remove with the target to consult `canDelete`
215
+ * with. `null` when there is nothing to delete — distinct from a refusal,
216
+ * and the reason no honest target exists to report.
217
+ *
218
+ * Builds `target.feature` itself rather than delegating the decision to
219
+ * `_targetFor`. There, `feature: null` means only "no particular feature";
220
+ * here it is a promise that the whole group is about to cease to exist.
221
+ * Conflating the two is what let a delete of ONE polygon be consulted as a
222
+ * group delete — see `ResolvedDeletion.unnamable`.
223
+ */
224
+ private _deletionOf;
225
+ /** Resolves the same features `_removeSelection()` would remove. */
226
+ private _selectionDeletion;
227
+ /** Resolves the same features `_removeFocusedFeature()` would remove. */
228
+ private _focusedFeatureDeletion;
229
+ /** Resolves the same features `_removeGroup(key)` would remove. */
230
+ private _groupDeletion;
231
+ /**
232
+ * Whether `removing` may be deleted: the feature-declared lock first, then
233
+ * the consumer's predicate.
234
+ *
235
+ * MUST stay pure. It also answers menu-render questions, which are not
236
+ * delete attempts — a side effect here would fire on every right-click.
237
+ */
238
+ private _mayDelete;
239
+ /**
240
+ * Whether a resolved deletion may proceed. The single gate every query and
241
+ * every command goes through.
242
+ *
243
+ * Wraps `_mayDelete` with the one refusal that cannot be phrased as a
244
+ * question about a target: an `unnamable` delete. Consulting the predicate
245
+ * there would mean LYING to it — handing it `feature: null`, which promises
246
+ * the whole group is about to cease to exist, for a delete that removes one
247
+ * polygon and leaves the rest standing. A consumer whose rule is "a field
248
+ * may be deleted, an individual polygon may not" answers `true` to that and
249
+ * loses a polygon it meant to keep. Fail closed exactly where a consumer's
250
+ * rule could be subverted.
251
+ *
252
+ * Only when a predicate is actually set. With none there is nobody to lie
253
+ * to, so there is nothing to protect — and refusing unconditionally would
254
+ * change 'legacy' mode's behaviour for unsupported-geometry features, which
255
+ * two applications depend on and this work must not drift.
256
+ *
257
+ * Pure, like `_mayDelete`: it also answers menu-render questions.
258
+ */
259
+ private _mayDeleteResolved;
260
+ /** Whether "Delete Polygon" (or the `Delete` key) may act. */
261
+ canDeleteFocusedFeature(): boolean;
262
+ /** Whether "Delete Field" may act on `key`. */
263
+ canDeleteGroup(key: string): boolean;
264
+ /** Whether the legacy "Delete" item (or the `Delete` key) may act. */
265
+ canDeleteSelection(): boolean;
266
+ /**
267
+ * Remove every selected feature, unless `canDelete` or a feature's own
268
+ * `editable: false` refuses. A refused delete emits on `deleteBlocked$` and
269
+ * changes nothing.
270
+ */
179
271
  deleteSelection(): void;
180
272
  /**
181
273
  * Delete every feature in `key`'s group. Backs the grouped "Delete Field"
@@ -190,6 +282,12 @@ declare class GoogleMapsService implements OnDestroy {
190
282
  * selected, a coincidence this design has already stopped being true once
191
283
  * before and could again.
192
284
  */
285
+ private _removeGroup;
286
+ /**
287
+ * Remove every feature in `key`'s group, unless `canDelete` or a feature's
288
+ * own `editable: false` refuses. A refused delete emits on `deleteBlocked$`
289
+ * and changes nothing.
290
+ */
193
291
  deleteGroup(key: string): void;
194
292
  /**
195
293
  * Whether polygon drawing mode is currently active.
@@ -273,6 +371,12 @@ declare class GoogleMapsService implements OnDestroy {
273
371
  allowDrawingHoleInPolygon(allow: boolean): void;
274
372
  setFileInputHandler(handler: ((file: File) => void) | undefined | null): void;
275
373
  getFileInputHandler(): ((file: File) => void) | undefined | null;
374
+ /**
375
+ * Reports a file the library tried to import and could not read. Called by
376
+ * the import controls, not by consumers — a consumer that owns importing
377
+ * through `setFileInputHandler` reports its own failures.
378
+ */
379
+ notifyFileImportError(file: File, error: unknown): void;
276
380
  setInteractionMode(mode: TheSeamMapInteractionMode): void;
277
381
  setGroupOptions(options: FeatureGroupRegistryOptions): void;
278
382
  /**
@@ -281,6 +385,25 @@ declare class GoogleMapsService implements OnDestroy {
281
385
  * even constructed).
282
386
  */
283
387
  setLabelProperty(property: string | undefined): void;
388
+ /**
389
+ * Write `label` into `featureLabelProperty` on every feature in `key`'s
390
+ * group, without re-adding any data. Returns `false` when no feature
391
+ * carries `key`, or when no `featureLabelProperty` is configured — there is
392
+ * then no property to write the label into.
393
+ *
394
+ * Unlike a write through the map's `value`, this does NOT go through
395
+ * `setData()`, so the selection and the viewport are untouched. The
396
+ * repaint and the value update fall out of the data layer's own
397
+ * `setproperty` event, which `_initFeatureChangeListeners()` already turns
398
+ * into a `_labelsOverlay.refresh()` and a `MapValueSource.FeatureChange`
399
+ * emission.
400
+ *
401
+ * It DOES emit a value change, because the label is part of the GeoJSON and
402
+ * the value genuinely changed. Writing that emitted value straight back
403
+ * through the `value` input is inert: `MapValueManagerService.setValue`
404
+ * finds the serialized form identical and returns without emitting.
405
+ */
406
+ setGroupLabel(key: string, label: string): boolean;
284
407
  private _ensureLabelsOverlay;
285
408
  private _buildLabels;
286
409
  private _warnAboutLabelDisagreement;
@@ -328,6 +451,12 @@ declare class GoogleMapsService implements OnDestroy {
328
451
  * `feature` no longer exists — `_applySelection` naturally clears to null
329
452
  * when the group is now empty, via `groupWithSources`.
330
453
  */
454
+ private _removeFocusedFeature;
455
+ /**
456
+ * Remove the focused polygon — or, with nothing focused, the selection —
457
+ * unless `canDelete` or a feature's own `editable: false` refuses. A
458
+ * refused delete emits on `deleteBlocked$` and changes nothing.
459
+ */
331
460
  deleteFocusedFeature(): void;
332
461
  /** Escape cascades: cancel a draw, then clear selection, then leave edit mode. */
333
462
  handleEscape(): void;
@@ -375,7 +504,7 @@ declare class GoogleMapsService implements OnDestroy {
375
504
  * Arm `_suppressNextMapClick`, and guarantee it cannot linger forever if
376
505
  * the echo it exists for never arrives — confirmed to be the normal case
377
506
  * for most real closes, and true of every synthetic/`play()`-driven draw,
378
- * per .superpowers/closing-click-report.md. A `setTimeout` would "solve"
507
+ * per docs/superpowers/reports/closing-click-report.md. A `setTimeout` would "solve"
379
508
  * this by guessing a safe wall-clock delay, which is exactly the kind of
380
509
  * timing window this fix is trying to avoid introducing. Two
381
510
  * `requestAnimationFrame` callbacks bound the window instead: the observed
@@ -409,10 +538,38 @@ interface MapControlsService {
409
538
  declare const MAP_CONTROLS_SERVICE: InjectionToken<MapControlsService>;
410
539
  declare const MAP_CONTROL_DATA: InjectionToken<any>;
411
540
 
541
+ /** One entry in the map's feature context menu. */
412
542
  interface TheSeamMapContextMenuItem {
413
543
  label: string;
414
- action: (item: TheSeamMapContextMenuItem) => void;
544
+ action: () => void;
545
+ }
546
+ /**
547
+ * What the menu needs from the map service to decide what to offer.
548
+ *
549
+ * Narrowed to the query/command pairs so the decision stays a pure function
550
+ * and can be tested without a rendered map.
551
+ */
552
+ interface TheSeamMapDeleteMenuContext {
553
+ mode: TheSeamMapInteractionMode;
554
+ editingEnabled: boolean;
555
+ /** The group the menu is opening for, or null when nothing is targeted. */
556
+ target: TheSeamMapGroupTarget | null;
557
+ canDeleteFocusedFeature(): boolean;
558
+ canDeleteGroup(key: string): boolean;
559
+ canDeleteSelection(): boolean;
560
+ deleteFocusedFeature(): void;
561
+ deleteGroup(key: string): void;
562
+ deleteSelection(): void;
415
563
  }
564
+ /**
565
+ * The delete items the feature context menu offers.
566
+ *
567
+ * A refused item is not rendered at all. The caller is expected to hide the
568
+ * menu entirely for an empty list, so a consumer that refuses everything gets
569
+ * no menu rather than an empty one.
570
+ */
571
+ declare function buildDeleteMenuItems(context: TheSeamMapDeleteMenuContext): TheSeamMapContextMenuItem[];
572
+
416
573
  declare class TheSeamGoogleMapsComponentBase {
417
574
  _elementRef: ElementRef;
418
575
  constructor(_elementRef: ElementRef);
@@ -465,6 +622,17 @@ declare class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase imp
465
622
  streetViewControlEnabled: boolean;
466
623
  allowDrawingHoleInPolygon: boolean;
467
624
  editingEnabled: boolean;
625
+ /**
626
+ * Intercepts a file the user chose or dropped, in place of the library's own
627
+ * import handling. Covers **both** import paths: a file picked through the
628
+ * upload button and one dropped onto the map (`fileDropEnabled` defaults to
629
+ * `true`, so setting this now also intercepts drops a consumer relying on
630
+ * the default previously had handled internally).
631
+ *
632
+ * Once called, the consumer owns the file, including reporting any failure
633
+ * in its own UI — `fileImportError` will not fire for a file handed to this
634
+ * handler.
635
+ */
468
636
  set fileImportHandler(value: ((file: File) => void) | undefined | null);
469
637
  get _attrDisabled(): true | null;
470
638
  get _attrTabIndex(): number;
@@ -497,9 +665,46 @@ declare class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase imp
497
665
  newGroupKeyFactory: (() => string) | undefined;
498
666
  /** Preselect a group. Applied on map-ready and after each external value write. */
499
667
  selectedGroupKey: string | null;
668
+ /**
669
+ * Vetoes a delete. Return `false` to refuse the target.
670
+ *
671
+ * `target.feature === null` means the whole group is about to cease to
672
+ * exist — every polygon of it is going, however the delete was asked for.
673
+ * A non-null `feature` means one polygon is being removed from a group that
674
+ * survives.
675
+ *
676
+ * **Consulted when no delete is happening.** It decides whether to render
677
+ * the context-menu items, so it runs on every context-menu open. A
678
+ * predicate that logs an attempt or flips state will do so on every
679
+ * right-click. It must also be deterministic for a given target, or the
680
+ * menu and the `Delete` key can disagree about the same target.
681
+ *
682
+ * That is a correctness warning, not a performance one. The context-menu
683
+ * target changes only on a right-click, a delete, and a value write, so
684
+ * this runs a handful of times per gesture.
685
+ *
686
+ * Passing nothing refuses nothing, which is the behaviour this component
687
+ * has always had.
688
+ */
689
+ canDelete: ((target: TheSeamMapGroupTarget) => boolean) | undefined;
500
690
  mapReady: EventEmitter<google.maps.Map | undefined>;
501
691
  selectionChange: EventEmitter<TheSeamMapGroupTarget | null>;
502
692
  featureHoverChange: EventEmitter<TheSeamMapGroupTarget | null>;
693
+ /**
694
+ * A delete was attempted and refused — in practice, the `Delete` key, since
695
+ * a refused menu item is never rendered. Emits the target that was refused
696
+ * so the consumer can explain why; only the consumer knows the reason.
697
+ */
698
+ deleteBlocked: EventEmitter<TheSeamMapGroupTarget>;
699
+ /**
700
+ * A file reached one of the import paths and could not be read — a corrupt
701
+ * archive, a `.zip` of something else, malformed GeoJSON. Emitted so the
702
+ * consumer can say so in its own UI; the library has nowhere to show it.
703
+ *
704
+ * Not emitted for a file a `fileImportHandler` took: once the consumer owns
705
+ * the file, it owns reporting the outcome too.
706
+ */
707
+ fileImportError: EventEmitter<TheSeamMapFileImportError>;
503
708
  featureContextMenu: MenuComponent;
504
709
  _options: {
505
710
  mapTypeControl: boolean;
@@ -525,7 +730,6 @@ declare class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase imp
525
730
  focus(): void;
526
731
  private _getHostElement;
527
732
  _onMapReady(theMap: google.maps.Map): void;
528
- _onClickDeleteFeature(): void;
529
733
  /** Select a group by key. Returns false when no such group exists. */
530
734
  selectGroup(key: string): boolean;
531
735
  clearSelection(): void;
@@ -534,10 +738,18 @@ declare class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase imp
534
738
  /** Pan to a group's centre. Returns false when no such group exists. */
535
739
  panToGroup(key: string): boolean;
536
740
  getGroups(): TheSeamMapFeatureGroup[];
741
+ /**
742
+ * Set a group's label text in place. Returns false when no such group
743
+ * exists, or when no `featureLabelProperty` is set.
744
+ *
745
+ * Does not clear the selection or re-fit the viewport, so it is safe to
746
+ * call while the user is renaming the very group being displayed.
747
+ */
748
+ setGroupLabel(key: string, label: string): boolean;
537
749
  setEditMode(enabled: boolean): void;
538
750
  isEditMode(): boolean;
539
751
  static ɵfac: i0.ɵɵFactoryDeclaration<TheSeamGoogleMapsComponent, never>;
540
- static ɵcmp: i0.ɵɵComponentDeclaration<TheSeamGoogleMapsComponent, "seam-google-maps", ["seamGoogleMaps"], { "disabled": { "alias": "disabled"; "required": false; }; "value": { "alias": "value"; "required": false; }; "tabIndex": { "alias": "tabIndex"; "required": false; }; "fileDropEnabled": { "alias": "fileDropEnabled"; "required": false; }; "fileUploadControlEnabled": { "alias": "fileUploadControlEnabled"; "required": false; }; "fullscreenControlEnabled": { "alias": "fullscreenControlEnabled"; "required": false; }; "reCenterControlEnabled": { "alias": "reCenterControlEnabled"; "required": false; }; "mapTypeControlEnabled": { "alias": "mapTypeControlEnabled"; "required": false; }; "streetViewControlEnabled": { "alias": "streetViewControlEnabled"; "required": false; }; "allowDrawingHoleInPolygon": { "alias": "allowDrawingHoleInPolygon"; "required": false; }; "editingEnabled": { "alias": "editingEnabled"; "required": false; }; "fileImportHandler": { "alias": "fileImportHandler"; "required": false; }; "zoom": { "alias": "zoom"; "required": false; }; "longitude": { "alias": "longitude"; "required": false; }; "latitude": { "alias": "latitude"; "required": false; }; "padding": { "alias": "padding"; "required": false; }; "interactionMode": { "alias": "interactionMode"; "required": false; }; "featureGroupProperty": { "alias": "featureGroupProperty"; "required": false; }; "featureLabelProperty": { "alias": "featureLabelProperty"; "required": false; }; "newGroupKeyFactory": { "alias": "newGroupKeyFactory"; "required": false; }; "selectedGroupKey": { "alias": "selectedGroupKey"; "required": false; }; }, { "mapReady": "mapReady"; "selectionChange": "selectionChange"; "featureHoverChange": "featureHoverChange"; }, never, never, false, never>;
752
+ static ɵcmp: i0.ɵɵComponentDeclaration<TheSeamGoogleMapsComponent, "seam-google-maps", ["seamGoogleMaps"], { "disabled": { "alias": "disabled"; "required": false; }; "value": { "alias": "value"; "required": false; }; "tabIndex": { "alias": "tabIndex"; "required": false; }; "fileDropEnabled": { "alias": "fileDropEnabled"; "required": false; }; "fileUploadControlEnabled": { "alias": "fileUploadControlEnabled"; "required": false; }; "fullscreenControlEnabled": { "alias": "fullscreenControlEnabled"; "required": false; }; "reCenterControlEnabled": { "alias": "reCenterControlEnabled"; "required": false; }; "mapTypeControlEnabled": { "alias": "mapTypeControlEnabled"; "required": false; }; "streetViewControlEnabled": { "alias": "streetViewControlEnabled"; "required": false; }; "allowDrawingHoleInPolygon": { "alias": "allowDrawingHoleInPolygon"; "required": false; }; "editingEnabled": { "alias": "editingEnabled"; "required": false; }; "fileImportHandler": { "alias": "fileImportHandler"; "required": false; }; "zoom": { "alias": "zoom"; "required": false; }; "longitude": { "alias": "longitude"; "required": false; }; "latitude": { "alias": "latitude"; "required": false; }; "padding": { "alias": "padding"; "required": false; }; "interactionMode": { "alias": "interactionMode"; "required": false; }; "featureGroupProperty": { "alias": "featureGroupProperty"; "required": false; }; "featureLabelProperty": { "alias": "featureLabelProperty"; "required": false; }; "newGroupKeyFactory": { "alias": "newGroupKeyFactory"; "required": false; }; "selectedGroupKey": { "alias": "selectedGroupKey"; "required": false; }; "canDelete": { "alias": "canDelete"; "required": false; }; }, { "mapReady": "mapReady"; "selectionChange": "selectionChange"; "featureHoverChange": "featureHoverChange"; "deleteBlocked": "deleteBlocked"; "fileImportError": "fileImportError"; }, never, never, false, never>;
541
753
  }
542
754
 
543
755
  /**
@@ -565,10 +777,15 @@ declare class TheSeamMapFileDropComponent implements OnInit, OnDestroy {
565
777
  private _disableFileDrop;
566
778
  private readonly _handleDragOverEvent;
567
779
  private readonly _handleDropEvent;
780
+ /**
781
+ * Routes a dropped file the same way the upload button routes a chosen one,
782
+ * so `fileImportHandler` means "the consumer owns imported files" whichever
783
+ * way the file arrived.
784
+ */
785
+ private _importDroppedFile;
568
786
  private readonly _handleDragEnterEvent;
569
787
  private readonly _handleDragLeaveEvent;
570
788
  private _dropAllowed;
571
- private _isSupportedDataTransfer;
572
789
  private _isSupportedDataTransferTypes;
573
790
  static ɵfac: i0.ɵɵFactoryDeclaration<TheSeamMapFileDropComponent, never>;
574
791
  static ɵcmp: i0.ɵɵComponentDeclaration<TheSeamMapFileDropComponent, "seam-map-file-drop", never, {}, {}, never, never, false, never>;
@@ -597,6 +814,7 @@ declare class TheSeamGoogleMapsUploadButtonControlComponent implements OnDestroy
597
814
  ngOnDestroy(): void;
598
815
  private _getFile;
599
816
  private _importFile;
817
+ private _reportImportError;
600
818
  private _createHiddenInput;
601
819
  private _createTemporaryFormElement;
602
820
  /**
@@ -933,6 +1151,21 @@ interface TheSeamMapFeatureStyleContext {
933
1151
  }
934
1152
  /** Merge only the supported subset of one options object into another. */
935
1153
  declare function mergeStyleOptions(target: google.maps.Data.StyleOptions, source: google.maps.Data.StyleOptions | undefined): google.maps.Data.StyleOptions;
1154
+ /**
1155
+ * Whether the feature declines to opt OUT of `option`.
1156
+ *
1157
+ * Resolved per key, not per object: a selected feature consults
1158
+ * `styleOptionsSelected` first and falls back to `styleOptions` only for a key
1159
+ * `styleOptionsSelected` does not itself mention. Otherwise a feature
1160
+ * declaring `styleOptionsSelected` for an unrelated reason, such as a
1161
+ * different selected fill colour, would silently lose an unrelated
1162
+ * `editable: false` from `styleOptions` the moment it is selected.
1163
+ *
1164
+ * Only an explicit `false` opts out. Shared by `computeFeatureStyle` and the
1165
+ * delete gate in `GoogleMapsService`, so the lock a consumer declares means
1166
+ * the same thing to both.
1167
+ */
1168
+ declare function featureAllows(feature: google.maps.Data.Feature, option: 'editable' | 'draggable' | 'clickable'): boolean;
936
1169
  /**
937
1170
  * The style for a feature, in a fixed precedence order:
938
1171
  *
@@ -960,10 +1193,10 @@ declare function mergeStyleOptions(target: google.maps.Data.StyleOptions, source
960
1193
  * feature that opts out of one opts out of the other. This implication runs
961
1194
  * only one way — `draggable: false` alone does not imply `editable: false`, so
962
1195
  * a feature may still opt out of dragging while remaining reshapeable via its
963
- * vertex handles. Resolved through the same per-key `wants()` lookup as
964
- * `editable` itself, so a feature that locks `editable: false` in
965
- * `styleOptions` cannot be dragged even if `styleOptionsSelected` declares
966
- * `draggable` for an unrelated reason (or not at all).
1196
+ * vertex handles. Resolved through `featureAllows`, which the delete gate
1197
+ * shares, so a feature that locks `editable: false` in `styleOptions` cannot
1198
+ * be dragged even if `styleOptionsSelected` declares `draggable` for an
1199
+ * unrelated reason (or not at all).
967
1200
  */
968
1201
  declare function computeFeatureStyle(feature: google.maps.Data.Feature, context: TheSeamMapFeatureStyleContext): google.maps.Data.StyleOptions;
969
1202
  /**
@@ -1078,5 +1311,5 @@ declare class TheSeamNoopGoogleMapsAPILoader extends TheSeamGoogleMapsApiLoader
1078
1311
  static ɵprov: i0.ɵɵInjectableDeclaration<TheSeamNoopGoogleMapsAPILoader>;
1079
1312
  }
1080
1313
 
1081
- export { AppFeaturePropertyName, FEATURE_STYLE_OPTIONS_DEFAULT, FEATURE_STYLE_OPTIONS_SELECTED, FEATURE_STYLE_OVERRIDE_OPTIONS_HOVERED, GoogleMapsContextMenu, GoogleMapsControlsService, GoogleMapsService, MAP_CONTROLS_SERVICE, MAP_CONTROL_DATA, MapControlRef, MapValueManagerService, MapValueSource, SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS, SUPPORTED_PROPERTY_STYLE_OPTIONS, THESEAM_LAZY_MAPS_API_CONFIG, TheSeamGoogleMapsApiLoader, TheSeamGoogleMapsComponent, TheSeamGoogleMapsModule, TheSeamGoogleMapsPlacesAutoCompleteComponent, TheSeamGoogleMapsPlacesAutocompleteDirective, TheSeamGoogleMapsRecenterButtonControlComponent, TheSeamGoogleMapsUploadButtonControlComponent, TheSeamLazyMapsApiLoader, TheSeamMapFileDropComponent, TheSeamMapsControlComponent, TheSeamNoopGoogleMapsAPILoader, applyHoleToFeature, computeFeatureHoverStyle, computeFeatureStyle, createFeatureChangeObservable, dataMultiPolygonFromGeoJson, dataPolygonFromGeoJson, geoJsonFeatureFromDataFeature, geoJsonPolygonFromDataFeature, getBoundsWithAllFeatures, getFeatureBounds, getFeatureCenter, getFeaturesCount, getHoveredStyleOptionsDefinedByFeature, getSelectedStyleOptionsDefinedByFeature, getStyleOptionsDefinedByFeature, isAppFeatureProperty, isFeatureSelected, mergeStyleOptions, polygonCoordinates, polygonHasValidPathsLengths, polygonsFromDataFeature, removeAllFeatures, setFeatureSelected, stripAppFeaturePropertiesFromJson };
1082
- export type { GoogleMapsRecenterButtonControlData, GoogleMapsUploadButtonControlData, MapControl, MapControlsService, MapValue, MapValueChange, TheSeamLazyMapsApiLoaderConfig, TheSeamMapFeatureGroup, TheSeamMapFeatureStyleContext, TheSeamMapGroupTarget, TheSeamMapInteractionMode };
1314
+ export { AppFeaturePropertyName, FEATURE_STYLE_OPTIONS_DEFAULT, FEATURE_STYLE_OPTIONS_SELECTED, FEATURE_STYLE_OVERRIDE_OPTIONS_HOVERED, GoogleMapsContextMenu, GoogleMapsControlsService, GoogleMapsService, MAP_CONTROLS_SERVICE, MAP_CONTROL_DATA, MapControlRef, MapValueManagerService, MapValueSource, SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS, SUPPORTED_PROPERTY_STYLE_OPTIONS, THESEAM_LAZY_MAPS_API_CONFIG, TheSeamGoogleMapsApiLoader, TheSeamGoogleMapsComponent, TheSeamGoogleMapsModule, TheSeamGoogleMapsPlacesAutoCompleteComponent, TheSeamGoogleMapsPlacesAutocompleteDirective, TheSeamGoogleMapsRecenterButtonControlComponent, TheSeamGoogleMapsUploadButtonControlComponent, TheSeamLazyMapsApiLoader, TheSeamMapFileDropComponent, TheSeamMapsControlComponent, TheSeamNoopGoogleMapsAPILoader, applyHoleToFeature, buildDeleteMenuItems, computeFeatureHoverStyle, computeFeatureStyle, createFeatureChangeObservable, dataMultiPolygonFromGeoJson, dataPolygonFromGeoJson, featureAllows, geoJsonFeatureFromDataFeature, geoJsonPolygonFromDataFeature, getBoundsWithAllFeatures, getFeatureBounds, getFeatureCenter, getFeaturesCount, getHoveredStyleOptionsDefinedByFeature, getSelectedStyleOptionsDefinedByFeature, getStyleOptionsDefinedByFeature, isAppFeatureProperty, isFeatureSelected, mergeStyleOptions, polygonCoordinates, polygonHasValidPathsLengths, polygonsFromDataFeature, removeAllFeatures, setFeatureSelected, stripAppFeaturePropertiesFromJson };
1315
+ export type { GoogleMapsRecenterButtonControlData, GoogleMapsUploadButtonControlData, MapControl, MapControlsService, MapValue, MapValueChange, TheSeamLazyMapsApiLoaderConfig, TheSeamMapContextMenuItem, TheSeamMapDeleteMenuContext, TheSeamMapFeatureGroup, TheSeamMapFeatureStyleContext, TheSeamMapFileImportError, TheSeamMapGroupTarget, TheSeamMapInteractionMode };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theseam/ui-common",
3
- "version": "2.0.1-beta.114",
3
+ "version": "2.0.1-beta.119",
4
4
  "peerDependencies": {
5
5
  "@angular/cdk": "^20.2.3",
6
6
  "@angular/common": "^20.3.0",
package/utils/index.d.ts CHANGED
@@ -219,6 +219,17 @@ declare function noInnerRingsValidator(): ValidatorFn;
219
219
  declare const NO_KINKS_VALIDATOR_NAME = "no-kinks";
220
220
  declare function noKinksValidator(): ValidatorFn;
221
221
 
222
+ /**
223
+ * Property key under which `readGeoFile` records the archive member a feature
224
+ * came from, for shapefile archives only.
225
+ *
226
+ * A zip can hold one shapefile per field, and once their features are
227
+ * concatenated the member name is the only thing distinguishing them — for
228
+ * some producer exports it is the only usable name at all, because the `.dbf`
229
+ * carries nothing but numbers. The value is the member's basename, without its
230
+ * directory or extension.
231
+ */
232
+ declare const GEO_FILE_SOURCE_NAME_PROPERTY = "seamSourceFileName";
222
233
  /**
223
234
  * Reads a File, or buffer of file content, in GeoJSON or ESRI Shapefile format
224
235
  * and returns a GeoJSON `FeatureCollection`.
@@ -484,5 +495,5 @@ interface SanitizeFilenameOptions {
484
495
  }
485
496
  declare function sanitizeFilename(filename: string, options?: SanitizeFilenameOptions): string;
486
497
 
487
- export { IS_FEATURE_COLLECTION_VALIDATOR_NAME, IS_ONLY_GEOMETRY_TYPES_VALIDATOR_NAME, MIN_MAX_POINTS_VALIDATOR_NAME, NO_EMPTY_FEATURE_COLLECTION_VALIDATOR_NAME, NO_INNER_RINGS_VALIDATOR_NAME, NO_KINKS_VALIDATOR_NAME, PollingTickerOptions, Refreshable, activatedRoutesWithDataProperty, addHoleToPolygon, arrayMoveImmutable, arrayMoveMutable, calcPercentage, closePolygons, coerceFeatureCollection, createPadding, deleteProperties, deleteProperty, fileBufferToBlob, fileBufferToObjectUrl, fileDataFromBuffer, fractionalDigitsCount, geoJsonToArea, getAttribute, getClosestWidgetCdkDrag, getControlName, getControlPath, hasAttribute, hasProperty, hasRequiredControl, isAbsoluteUrl, isEmptyInputValue, isEmptyUrlRoute, isFeatureCollectionValidator, isNullOrUndefined, isNullOrUndefinedOrEmpty, isNumeric, isOnlyGeometryTypes, isOnlyGeometryTypesValidator, leafChildRoute, loadStyle, loadStyleSheet, mapEach, mergePolygons, minMaxPointsValidator, noEmptyFeatureCollectionValidator, noInnerRingsValidator, noKinksValidator, notNullOrUndefined, notNullOrUndefinedOrEmpty, observeControlIsDifferent, observeControlStatus, observeControlValid, observeControlValue, observeControlValueChange, observeQueryList, openBlob, padEnd, padStart, phoneNumberMask, pollingTicker, polygonContains, polygonHasMinDistinctVertices, polygonViolatesMinMax, readFileAsDataUrlAsync, readFileAsync, readGeoFile, ringIsClockwise, routeSnapshotPathFull, routeSnapshotPathRelative, sanitizeFilename, splitMultiPolygons, stripOuter, subscriberCount, tapFirst, toggleAttribute, trimRepeated, waitOnConditionAsync, waitOnNonPendingStatus, willHaveDataProp, withoutProperties, withoutProperty, wrapIntoObservable };
498
+ export { GEO_FILE_SOURCE_NAME_PROPERTY, IS_FEATURE_COLLECTION_VALIDATOR_NAME, IS_ONLY_GEOMETRY_TYPES_VALIDATOR_NAME, MIN_MAX_POINTS_VALIDATOR_NAME, NO_EMPTY_FEATURE_COLLECTION_VALIDATOR_NAME, NO_INNER_RINGS_VALIDATOR_NAME, NO_KINKS_VALIDATOR_NAME, PollingTickerOptions, Refreshable, activatedRoutesWithDataProperty, addHoleToPolygon, arrayMoveImmutable, arrayMoveMutable, calcPercentage, closePolygons, coerceFeatureCollection, createPadding, deleteProperties, deleteProperty, fileBufferToBlob, fileBufferToObjectUrl, fileDataFromBuffer, fractionalDigitsCount, geoJsonToArea, getAttribute, getClosestWidgetCdkDrag, getControlName, getControlPath, hasAttribute, hasProperty, hasRequiredControl, isAbsoluteUrl, isEmptyInputValue, isEmptyUrlRoute, isFeatureCollectionValidator, isNullOrUndefined, isNullOrUndefinedOrEmpty, isNumeric, isOnlyGeometryTypes, isOnlyGeometryTypesValidator, leafChildRoute, loadStyle, loadStyleSheet, mapEach, mergePolygons, minMaxPointsValidator, noEmptyFeatureCollectionValidator, noInnerRingsValidator, noKinksValidator, notNullOrUndefined, notNullOrUndefinedOrEmpty, observeControlIsDifferent, observeControlStatus, observeControlValid, observeControlValue, observeControlValueChange, observeQueryList, openBlob, padEnd, padStart, phoneNumberMask, pollingTicker, polygonContains, polygonHasMinDistinctVertices, polygonViolatesMinMax, readFileAsDataUrlAsync, readFileAsync, readGeoFile, ringIsClockwise, routeSnapshotPathFull, routeSnapshotPathRelative, sanitizeFilename, splitMultiPolygons, stripOuter, subscriberCount, tapFirst, toggleAttribute, trimRepeated, waitOnConditionAsync, waitOnNonPendingStatus, willHaveDataProp, withoutProperties, withoutProperty, wrapIntoObservable };
488
499
  export type { IActivatedRouteWithData, IFileData, PollingActionFn, RefreshableOptions, SanitizeFilenameOptions, SubscriberCountChangedFn };