@object-ui/plugin-map 17.7.0 → 18.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,288 @@
1
1
  # @object-ui/plugin-map
2
2
 
3
+ ## 18.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 6f3299f: objectui moves to major 18, following `@objectstack/*` from 17 to 18 (objectui#12334). objectui's major is not a count of its own breaking changes: it tracks the major of the `@objectstack/spec` its packages depend on, so that the same major means compatible across the two projects. These packages already declare `@objectstack/*` on the 18 line (objectui#12030), so every package in the fixed release group crosses to 18 together. It is the one `major` that rule admits: objectui's own breaking changes ship as `minor`, described in their entries.
8
+
9
+ The 18 line is released from Changesets pre mode on the `next` tag (`.changeset/pre.json`), as `@objectstack/*` 18 is: these releases are `18.0.0-next.N` on the npm `next` dist-tag, and they do not move `latest`. The first `18.0.0` on `latest` comes when `@objectstack` 18 is generally available and this repository leaves pre mode.
10
+
11
+ What a consumer must do to take it is in the `@objectstack/*` 18 entry of this release (objectui#12030): move its own `@objectstack/*` packages to the 18 line at the same time.
12
+
13
+ ### Patch Changes
14
+
15
+ - fbaa79d: A map view in a browser without WebGL2 shows its own "Map failed to load" alert and lists its records, instead of crashing the page (objectui#11819).
16
+
17
+ MapLibre draws only through WebGL2. Without it — hardware acceleration turned off, a GPU-blocklisted browser, some remote desktops, headless Chromium — the page body was replaced by the render-failure card *Component "object-map" failed to render — Cannot read properties of undefined (reading 'destroy')*, which names neither the map nor the cause. `ObjectMap` now asks the browser for a WebGL2 context before it mounts the map. When there is none it never constructs a map: it shows the amber "Map failed to load" alert, naming WebGL2, and lists the records the markers would have drawn. The search box above narrows that list, and choosing a record does what clicking its marker does. A style or tile failure is unchanged: the map keeps running with its markers and shows the alert over them.
18
+
19
+ Nothing is added to the package entry: no export, prop or type member.
20
+ - 524136e: The view-level `provider: 'api'` data source is no longer read anywhere in objectui (objectui#12325). `@objectstack/spec` retires it (objectstack#23082, ADR-0049): a view binds its object (`provider: 'object'`) or static rows (`provider: 'value'`), and a metadata-declared API call is the page element's `dataSource` binding.
21
+
22
+ Breaking, declared as `minor` per the version-alignment rule:
23
+
24
+ - **`resolveDataSource`** (`@object-ui/core`) has no `api` arm. A block that still says `provider: 'api'` is an unknown provider and gets an unknown provider's answer (the fallback DataSource, else `null`); no `ApiDataSource` is built from its `read` / `write`. `ResolveDataSourceOptions` loses `fetch` and `defaultHeaders`, which only that arm read.
25
+ - **`ViewDataProvider`** (`@object-ui/core`) has no `api` arm: such a config resolves with `Unknown data provider: api`. `ViewDataConfig` and `ResolvedData.provider` drop `'api'`, and `DataFetcher.fetchUrl`, which only that arm called, is removed.
26
+ - **`useViewData`** (`@object-ui/react`) no longer keys on or threads anything for an `api` block.
27
+ - **`ObjectGantt`** reads no `api` block: its `read` URL is never requested, and the chart answers it like any unknown provider. `ObjectCalendar` and `ObjectMap` drop their `api` branches, which only warned "not yet implemented".
28
+ - **`ListView`** no longer stands down for a gantt view with an `api` block: it fetches the bound object like any other list.
29
+
30
+ Unchanged: `ApiDataSource` stays a class for code that constructs it from an `ApiDataSourceConfig`, so the console's approvals inbox reads exactly as before.
31
+ - d75f212: Published text no longer teaches the retired view-level `provider: 'api'` data source (objectui#12364). A view binds `provider: 'object'` or `provider: 'value'`; a metadata-declared API call is the page element's `dataSource` binding. Text only: no schema accepts or refuses anything new, and no renderer behaves differently.
32
+
33
+ - **`@object-ui/types`:** the `object-tree` `data` description drops the `api` provider from the providers it names.
34
+ - **`@object-ui/plugin-grid` / `@object-ui/plugin-map`:** the `data` input descriptions drop the `api` provider.
35
+ - **`@object-ui/plugin-calendar` / `@object-ui/plugin-gantt` / `@object-ui/plugin-map`:** the error thrown when no `DataSource` is available now reads `DataSource required for the object provider` (was `DataSource required for object/api providers`). It fires in exactly the same conditions as before.
36
+ - **`@object-ui/react` / `@object-ui/auth`:** the README and docblocks describe `SchemaRendererProvider`'s `apiFetch` as what it is now: the host's authenticated fetch the renderers use for their own reads of the host's API (chart metadata, dataset dimension labels, record-permission probes). It is not a channel for a view's data source.
37
+ - **`@object-ui/app-shell`:** comment wording only in `ConsoleShell`, `useConsoleActionRuntime` and `ObjectView` (these comments ship in the built JS): no behaviour change.
38
+ - **`@object-ui/core`:** docblock wording only on `normalizeListViewSchema` and `resolveRecordSourceObjectName` (these ship in `dist/*.d.ts` and the built JS): no behaviour change.
39
+ - 1e6d83b: Data-bound blocks title their "data source could not be resolved" panel in the page's language (objectui#12920, the family of objectui#12910). The panel shows when a block's `dataSource.view` names a view its object does not have. Each block's title now reads `@object-ui/i18n` through `useObjectTranslation`, with the `en` pack's value as the inline default, so a page with no `I18nProvider` draws the same English it drew before.
40
+
41
+ - **Plugin blocks.** `object-calendar`, `object-chart`, `object-metric`, `object-pivot`, `detail-view`, `record:related_list`, `object-form`, `embeddable-form`, `object-master-detail-form`, `record:line_items`, `object-gantt`, `object-grid`, `object-kanban`, `list-view`, `object-map` and `object-timeline` read one `element.KIND.sourceUnresolved` key per block kind. `object-metric` reads `element.number.sourceUnresolved`, the key `element:number` already reads for the same sentence. The three forms share `element.form.sourceUnresolved`. `record:related_list`'s panel for a failed `parentDataSource` read reads `element.relatedList.parentUnreadable` ("This related list’s parent record could not be read").
42
+ - **`@object-ui/react` panel defaults.** `ElementDataSourceErrorPanel` with no `title` reads `element.component.sourceUnresolved`, and `NoDataSourcePanel` with no `title` reads `element.component.noDataSource`. A passed `title` still wins, an empty string included. Props and markup do not change.
43
+
44
+ Clause-②: yes
45
+
46
+ The new keys in `@object-ui/i18n` widen its exported `TranslationKeys`. No prop, input or export of these packages changes.
47
+ - b13ea3c: feat(types)!: `ObjectGridSchema.defaultFilters` and the flat `ObjectGanttSchema` / `ObjectMapSchema` `filter` follow their `@objectstack/spec` rows (objectui#6152, round 10)
48
+
49
+ Clause-②: yes
50
+
51
+ `@objectstack/spec` typed `ComponentPropsMap['object-grid'].defaultFilters` as the same
52
+ `ViewFilterRule` array as `filter`, `[{ field, operator, value }, ...]`, from 17.6.0 until 18
53
+ retired it (see objectui#12030): the legacy fallback `ObjectGrid` read only when `filter` was
54
+ absent, refusing the MongoDB-style record, a bare string and the AST tuple array. The `object-gantt` and `object-map` rows type `filter` the same
55
+ way. `@object-ui/types` now takes each row's own member by reference, on the TypeScript interface
56
+ and on the zod mirror, with no alias window.
57
+
58
+ **Widened.** `ObjectGridSchema.defaultFilters` was `Record<string, any>` and
59
+ `z.record(z.string(), z.any())`, so the zod mirror REFUSED the rule array the row declares. The
60
+ flat grid mirror is the source of an `object-view`'s `table` slot, so
61
+ `table: { defaultFilters: [{ field: 'status', operator: 'equals', value: 'open' }] }` parsed
62
+ there through 17.x, on the tolerant and the strict face and through `safeValidateSchema`; retired
63
+ in 18, see objectui#12030: the row's tombstone refuses `defaultFilters` by name, so every value,
64
+ the rule array included, is refused there now.
65
+
66
+ **Narrowed (breaking).**
67
+
68
+ - The record form of `defaultFilters` is refused: on the interface (a compile error, in an
69
+ `object-view`'s `table` too) and on the zod mirror, at `defaultFilters` (`table.defaultFilters`
70
+ in an `object-view`), with the protocol's own message, which computed the rule array from the
71
+ record's keys through 17.x (since 18, see objectui#12030, it is the retired-key message, which
72
+ names `filter`). Respell
73
+ `defaultFilters: { status: 'open' }` as
74
+ `filter: [{ field: 'status', operator: 'equals', value: 'open' }]`; the rule-array
75
+ `defaultFilters` spelling this entry first offered is retired in 18 too.
76
+ - `ObjectGanttSchema.filter` and `ObjectMapSchema.filter` were `any[]` and `z.array(z.any())`, so
77
+ `filter: [['status', '=', 'open']]` type-checked and parsed. Both are the row's rule array now;
78
+ respell the tuple as `[{ field: 'status', operator: 'equals', value: 'open' }]`. These two flat
79
+ types describe the node as the renderers read it: an authored `object-gantt` / `object-map`
80
+ node's `properties` bag is the row itself, which refused the tuple array already.
81
+
82
+ What did not move: the renderers' reads. `ObjectGrid` lowered `defaultFilters` through the same
83
+ `toFilterNode` sink as `filter`, so a rule array there sent the same `$filter` and drew the same
84
+ rows as the same array written as `filter` (retired in 18, see objectui#12030: `ObjectGrid` and
85
+ `ObjectView` no longer read `defaultFilters`, so a view that still carries it renders unfiltered);
86
+ the sink still lowers a record or an AST that reaches `filter` at runtime, and `ObjectGantt` / `ObjectMap` still forward an AST a host composes. The
87
+ `@object-ui/core`, `@object-ui/plugin-grid` and `@object-ui/plugin-view` entries are comment
88
+ repairs to sentences that called the key `Record<string, any>`. `@object-ui/plugin-grid`,
89
+ `@object-ui/plugin-view` and `@object-ui/plugin-map` also carry typed test fixtures re-spelled to
90
+ the rule array, and `@object-ui/plugin-grid` a pin of the above through the real renderer (since
91
+ 18 it pins that `defaultFilters` is not read).
92
+ - Updated dependencies [18d7b48]
93
+ - Updated dependencies [172acc3]
94
+ - Updated dependencies [f0496bd]
95
+ - Updated dependencies [c4c506b]
96
+ - Updated dependencies [9db9ff3]
97
+ - Updated dependencies [c096f03]
98
+ - Updated dependencies [92f4e2b]
99
+ - Updated dependencies [b10c68e]
100
+ - Updated dependencies [bdc9049]
101
+ - Updated dependencies [2e818d0]
102
+ - Updated dependencies [fd060f0]
103
+ - Updated dependencies [8b14aec]
104
+ - Updated dependencies [2abec3a]
105
+ - Updated dependencies [9dfaca6]
106
+ - Updated dependencies [c000398]
107
+ - Updated dependencies [73b5d77]
108
+ - Updated dependencies [e6dcd85]
109
+ - Updated dependencies [96fcf30]
110
+ - Updated dependencies [7a2c60b]
111
+ - Updated dependencies [9fc68aa]
112
+ - Updated dependencies [d50f724]
113
+ - Updated dependencies [17acfbb]
114
+ - Updated dependencies [89cc738]
115
+ - Updated dependencies [c0862c1]
116
+ - Updated dependencies [c0862c1]
117
+ - Updated dependencies [c0862c1]
118
+ - Updated dependencies [c0862c1]
119
+ - Updated dependencies [c0862c1]
120
+ - Updated dependencies [4c0de52]
121
+ - Updated dependencies [a80fef7]
122
+ - Updated dependencies [e06365c]
123
+ - Updated dependencies [1e1f09e]
124
+ - Updated dependencies [455c646]
125
+ - Updated dependencies [f34e877]
126
+ - Updated dependencies [f34e877]
127
+ - Updated dependencies [9844bbf]
128
+ - Updated dependencies [cef0eee]
129
+ - Updated dependencies [7241a81]
130
+ - Updated dependencies [74add0c]
131
+ - Updated dependencies [aaba865]
132
+ - Updated dependencies [45d5853]
133
+ - Updated dependencies [4f4fc03]
134
+ - Updated dependencies [2312bd9]
135
+ - Updated dependencies [c5406c2]
136
+ - Updated dependencies [d99b731]
137
+ - Updated dependencies [2a48bd4]
138
+ - Updated dependencies [c7b30bd]
139
+ - Updated dependencies [69bca0a]
140
+ - Updated dependencies [023f00d]
141
+ - Updated dependencies [158c75d]
142
+ - Updated dependencies [7525045]
143
+ - Updated dependencies [5af42db]
144
+ - Updated dependencies [ce991bd]
145
+ - Updated dependencies [5f75cfa]
146
+ - Updated dependencies [b7cd5c8]
147
+ - Updated dependencies [5330038]
148
+ - Updated dependencies [c9fc10b]
149
+ - Updated dependencies [dc6d28e]
150
+ - Updated dependencies [c0c2f79]
151
+ - Updated dependencies [0665c3b]
152
+ - Updated dependencies [d2500d8]
153
+ - Updated dependencies [e723f58]
154
+ - Updated dependencies [f3d5408]
155
+ - Updated dependencies [b231607]
156
+ - Updated dependencies [466a219]
157
+ - Updated dependencies [6fb281d]
158
+ - Updated dependencies [334f0cf]
159
+ - Updated dependencies [c08c933]
160
+ - Updated dependencies [92f979d]
161
+ - Updated dependencies [c4dd707]
162
+ - Updated dependencies [c4dd707]
163
+ - Updated dependencies [923504f]
164
+ - Updated dependencies [5c2982a]
165
+ - Updated dependencies [97e7d4e]
166
+ - Updated dependencies [10aba37]
167
+ - Updated dependencies [5d3f437]
168
+ - Updated dependencies [7af0ab3]
169
+ - Updated dependencies [b434f5f]
170
+ - Updated dependencies [fd4872f]
171
+ - Updated dependencies [f0532d8]
172
+ - Updated dependencies [3092aca]
173
+ - Updated dependencies [82e5f53]
174
+ - Updated dependencies [d81e460]
175
+ - Updated dependencies [8106db1]
176
+ - Updated dependencies [093d55b]
177
+ - Updated dependencies [a8051d6]
178
+ - Updated dependencies [72594f2]
179
+ - Updated dependencies [524136e]
180
+ - Updated dependencies [6f3299f]
181
+ - Updated dependencies [f2b17c6]
182
+ - Updated dependencies [52d6194]
183
+ - Updated dependencies [23bf859]
184
+ - Updated dependencies [1c72d77]
185
+ - Updated dependencies [2b4d3f1]
186
+ - Updated dependencies [d75f212]
187
+ - Updated dependencies [ff9df88]
188
+ - Updated dependencies [70e843f]
189
+ - Updated dependencies [a2225f9]
190
+ - Updated dependencies [5c4deb5]
191
+ - Updated dependencies [c950345]
192
+ - Updated dependencies [21f9577]
193
+ - Updated dependencies [044f231]
194
+ - Updated dependencies [f8267df]
195
+ - Updated dependencies [3eb3ec1]
196
+ - Updated dependencies [1ffd6a2]
197
+ - Updated dependencies [5f8ecf6]
198
+ - Updated dependencies [726d8c9]
199
+ - Updated dependencies [ef71a09]
200
+ - Updated dependencies [619e3f7]
201
+ - Updated dependencies [c9e6742]
202
+ - Updated dependencies [f62b6ff]
203
+ - Updated dependencies [608033b]
204
+ - Updated dependencies [611566b]
205
+ - Updated dependencies [d66d7e8]
206
+ - Updated dependencies [15d8ca6]
207
+ - Updated dependencies [378896d]
208
+ - Updated dependencies [71243db]
209
+ - Updated dependencies [a8add5c]
210
+ - Updated dependencies [33ee9de]
211
+ - Updated dependencies [4839f5c]
212
+ - Updated dependencies [c7462e7]
213
+ - Updated dependencies [e058d76]
214
+ - Updated dependencies [c999d4c]
215
+ - Updated dependencies [8df2608]
216
+ - Updated dependencies [5483297]
217
+ - Updated dependencies [ed43c79]
218
+ - Updated dependencies [260ef71]
219
+ - Updated dependencies [655e897]
220
+ - Updated dependencies [655e897]
221
+ - Updated dependencies [69a408f]
222
+ - Updated dependencies [d2b21a1]
223
+ - Updated dependencies [5ff64ef]
224
+ - Updated dependencies [26323c4]
225
+ - Updated dependencies [9753811]
226
+ - Updated dependencies [bc281f4]
227
+ - Updated dependencies [d637be3]
228
+ - Updated dependencies [2cfdc99]
229
+ - Updated dependencies [1e6d83b]
230
+ - Updated dependencies [c219165]
231
+ - Updated dependencies [a7ae252]
232
+ - Updated dependencies [fb501bc]
233
+ - Updated dependencies [30083da]
234
+ - Updated dependencies [025130c]
235
+ - Updated dependencies [8aa8e3e]
236
+ - Updated dependencies [024b7b6]
237
+ - Updated dependencies [909c64e]
238
+ - Updated dependencies [9e7e1a5]
239
+ - Updated dependencies [2493e85]
240
+ - Updated dependencies [d0b9648]
241
+ - Updated dependencies [46dbf32]
242
+ - Updated dependencies [a928aaa]
243
+ - Updated dependencies [61ed5ad]
244
+ - Updated dependencies [1b94d50]
245
+ - Updated dependencies [988aa9f]
246
+ - Updated dependencies [fb85637]
247
+ - Updated dependencies [9f1dd79]
248
+ - Updated dependencies [df71568]
249
+ - Updated dependencies [d11174a]
250
+ - Updated dependencies [2d8a8b7]
251
+ - Updated dependencies [cbac9d7]
252
+ - Updated dependencies [616df65]
253
+ - Updated dependencies [4b92c5a]
254
+ - Updated dependencies [3650d94]
255
+ - Updated dependencies [8cd4db4]
256
+ - Updated dependencies [daeb77f]
257
+ - Updated dependencies [eb4552e]
258
+ - Updated dependencies [3c3115e]
259
+ - Updated dependencies [55e90fd]
260
+ - Updated dependencies [9b75509]
261
+ - Updated dependencies [b13ea3c]
262
+ - Updated dependencies [d7e9e9a]
263
+ - Updated dependencies [cf62edf]
264
+ - Updated dependencies [0253416]
265
+ - Updated dependencies [5d77c09]
266
+ - Updated dependencies [3fd8625]
267
+ - Updated dependencies [1473757]
268
+ - Updated dependencies [d73d987]
269
+ - Updated dependencies [12ff256]
270
+ - Updated dependencies [26b0bd2]
271
+ - Updated dependencies [26b0bd2]
272
+ - Updated dependencies [d328698]
273
+ - Updated dependencies [d328698]
274
+ - Updated dependencies [b4e0787]
275
+ - Updated dependencies [088e0f7]
276
+ - Updated dependencies [78b07f4]
277
+ - Updated dependencies [b403bb3]
278
+ - Updated dependencies [4016370]
279
+ - Updated dependencies [12dc7b4]
280
+ - @object-ui/types@18.0.0
281
+ - @object-ui/components@18.0.0
282
+ - @object-ui/core@18.0.0
283
+ - @object-ui/react@18.0.0
284
+ - @object-ui/permissions@18.0.0
285
+
3
286
  ## 17.7.0
4
287
 
5
288
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectMap.d.ts","sourceRoot":"","sources":["../src/ObjectMap.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAmB,UAAU,EAAY,MAAM,kBAAkB,CAAC;AA0B/F,OAAO,kCAAkC,CAAC;AAkB1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAChD,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAqfD,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAq6B9C,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"ObjectMap.d.ts","sourceRoot":"","sources":["../src/ObjectMap.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAmB,UAAU,EAAY,MAAM,kBAAkB,CAAC;AA0B/F,OAAO,kCAAkC,CAAC;AAoD1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAChD,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAqfD,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAm9B9C,CAAC;AAEF,eAAe,SAAS,CAAC"}
package/dist/index.d.ts CHANGED
@@ -20,9 +20,9 @@ export declare const ObjectMapRenderer: React.FC<any>;
20
20
  *
21
21
  * ## Why unregistering is the whole retirement here — measured, not assumed
22
22
  *
23
- * ⚠️ `BaseSchema` closes with `[key: string]: any` and `BaseSchemaCore` ends
24
- * `.passthrough()`, so a dropped MEMBER KEY is KEPT, not refused (the
25
- * objectui#7664 failure). That hazard needs a schema face to arise on, and this
23
+ * ⚠️ `BaseSchemaCore` ends `.passthrough()` (and `BaseSchema` closed with
24
+ * `[key: string]: any` until objectui#8347), so a dropped MEMBER KEY is KEPT,
25
+ * not refused, on the zod face (the objectui#7664 failure). That hazard needs a schema face to arise on, and this
26
26
  * TYPE NAME never had one: in `@object-ui/types` the literal `'map'` appears
27
27
  * only in the stored view-type unions (`NamedListView.type`,
28
28
  * `defaultViewType`), never as a component node type, against a firing control
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,CAAC;AAwB/B,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAgB1C,CAAC;AAmEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,CAAC;AAwB/B,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAoB1C,CAAC;AAmEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG"}
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { useCallback as e, useEffect as t, useMemo as n, useRef as r, useState as i } from "react";
2
2
  import { ComponentRegistry as a, ValueDataSource as o, applyNonGridRowCeiling as s, buildExpandFields as ee, convertSortToQueryParams as te, elementDataSourceBlock as c, getRecordDisplayName as ne, nonGridRowCeilingQuery as re, recordDisplayValueAt as l, resolveRecordSourceConfig as u, resolveRecordSourceObjectName as ie } from "@object-ui/core";
3
- import { ElementDataSourceGate as d, NonGridRowCeilingNote as ae, useDataInvalidation as oe, useFilterScope as se, useNavigationOverlay as ce, useResolvedFilter as le, useSchemaContext as ue, useSettledSchema as de } from "@object-ui/react";
3
+ import { ElementDataSourceGate as d, NonGridRowCeilingNote as ae, useDataInvalidation as oe, useFilterScope as se, useNavigationOverlay as ce, useObjectTranslation as le, useResolvedFilter as ue, useSchemaContext as de, useSettledSchema as fe } from "@object-ui/react";
4
4
  import { ObjectMapConfigSchema as f } from "@object-ui/types/zod";
5
- import { NavigationOverlay as fe, cn as p, useIsMobile as pe } from "@object-ui/components";
6
- import { usePermissions as me } from "@object-ui/permissions";
7
- import he, { Marker as m, NavigationControl as ge, Popup as _e } from "react-map-gl/maplibre";
5
+ import { NavigationOverlay as pe, cn as p, useIsMobile as me } from "@object-ui/components";
6
+ import { usePermissions as he } from "@object-ui/permissions";
7
+ import ge, { Marker as m, NavigationControl as _e, Popup as ve } from "react-map-gl/maplibre";
8
8
  import "maplibre-gl/dist/maplibre-gl.css";
9
9
  import { jsx as h, jsxs as g } from "react/jsx-runtime";
10
10
  function _(e) {
11
11
  return e >= -180 && e < 180 ? e : ((e + 180) % 360 + 360) % 360 - 180;
12
12
  }
13
13
  var v = (e) => Math.min(85, Math.max(-85, e));
14
- function ve(e) {
14
+ function ye(e) {
15
15
  if (e.length === 0) return null;
16
16
  let t = e.map(([e]) => _(e)).sort((e, t) => e - t), n = e.map(([, e]) => v(e)), r = t.length, i = t[0] + 360 - t[r - 1], a = 0;
17
17
  for (let e = 1; e < r; e++) {
@@ -21,7 +21,7 @@ function ve(e) {
21
21
  let o = t[a], s = t[(a + r - 1) % r], ee = a === 0 ? s : s + 360;
22
22
  return [[o, Math.min(...n)], [ee, Math.max(...n)]];
23
23
  }
24
- function ye(e) {
24
+ function be(e) {
25
25
  let [[t, n], [r, i]] = e;
26
26
  return {
27
27
  longitude: _((t + r) / 2),
@@ -30,12 +30,22 @@ function ye(e) {
30
30
  }
31
31
  //#endregion
32
32
  //#region src/ObjectMap.tsx
33
- var be = "https://demotiles.maplibre.org/style.json", y = Object.keys(f.shape).filter((e) => e !== "style");
34
- function xe(e) {
33
+ var xe = "https://demotiles.maplibre.org/style.json";
34
+ function Se() {
35
+ if (typeof document > "u") return !0;
36
+ try {
37
+ let e = document.createElement("canvas").getContext("webgl2");
38
+ return e ? (e.getExtension("WEBGL_lose_context")?.loseContext(), !0) : !1;
39
+ } catch {
40
+ return !1;
41
+ }
42
+ }
43
+ var y = Object.keys(f.shape).filter((e) => e !== "style");
44
+ function Ce(e) {
35
45
  return u(e, "view-data");
36
46
  }
37
47
  var b = () => globalThis.process?.env?.NODE_ENV !== "production", x = /* @__PURE__ */ new Set();
38
- function Se(e) {
48
+ function we(e) {
39
49
  if (!b()) return;
40
50
  let t = e.filter;
41
51
  if (!t || typeof t != "object" || Array.isArray(t) || !Object.prototype.hasOwnProperty.call(t, "map")) return;
@@ -65,8 +75,8 @@ function T(e) {
65
75
  let n = `${e.type ?? "map"}::${e.objectName ?? ""}::${t.join(",")}`;
66
76
  w.has(n) || (w.add(n), console.warn(`[ObjectMap] The \`map\` block configures this map, so these top-level keys are IGNORED: ${t.map((e) => `\`${e}\``).join(", ")}. The \`map\` block is the authoring shape; the flat top-level spelling is the internal form ObjectView/ListView produce when they flatten \`options.map\`, and what the author wrote outranks it. Move anything you still need into \`map\`, or drop the \`map\` block. objectui#5018.`));
67
77
  }
68
- function Ce(e) {
69
- Se(e), C(e);
78
+ function Te(e) {
79
+ we(e), C(e);
70
80
  let t = e.mapStyle || e.map?.style, n = e.map ?? null;
71
81
  if (n) {
72
82
  let r = f.safeParse(n);
@@ -86,10 +96,10 @@ function Ce(e) {
86
96
  style: t
87
97
  } : { style: t };
88
98
  }
89
- function we(e) {
99
+ function Ee(e) {
90
100
  return !!e.locationField || !!(e.latitudeField && e.longitudeField);
91
101
  }
92
- function Te(e, t) {
102
+ function De(e, t) {
93
103
  if (t.latitudeField && t.longitudeField) {
94
104
  let n = e[t.latitudeField], r = e[t.longitudeField];
95
105
  if (typeof n == "number" && typeof r == "number") return [n, r];
@@ -111,7 +121,7 @@ function Te(e, t) {
111
121
  }
112
122
  return null;
113
123
  }
114
- function Ee(e, t, n = 50) {
124
+ function Oe(e, t, n = 50) {
115
125
  if (e.length <= 1 || t >= 15) return e.map((e) => ({
116
126
  id: e.id,
117
127
  coordinates: e.coordinates,
@@ -142,17 +152,17 @@ function Ee(e, t, n = 50) {
142
152
  }
143
153
  }), a;
144
154
  }
145
- var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, onRowClick: f, onEdit: _, onDelete: v, enableClustering: y, clusterRadius: b = 50 }) => {
146
- let [x, Se] = i([]), [S, C] = i(!0), [w, T] = i(null), [E, De] = i(null), [D, O] = i(null), [k, Oe] = i(""), ke = pe(), A = r(null), [j, Ae] = i(null), [je, M] = i(null), [Me, N] = i(!1), [Ne, Pe] = i(null), Fe = e((e) => {
147
- Pe(e?.error?.message || "Failed to load the map style/tiles.");
148
- }, []), Ie = e(() => {
155
+ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: le, onRowClick: de, onEdit: f, onDelete: _, enableClustering: v, clusterRadius: y = 50 }) => {
156
+ let [b, x] = i([]), [we, S] = i(!0), [C, w] = i(null), [T, E] = i(null), [D, O] = i(null), [k, ke] = i(""), Ae = me(), A = r(null), [j, je] = i(null), [Me, M] = i(null), [Ne, N] = i(!1), [Pe, Fe] = i(null), Ie = e((e) => {
157
+ Fe(e?.error?.message || "Failed to load the map style/tiles.");
158
+ }, []), [Le] = i(Se), Re = e(() => {
149
159
  if (typeof navigator > "u" || !navigator.geolocation) {
150
160
  M("Geolocation is not available in this browser.");
151
161
  return;
152
162
  }
153
163
  N(!0), M(null), navigator.geolocation.getCurrentPosition((e) => {
154
164
  let { longitude: t, latitude: n } = e.coords;
155
- Ae({
165
+ je({
156
166
  lng: t,
157
167
  lat: n
158
168
  }), N(!1);
@@ -170,10 +180,10 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
170
180
  timeout: 8e3,
171
181
  maximumAge: 6e4
172
182
  });
173
- }, []), P = n(() => xe(a), [a]), F = n(() => Ce(a), [a]), I = P?.provider === "value", L = P?.provider, R = P?.provider === "object" ? P.object : void 0, z = P?.provider === "value" ? P.items : void 0, Le = ie(a, P), { ready: Re, def: B } = de(Le ?? "", I ? void 0 : c), V = me(), H = !Array.isArray(d) && L === "object", U = oe(H ? R : void 0), ze = r(U), Be = r(null), W = r(0), Ve = se(), G = le(a.filter, Ve);
183
+ }, []), P = n(() => Ce(a), [a]), F = n(() => Te(a), [a]), I = P?.provider === "value", L = P?.provider, R = P?.provider === "object" ? P.object : void 0, z = P?.provider === "value" ? P.items : void 0, ze = ie(a, P), { ready: Be, def: B } = fe(ze ?? "", I ? void 0 : c), V = he(), H = !Array.isArray(d) && L === "object", U = oe(H ? R : void 0), Ve = r(U), He = r(null), W = r(0), Ue = se(), G = ue(a.filter, Ue);
174
184
  t(() => {
175
- if (H && !Re) {
176
- C(!0);
185
+ if (H && !Be) {
186
+ S(!0);
177
187
  return;
178
188
  }
179
189
  let e = [
@@ -187,14 +197,14 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
187
197
  a.sort,
188
198
  B,
189
199
  V
190
- ], t = Be.current, n = t !== null && t.length === e.length && e.every((e, n) => Object.is(e, t[n])), r = U !== ze.current;
191
- ze.current = U;
200
+ ], t = He.current, n = t !== null && t.length === e.length && e.every((e, n) => Object.is(e, t[n])), r = U !== Ve.current;
201
+ Ve.current = U;
192
202
  let i = r && n, ne = ++W.current, l = () => W.current === ne, u = (t, n) => {
193
- l() && (Se(t), De(n), T(null), Be.current = e);
203
+ l() && (x(t), E(n), w(null), He.current = e);
194
204
  };
195
205
  return (async () => {
196
206
  try {
197
- if (i || C(!0), Array.isArray(d)) {
207
+ if (i || S(!0), Array.isArray(d)) {
198
208
  u(d, null);
199
209
  return;
200
210
  }
@@ -207,7 +217,7 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
207
217
  u(t.rows, t);
208
218
  return;
209
219
  }
210
- if (!c || typeof c.find != "function") throw Error("DataSource required for object/api providers");
220
+ if (!c || typeof c.find != "function") throw Error("DataSource required for the object provider");
211
221
  if (L === "object") {
212
222
  let e = R, t = ee(B?.fields), n = V?.isLoaded ? t.filter((t) => V.checkField(e, t, "read")) : t, r = await c.find(e, {
213
223
  $filter: G,
@@ -216,11 +226,11 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
216
226
  ...n.length > 0 ? { $expand: n } : {}
217
227
  }), i = s(r);
218
228
  u(i.rows, i);
219
- } else L === "api" && (console.warn("API provider not yet implemented for ObjectMap"), u([], null));
229
+ }
220
230
  } catch (e) {
221
- i ? console.error("[ObjectMap] Failed to refresh data:", e) : l() && T(e);
231
+ i ? console.error("[ObjectMap] Failed to refresh data:", e) : l() && w(e);
222
232
  } finally {
223
- l() && C(!1);
233
+ l() && S(!1);
224
234
  }
225
235
  })(), () => {
226
236
  W.current += 1;
@@ -234,7 +244,7 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
234
244
  I,
235
245
  G,
236
246
  a.sort,
237
- Re,
247
+ Be,
238
248
  B,
239
249
  V,
240
250
  U,
@@ -243,8 +253,8 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
243
253
  let { markers: K, invalidCount: q } = n(() => {
244
254
  let e = 0;
245
255
  return {
246
- markers: x.map((t, n) => {
247
- let r = Te(t, F);
256
+ markers: b.map((t, n) => {
257
+ let r = De(t, F);
248
258
  if (!r) return e++, null;
249
259
  let i = ne(B, t, {
250
260
  titleField: F.titleField,
@@ -261,23 +271,25 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
261
271
  invalidCount: e
262
272
  };
263
273
  }, [
264
- x,
274
+ b,
265
275
  F,
266
276
  B
267
- ]), J = n(() => K.find((e) => e.id === D), [K, D]), [Y, He] = i(F.zoom || 3), Ue = e((e) => {
277
+ ]), J = n(() => K.find((e) => e.id === D), [K, D]), [Y, We] = i(F.zoom || 3), Ge = e((e) => {
268
278
  try {
269
279
  let t = e?.target?.getZoom?.();
270
- typeof t == "number" && Number.isFinite(t) && He(Math.round(t));
280
+ typeof t == "number" && Number.isFinite(t) && We(Math.round(t));
271
281
  } catch {}
272
282
  }, []), X = ce({
273
283
  navigation: a.navigation,
274
284
  objectName: a.objectName,
275
- onRowClick: f
276
- }), Z = n(() => {
285
+ onRowClick: de
286
+ }), Ke = (e) => {
287
+ O(e.id), X.handleClick(e.data), le?.(e.data);
288
+ }, Z = n(() => {
277
289
  if (!k.trim()) return K;
278
290
  let e = k.toLowerCase();
279
291
  return K.filter((t) => t.title?.toLowerCase().includes(e) || t.description?.toLowerCase().includes(e));
280
- }, [K, k]), We = n(() => y ?? (a.enableClustering || Z.length > 100) ? Ee(Z, Y, b) : Z.map((e) => ({
292
+ }, [K, k]), qe = n(() => v ?? (a.enableClustering || Z.length > 100) ? Oe(Z, Y, y) : Z.map((e) => ({
281
293
  id: e.id,
282
294
  coordinates: e.coordinates,
283
295
  markers: [e],
@@ -285,34 +297,34 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
285
297
  })), [
286
298
  Z,
287
299
  Y,
300
+ v,
288
301
  y,
289
- b,
290
302
  a
291
- ]), Q = n(() => ve(Z.map((e) => e.coordinates)), [Z]), $ = typeof F.center?.[0] == "number" ? F.center[0] : void 0, Ge = typeof F.center?.[1] == "number" ? F.center[1] : void 0, Ke = typeof F.zoom == "number" ? F.zoom : void 0, qe = $ !== void 0 || Ge !== void 0 || Ke !== void 0, Je = n(() => {
292
- if (Q && !qe) return {
303
+ ]), Q = n(() => ye(Z.map((e) => e.coordinates)), [Z]), $ = typeof F.center?.[0] == "number" ? F.center[0] : void 0, Je = typeof F.center?.[1] == "number" ? F.center[1] : void 0, Ye = typeof F.zoom == "number" ? F.zoom : void 0, Xe = $ !== void 0 || Je !== void 0 || Ye !== void 0, Ze = n(() => {
304
+ if (Q && !Xe) return {
293
305
  bounds: Q,
294
306
  fitBoundsOptions: {
295
307
  padding: 48,
296
308
  maxZoom: 12
297
309
  }
298
310
  };
299
- let e = Q ? ye(Q) : {
311
+ let e = Q ? be(Q) : {
300
312
  longitude: 0,
301
313
  latitude: 0
302
314
  };
303
315
  return {
304
- longitude: Ge ?? e.longitude,
316
+ longitude: Je ?? e.longitude,
305
317
  latitude: $ ?? e.latitude,
306
- zoom: Ke ?? (Q ? 3 : 2)
318
+ zoom: Ye ?? (Q ? 3 : 2)
307
319
  };
308
320
  }, [
309
321
  Q,
310
- qe,
311
- Ge,
322
+ Xe,
323
+ Je,
312
324
  $,
313
- Ke
325
+ Ye
314
326
  ]);
315
- return we(F) ? S ? /* @__PURE__ */ h("div", {
327
+ return Ee(F) ? we ? /* @__PURE__ */ h("div", {
316
328
  className: p("min-w-0 overflow-hidden", u),
317
329
  children: /* @__PURE__ */ h("div", {
318
330
  className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
@@ -321,13 +333,13 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
321
333
  children: "Loading map..."
322
334
  })
323
335
  })
324
- }) : w ? /* @__PURE__ */ h("div", {
336
+ }) : C ? /* @__PURE__ */ h("div", {
325
337
  className: p("min-w-0 overflow-hidden", u),
326
338
  children: /* @__PURE__ */ h("div", {
327
339
  className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
328
340
  children: /* @__PURE__ */ g("div", {
329
341
  className: "text-destructive",
330
- children: ["Error: ", w.message]
342
+ children: ["Error: ", C.message]
331
343
  })
332
344
  })
333
345
  }) : /* @__PURE__ */ g("div", {
@@ -342,7 +354,7 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
342
354
  children: /* @__PURE__ */ h("input", {
343
355
  type: "text",
344
356
  value: k,
345
- onChange: (e) => Oe(e.target.value),
357
+ onChange: (e) => ke(e.target.value),
346
358
  placeholder: "Search locations…",
347
359
  className: "w-full px-3 py-2 text-sm border rounded-md bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
348
360
  })
@@ -350,49 +362,49 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
350
362
  /* @__PURE__ */ g("div", {
351
363
  className: "relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full",
352
364
  children: [
353
- /* @__PURE__ */ g(he, {
365
+ Le ? /* @__PURE__ */ g(ge, {
354
366
  ref: (e) => {
355
367
  A.current = e;
356
368
  },
357
- initialViewState: Je,
369
+ initialViewState: Ze,
358
370
  style: {
359
371
  width: "100%",
360
372
  height: "100%"
361
373
  },
362
- mapStyle: F.style || be,
374
+ mapStyle: F.style || xe,
363
375
  touchZoomRotate: !0,
364
376
  dragRotate: !0,
365
377
  touchPitch: !0,
366
- onLoad: Ue,
367
- onZoom: (e) => He(Math.round(e.viewState.zoom)),
368
- onError: Fe,
378
+ onLoad: Ge,
379
+ onZoom: (e) => We(Math.round(e.viewState.zoom)),
380
+ onError: Ie,
369
381
  children: [
370
- Ne && /* @__PURE__ */ g("div", {
382
+ Pe && /* @__PURE__ */ g("div", {
371
383
  role: "alert",
372
384
  className: "absolute inset-x-0 top-0 z-20 p-2 text-sm text-center text-amber-900 bg-amber-50 border-b border-amber-200",
373
385
  children: [
374
386
  "Map failed to load (",
375
- Ne,
387
+ Pe,
376
388
  "). Markers below are still listed in the search box;",
377
389
  " ",
378
390
  F.style ? "check the configured map style URL." : "configure a custom map style for production use."
379
391
  ]
380
392
  }),
381
- /* @__PURE__ */ h(ge, {
393
+ /* @__PURE__ */ h(_e, {
382
394
  position: "top-right",
383
395
  showCompass: !0,
384
396
  showZoom: !0
385
397
  }),
386
398
  /* @__PURE__ */ h("button", {
387
399
  type: "button",
388
- onClick: Ie,
389
- disabled: Me,
400
+ onClick: Re,
401
+ disabled: Ne,
390
402
  className: "absolute top-2 left-2 z-10 inline-flex items-center justify-center size-9 rounded-md bg-background/95 border shadow-sm hover:bg-background disabled:opacity-50",
391
403
  "aria-label": "Show my location",
392
404
  "data-testid": "map-geolocate",
393
405
  children: /* @__PURE__ */ h("span", {
394
406
  "aria-hidden": "true",
395
- children: Me ? "⏳" : "🧭"
407
+ children: Ne ? "⏳" : "🧭"
396
408
  })
397
409
  }),
398
410
  j && /* @__PURE__ */ h(m, {
@@ -405,7 +417,7 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
405
417
  "data-testid": "map-user-location"
406
418
  })
407
419
  }),
408
- We.map((e) => e.isCluster ? /* @__PURE__ */ h(m, {
420
+ qe.map((e) => e.isCluster ? /* @__PURE__ */ h(m, {
409
421
  longitude: e.coordinates[0],
410
422
  latitude: e.coordinates[1],
411
423
  anchor: "center",
@@ -435,16 +447,14 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
435
447
  latitude: e.coordinates[1],
436
448
  anchor: "bottom",
437
449
  onClick: (t) => {
438
- t.originalEvent.stopPropagation();
439
- let n = e.markers[0];
440
- O(n.id), X.handleClick(n.data), ue?.(n.data);
450
+ t.originalEvent.stopPropagation(), Ke(e.markers[0]);
441
451
  },
442
452
  children: /* @__PURE__ */ h("div", {
443
453
  className: "text-2xl cursor-pointer hover:scale-110 transition-transform",
444
454
  children: "📍"
445
455
  })
446
456
  }, e.id)),
447
- J && !ke && /* @__PURE__ */ h(_e, {
457
+ J && !Ae && /* @__PURE__ */ h(ve, {
448
458
  longitude: J.coordinates[0],
449
459
  latitude: J.coordinates[1],
450
460
  anchor: "top",
@@ -463,15 +473,15 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
463
473
  }),
464
474
  /* @__PURE__ */ g("div", {
465
475
  className: "mt-2 text-xs flex gap-2",
466
- children: [_ && /* @__PURE__ */ h("button", {
476
+ children: [f && /* @__PURE__ */ h("button", {
467
477
  type: "button",
468
478
  className: "text-blue-500 hover:underline",
469
- onClick: () => _(J.data),
479
+ onClick: () => f(J.data),
470
480
  children: "Edit"
471
- }), v && /* @__PURE__ */ h("button", {
481
+ }), _ && /* @__PURE__ */ h("button", {
472
482
  type: "button",
473
483
  className: "text-red-500 hover:underline",
474
- onClick: () => v(J.data),
484
+ onClick: () => _(J.data),
475
485
  children: "Delete"
476
486
  })]
477
487
  })
@@ -479,8 +489,34 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
479
489
  })
480
490
  })
481
491
  ]
492
+ }) : /* @__PURE__ */ g("div", {
493
+ className: "flex h-full flex-col",
494
+ "data-testid": "map-webgl2-fallback",
495
+ children: [/* @__PURE__ */ h("div", {
496
+ role: "alert",
497
+ className: "p-2 text-sm text-center text-amber-900 bg-amber-50 border-b border-amber-200",
498
+ children: "Map failed to load (this browser does not provide WebGL2, which the map needs). The records are listed below; turn on hardware acceleration or use a browser with WebGL2 to see the map."
499
+ }), /* @__PURE__ */ g("ul", {
500
+ className: "min-h-0 flex-1 overflow-y-auto divide-y bg-background",
501
+ "aria-label": "Locations",
502
+ children: [Z.length === 0 && /* @__PURE__ */ h("li", {
503
+ className: "px-3 py-2 text-sm text-muted-foreground",
504
+ children: "No locations to list."
505
+ }), Z.map((e) => /* @__PURE__ */ h("li", { children: /* @__PURE__ */ g("button", {
506
+ type: "button",
507
+ onClick: () => Ke(e),
508
+ className: p("block w-full px-3 py-2 text-left hover:bg-accent focus:outline-none focus-visible:bg-accent", e.id === D && "bg-accent"),
509
+ children: [/* @__PURE__ */ h("span", {
510
+ className: "block truncate text-sm font-medium",
511
+ children: e.title
512
+ }), e.description && /* @__PURE__ */ h("span", {
513
+ className: "block truncate text-xs text-muted-foreground",
514
+ children: e.description
515
+ })]
516
+ }) }, e.id))]
517
+ })]
482
518
  }),
483
- J && ke && /* @__PURE__ */ g("div", {
519
+ J && Ae && /* @__PURE__ */ g("div", {
484
520
  className: "absolute inset-x-0 bottom-0 z-30 bg-background border-t shadow-lg rounded-t-2xl p-4 pb-[max(env(safe-area-inset-bottom),1rem)]",
485
521
  role: "dialog",
486
522
  "aria-label": "Location details",
@@ -512,28 +548,28 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
512
548
  }),
513
549
  /* @__PURE__ */ g("div", {
514
550
  className: "mt-3 flex flex-wrap gap-2 text-xs",
515
- children: [_ && /* @__PURE__ */ h("button", {
551
+ children: [f && /* @__PURE__ */ h("button", {
516
552
  type: "button",
517
553
  className: "px-3 py-1.5 rounded-md border bg-card hover:bg-accent",
518
- onClick: () => _(J.data),
554
+ onClick: () => f(J.data),
519
555
  children: "Edit"
520
- }), v && /* @__PURE__ */ h("button", {
556
+ }), _ && /* @__PURE__ */ h("button", {
521
557
  type: "button",
522
558
  className: "px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10",
523
- onClick: () => v(J.data),
559
+ onClick: () => _(J.data),
524
560
  children: "Delete"
525
561
  })]
526
562
  })
527
563
  ]
528
564
  }),
529
- je && /* @__PURE__ */ h("div", {
565
+ Me && /* @__PURE__ */ h("div", {
530
566
  className: "absolute top-2 left-14 right-2 z-10 text-xs px-3 py-1.5 rounded-md bg-destructive/10 text-destructive border border-destructive/30",
531
- children: je
567
+ children: Me
532
568
  })
533
569
  ]
534
570
  }),
535
- E && /* @__PURE__ */ h(ae, { result: E }),
536
- X.isOverlay && /* @__PURE__ */ h(fe, {
571
+ T && /* @__PURE__ */ h(ae, { result: T }),
572
+ X.isOverlay && /* @__PURE__ */ h(pe, {
537
573
  ...X,
538
574
  title: "Location Details",
539
575
  children: (e) => /* @__PURE__ */ h("div", {
@@ -581,17 +617,17 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
581
617
  })
582
618
  })
583
619
  });
584
- }, De = {
620
+ }, D = {
585
621
  filter: !0,
586
622
  sort: !0
587
- }, D = c(({ schema: e, ...t }) => {
588
- let { dataSource: n } = ue() || {};
623
+ }, O = c(({ schema: e, ...t }) => {
624
+ let { dataSource: n } = de() || {}, { t: r } = le();
589
625
  return /* @__PURE__ */ h(d, {
590
626
  schema: e,
591
- mapping: De,
627
+ mapping: D,
592
628
  dataSource: n,
593
629
  testId: "object-map",
594
- errorTitle: "This map’s data source could not be resolved",
630
+ errorTitle: r("element.map.sourceUnresolved", { defaultValue: "This map’s data source could not be resolved" }),
595
631
  children: (e) => /* @__PURE__ */ h(E, {
596
632
  schema: e,
597
633
  dataSource: n,
@@ -599,7 +635,7 @@ var E = ({ schema: a, dataSource: c, className: u, data: d, onMarkerClick: ue, o
599
635
  })
600
636
  });
601
637
  });
602
- a.register("object-map", D, {
638
+ a.register("object-map", O, {
603
639
  namespace: "plugin-map",
604
640
  label: "Object Map",
605
641
  category: "view",
@@ -617,7 +653,7 @@ a.register("object-map", D, {
617
653
  {
618
654
  name: "data",
619
655
  type: "object",
620
- description: "A `{ provider, … }` data-source configuration, read FIRST on the record-source ladder: a map carrying one never reaches `staticData` and never queries `objectName`. `{ provider: 'value', items }` plots those rows and `{ provider: 'object', object }` queries that object, both narrowed by `filter` and ordered by `sort`. The `api` provider is not implemented on the map and plots no markers. A bare array is not this key’s shape and is not a record source: the map falls through to `staticData`, then `objectName`, so inline rows belong under `staticData`."
656
+ description: "A `{ provider, … }` data-source configuration, read FIRST on the record-source ladder: a map carrying one never reaches `staticData` and never queries `objectName`. `{ provider: 'value', items }` plots those rows and `{ provider: 'object', object }` queries that object, both narrowed by `filter` and ordered by `sort`. A bare array is not this key’s shape and is not a record source: the map falls through to `staticData`, then `objectName`, so inline rows belong under `staticData`."
621
657
  },
622
658
  {
623
659
  name: "staticData",
@@ -652,4 +688,4 @@ a.register("object-map", D, {
652
688
  ]
653
689
  });
654
690
  //#endregion
655
- export { E as ObjectMap, D as ObjectMapRenderer };
691
+ export { E as ObjectMap, O as ObjectMapRenderer };
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/types/zod"),require("@object-ui/components"),require("@object-ui/permissions"),require("react-map-gl/maplibre"),require("maplibre-gl/dist/maplibre-gl.css"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@object-ui/types/zod`,`@object-ui/components`,`@object-ui/permissions`,`react-map-gl/maplibre`,`maplibre-gl/dist/maplibre-gl.css`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginMap={},e.React,e.ObjectUICore,e.ObjectUIReact,e.ObjectUITypesZod,e.ObjectUIComponents,e._object_ui_permissions,e.react_map_gl_maplibre,e.maplibre_gl_dist_maplibre_gl_css,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c,l){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var u=Object.create,d=Object.defineProperty,ee=Object.getOwnPropertyDescriptor,f=Object.getOwnPropertyNames,p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,h=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=f(t),a=0,o=i.length,s;a<o;a++)s=i[a],!m.call(e,s)&&s!==n&&d(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=ee(t,s))||r.enumerable});return e},g=(e,t,n)=>(n=e==null?{}:u(p(e)),h(t||!e||!e.__esModule||!m.call(e,`default`)?d(n,`default`,{value:e,enumerable:!0}):n,e));t=g(t,1),s=g(s,1);function _(e){return e>=-180&&e<180?e:((e+180)%360+360)%360-180}var te=e=>Math.min(85,Math.max(-85,e));function ne(e){if(e.length===0)return null;let t=e.map(([e])=>_(e)).sort((e,t)=>e-t),n=e.map(([,e])=>te(e)),r=t.length,i=t[0]+360-t[r-1],a=0;for(let e=1;e<r;e++){let n=t[e]-t[e-1];n>i&&(i=n,a=e)}let o=t[a],s=t[(a+r-1)%r],c=a===0?s:s+360;return[[o,Math.min(...n)],[c,Math.max(...n)]]}function re(e){let[[t,n],[r,i]]=e;return{longitude:_((t+r)/2),latitude:(n+i)/2}}var ie=`https://demotiles.maplibre.org/style.json`,v=Object.keys(i.ObjectMapConfigSchema.shape).filter(e=>e!==`style`);function ae(e){return(0,n.resolveRecordSourceConfig)(e,`view-data`)}var y=()=>globalThis.process?.env?.NODE_ENV!==`production`,b=new Set;function x(e){if(!y())return;let t=e.filter;if(!t||typeof t!=`object`||Array.isArray(t)||!Object.prototype.hasOwnProperty.call(t,`map`))return;let n=t.map;if(!n||typeof n!=`object`)return;let r;try{r=`${e.type??`map`}::${e.objectName??``}::${JSON.stringify(n)}`}catch{r=`${e.type??`map`}::${e.objectName??``}::<unserializable>`}b.has(r)||(b.add(r),console.warn("[ObjectMap] `filter.map` is no longer read as map configuration, so this map has NO coordinate binding and renders the \"Map configuration required\" refusal (objectui#8169 — the `latitude` / `longitude` / `location` defaults are gone). `filter` is the query filter; the map config belongs under the declared `map` input — move it to `schema.map` (`{ type: 'object-map', map: { latitudeField, longitudeField, titleField } }`). The old spelling was never documented and could not survive a `dataSource` binding, whose merged filter is an `and` node with no `map` key at all (objectstack#7121). If `map` is genuinely a field you are filtering on, ignore this — the filter itself is passed through untouched. objectui#4034."))}var S=new Set;function C(e){if(!y())return;let t=e.style;if(typeof t!=`string`||t===``)return;let n=`${e.type??`map`}::${e.objectName??``}::${t}`;S.has(n)||(S.add(n),console.warn(`[ObjectMap] A top-level \`style\` is NOT read as a map style, so this map is rendering with the DEFAULT public demo tiles and \`${t}\` was dropped. \`style\` is the base schema's INLINE CSS key (a record of CSS properties), which every node may carry; the map style is \`mapStyle\` — named that way precisely to avoid this collision. Write \`mapStyle: '${t}'\` at the top level, or \`map: { style: '${t}' }\` in the declared config block. On a view, write that same declared \`map: { style: ... }\`: ObjectView / ListView flatten \`options.map\` through a whitelist of the keys \`ObjectMapConfigSchema\` declares, and that whitelist carries \`style\` out under the flat spelling \`mapStyle\` (objectui#9950), so the declared block arrives and is read. \`mapStyle\` is the TOP-LEVEL spelling only — inside the \`map\` block it is undeclared, and the flatten drops it. objectui#5017.`))}var w=new Set;function T(e){if(!y())return;let t=v.filter(t=>e[t]!==void 0);if(t.length===0)return;let n=`${e.type??`map`}::${e.objectName??``}::${t.join(`,`)}`;w.has(n)||(w.add(n),console.warn(`[ObjectMap] The \`map\` block configures this map, so these top-level keys are IGNORED: ${t.map(e=>`\`${e}\``).join(`, `)}. The \`map\` block is the authoring shape; the flat top-level spelling is the internal form ObjectView/ListView produce when they flatten \`options.map\`, and what the author wrote outranks it. Move anything you still need into \`map\`, or drop the \`map\` block. objectui#5018.`))}function oe(e){x(e),C(e);let t=e.mapStyle||e.map?.style,n=e.map??null;if(n){let r=i.ObjectMapConfigSchema.safeParse(n);return r.success||console.warn(`[ObjectMap] Invalid map configuration:`,r.error.format()),T(e),{...n,style:t}}return e.locationField||e.latitudeField?{locationField:e.locationField,latitudeField:e.latitudeField,longitudeField:e.longitudeField,titleField:e.titleField,descriptionField:e.descriptionField,zoom:e.zoom,center:e.center,style:t}:{style:t}}function se(e){return!!e.locationField||!!(e.latitudeField&&e.longitudeField)}function ce(e,t){if(t.latitudeField&&t.longitudeField){let n=e[t.latitudeField],r=e[t.longitudeField];if(typeof n==`number`&&typeof r==`number`)return[n,r]}if(t.locationField){let n=e[t.locationField];if(typeof n==`object`&&n){let e=n.lat||n.latitude,t=n.lng||n.lon||n.longitude;if(typeof e==`number`&&typeof t==`number`)return[e,t]}if(typeof n==`string`){let e=n.split(`,`).map(e=>parseFloat(e.trim()));if(e.length===2&&!isNaN(e[0])&&!isNaN(e[1]))return[e[0],e[1]]}if(Array.isArray(n)&&n.length===2){let e=parseFloat(n[0]),t=parseFloat(n[1]);if(!isNaN(e)&&!isNaN(t))return[e,t]}}return null}function le(e,t,n=50){if(e.length<=1||t>=15)return e.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1}));let r=n/2**t,i=new Map;e.forEach(e=>{let t=`${Math.floor(e.coordinates[0]/r)}:${Math.floor(e.coordinates[1]/r)}`;i.has(t)||i.set(t,[]),i.get(t).push(e)});let a=[];return i.forEach((e,t)=>{if(e.length===1)a.push({id:e[0].id,coordinates:e[0].coordinates,markers:e,isCluster:!1});else{let n=e.reduce((e,t)=>e+t.coordinates[0],0)/e.length,r=e.reduce((e,t)=>e+t.coordinates[1],0)/e.length;a.push({id:`cluster-${t}`,coordinates:[n,r],markers:e,isCluster:!0})}}),a}var E=({schema:e,dataSource:i,className:c,data:u,onMarkerClick:d,onRowClick:ee,onEdit:f,onDelete:p,enableClustering:m,clusterRadius:h=50})=>{let[g,_]=(0,t.useState)([]),[te,v]=(0,t.useState)(!0),[y,b]=(0,t.useState)(null),[x,S]=(0,t.useState)(null),[C,w]=(0,t.useState)(null),[T,E]=(0,t.useState)(``),D=(0,a.useIsMobile)(),O=(0,t.useRef)(null),[k,ue]=(0,t.useState)(null),[de,A]=(0,t.useState)(null),[fe,j]=(0,t.useState)(!1),[pe,me]=(0,t.useState)(null),he=(0,t.useCallback)(e=>{me(e?.error?.message||`Failed to load the map style/tiles.`)},[]),ge=(0,t.useCallback)(()=>{if(typeof navigator>`u`||!navigator.geolocation){A(`Geolocation is not available in this browser.`);return}j(!0),A(null),navigator.geolocation.getCurrentPosition(e=>{let{longitude:t,latitude:n}=e.coords;ue({lng:t,lat:n}),j(!1);try{O.current?.flyTo({center:[t,n],zoom:12,duration:800})}catch{}},e=>{j(!1),A(e.message||`Unable to retrieve location.`)},{enableHighAccuracy:!1,timeout:8e3,maximumAge:6e4})},[]),M=(0,t.useMemo)(()=>ae(e),[e]),N=(0,t.useMemo)(()=>oe(e),[e]),P=M?.provider===`value`,F=M?.provider,I=M?.provider===`object`?M.object:void 0,L=M?.provider===`value`?M.items:void 0,_e=(0,n.resolveRecordSourceObjectName)(e,M),{ready:ve,def:R}=(0,r.useSettledSchema)(_e??``,P?void 0:i),z=(0,o.usePermissions)(),B=!Array.isArray(u)&&F===`object`,V=(0,r.useDataInvalidation)(B?I:void 0),ye=(0,t.useRef)(V),be=(0,t.useRef)(null),H=(0,t.useRef)(0),xe=(0,r.useFilterScope)(),U=(0,r.useResolvedFilter)(e.filter,xe);(0,t.useEffect)(()=>{if(B&&!ve){v(!0);return}let t=[u,F,I,L,i,P,U,e.sort,R,z],r=be.current,a=r!==null&&r.length===t.length&&t.every((e,t)=>Object.is(e,r[t])),o=V!==ye.current;ye.current=V;let s=o&&a,c=++H.current,l=()=>H.current===c,d=(e,n)=>{l()&&(_(e),S(n),b(null),be.current=t)};return(async()=>{try{if(s||v(!0),Array.isArray(u)){d(u,null);return}if(P&&F===`value`){let t=await new n.ValueDataSource({items:L??[]}).find(``,{$filter:U,$orderby:(0,n.convertSortToQueryParams)(e.sort),...(0,n.nonGridRowCeilingQuery)()}),r=(0,n.applyNonGridRowCeiling)(t);d(r.rows,r);return}if(!i||typeof i.find!=`function`)throw Error(`DataSource required for object/api providers`);if(F===`object`){let t=I,r=(0,n.buildExpandFields)(R?.fields),a=z?.isLoaded?r.filter(e=>z.checkField(t,e,`read`)):r,o=await i.find(t,{$filter:U,$orderby:(0,n.convertSortToQueryParams)(e.sort),...(0,n.nonGridRowCeilingQuery)(),...a.length>0?{$expand:a}:{}}),s=(0,n.applyNonGridRowCeiling)(o);d(s.rows,s)}else F===`api`&&(console.warn(`API provider not yet implemented for ObjectMap`),d([],null))}catch(e){s?console.error(`[ObjectMap] Failed to refresh data:`,e):l()&&b(e)}finally{l()&&v(!1)}})(),()=>{H.current+=1}},[u,F,I,L,i,P,U,e.sort,ve,R,z,V,B]);let{markers:W,invalidCount:G}=(0,t.useMemo)(()=>{let e=0;return{markers:g.map((t,r)=>{let i=ce(t,N);if(!i)return e++,null;let a=(0,n.getRecordDisplayName)(R,t,{titleField:N.titleField,fallback:`Marker`}),o=(0,n.recordDisplayValueAt)(t,N.descriptionField),[s,c]=i;return!isFinite(s)||!isFinite(c)||s<-90||s>90||c<-180||c>180?(e++,null):{id:t.id||t._id||`marker-${r}`,title:a,description:o,coordinates:[c,s],data:t}}).filter(e=>e!==null),invalidCount:e}},[g,N,R]),K=(0,t.useMemo)(()=>W.find(e=>e.id===C),[W,C]),[q,Se]=(0,t.useState)(N.zoom||3),Ce=(0,t.useCallback)(e=>{try{let t=e?.target?.getZoom?.();typeof t==`number`&&Number.isFinite(t)&&Se(Math.round(t))}catch{}},[]),J=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:ee}),Y=(0,t.useMemo)(()=>{if(!T.trim())return W;let e=T.toLowerCase();return W.filter(t=>t.title?.toLowerCase().includes(e)||t.description?.toLowerCase().includes(e))},[W,T]),we=(0,t.useMemo)(()=>m??(e.enableClustering||Y.length>100)?le(Y,q,h):Y.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1})),[Y,q,m,h,e]),X=(0,t.useMemo)(()=>ne(Y.map(e=>e.coordinates)),[Y]),Z=typeof N.center?.[0]==`number`?N.center[0]:void 0,Q=typeof N.center?.[1]==`number`?N.center[1]:void 0,$=typeof N.zoom==`number`?N.zoom:void 0,Te=Z!==void 0||Q!==void 0||$!==void 0,Ee=(0,t.useMemo)(()=>{if(X&&!Te)return{bounds:X,fitBoundsOptions:{padding:48,maxZoom:12}};let e=X?re(X):{longitude:0,latitude:0};return{longitude:Q??e.longitude,latitude:Z??e.latitude,zoom:$??(X?3:2)}},[X,Te,Q,Z,$]);return se(N)?te?(0,l.jsx)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,l.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading map...`})})}):y?(0,l.jsx)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,l.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,y.message]})})}):(0,l.jsxs)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:[G>0&&(0,l.jsx)(`div`,{className:`mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded`,children:`${G} record${G===1?``:`s`} with missing or invalid coordinates excluded from the map.`}),W.length>0&&(0,l.jsx)(`div`,{className:`mb-2`,children:(0,l.jsx)(`input`,{type:`text`,value:T,onChange:e=>E(e.target.value),placeholder:`Search locations…`,className:`w-full px-3 py-2 text-sm border rounded-md bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring`})}),(0,l.jsxs)(`div`,{className:`relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full`,children:[(0,l.jsxs)(s.default,{ref:e=>{O.current=e},initialViewState:Ee,style:{width:`100%`,height:`100%`},mapStyle:N.style||ie,touchZoomRotate:!0,dragRotate:!0,touchPitch:!0,onLoad:Ce,onZoom:e=>Se(Math.round(e.viewState.zoom)),onError:he,children:[pe&&(0,l.jsxs)(`div`,{role:`alert`,className:`absolute inset-x-0 top-0 z-20 p-2 text-sm text-center text-amber-900 bg-amber-50 border-b border-amber-200`,children:[`Map failed to load (`,pe,`). Markers below are still listed in the search box;`,` `,N.style?`check the configured map style URL.`:`configure a custom map style for production use.`]}),(0,l.jsx)(s.NavigationControl,{position:`top-right`,showCompass:!0,showZoom:!0}),(0,l.jsx)(`button`,{type:`button`,onClick:ge,disabled:fe,className:`absolute top-2 left-2 z-10 inline-flex items-center justify-center size-9 rounded-md bg-background/95 border shadow-sm hover:bg-background disabled:opacity-50`,"aria-label":`Show my location`,"data-testid":`map-geolocate`,children:(0,l.jsx)(`span`,{"aria-hidden":`true`,children:fe?`⏳`:`🧭`})}),k&&(0,l.jsx)(s.Marker,{longitude:k.lng,latitude:k.lat,anchor:`center`,children:(0,l.jsx)(`div`,{className:`size-3 rounded-full bg-blue-500 ring-4 ring-blue-500/30 shadow`,"aria-label":`Your location`,"data-testid":`map-user-location`})}),we.map(e=>e.isCluster?(0,l.jsx)(s.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`center`,onClick:t=>{t.originalEvent.stopPropagation();try{let t=Math.min(20,Math.max(q+2,8));O.current?.flyTo({center:[e.coordinates[0],e.coordinates[1]],zoom:t,duration:600})}catch{}},children:(0,l.jsx)(`div`,{className:`flex items-center justify-center rounded-full bg-primary text-primary-foreground font-bold text-xs cursor-pointer hover:scale-110 transition-transform shadow-md`,style:{width:Math.min(48,24+e.markers.length*2),height:Math.min(48,24+e.markers.length*2)},title:`${e.markers.length} markers`,"data-testid":`map-cluster`,children:e.markers.length})},e.id):(0,l.jsx)(s.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`bottom`,onClick:t=>{t.originalEvent.stopPropagation();let n=e.markers[0];w(n.id),J.handleClick(n.data),d?.(n.data)},children:(0,l.jsx)(`div`,{className:`text-2xl cursor-pointer hover:scale-110 transition-transform`,children:`📍`})},e.id)),K&&!D&&(0,l.jsx)(s.Popup,{longitude:K.coordinates[0],latitude:K.coordinates[1],anchor:`top`,onClose:()=>w(null),closeOnClick:!1,children:(0,l.jsxs)(`div`,{className:`p-2 min-w-[150px] sm:min-w-[200px]`,children:[(0,l.jsx)(`h3`,{className:`font-bold text-sm mb-1`,children:K.title}),K.description&&(0,l.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:K.description}),(0,l.jsxs)(`div`,{className:`mt-2 text-xs flex gap-2`,children:[f&&(0,l.jsx)(`button`,{type:`button`,className:`text-blue-500 hover:underline`,onClick:()=>f(K.data),children:`Edit`}),p&&(0,l.jsx)(`button`,{type:`button`,className:`text-red-500 hover:underline`,onClick:()=>p(K.data),children:`Delete`})]})]})})]}),K&&D&&(0,l.jsxs)(`div`,{className:`absolute inset-x-0 bottom-0 z-30 bg-background border-t shadow-lg rounded-t-2xl p-4 pb-[max(env(safe-area-inset-bottom),1rem)]`,role:`dialog`,"aria-label":`Location details`,"data-testid":`map-mobile-record-sheet`,children:[(0,l.jsx)(`div`,{className:`mx-auto mb-2 h-1 w-10 rounded-full bg-muted`,"aria-hidden":`true`}),(0,l.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,l.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold truncate`,children:K.title}),K.description&&(0,l.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-3`,children:K.description})]}),(0,l.jsx)(`button`,{type:`button`,onClick:()=>w(null),className:`text-muted-foreground hover:text-foreground text-lg leading-none px-2`,"aria-label":`Close details`,"data-testid":`map-mobile-record-close`,children:`×`})]}),(0,l.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-xs`,children:[f&&(0,l.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 rounded-md border bg-card hover:bg-accent`,onClick:()=>f(K.data),children:`Edit`}),p&&(0,l.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10`,onClick:()=>p(K.data),children:`Delete`})]})]}),de&&(0,l.jsx)(`div`,{className:`absolute top-2 left-14 right-2 z-10 text-xs px-3 py-1.5 rounded-md bg-destructive/10 text-destructive border border-destructive/30`,children:de})]}),x&&(0,l.jsx)(r.NonGridRowCeilingNote,{result:x}),J.isOverlay&&(0,l.jsx)(a.NavigationOverlay,{...J,title:`Location Details`,children:e=>(0,l.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,l.jsxs)(`div`,{className:`flex flex-col`,children:[(0,l.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,l.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]}):(0,l.jsx)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border p-4 text-center`,"data-testid":`map-missing-location-binding`,role:`alert`,children:(0,l.jsxs)(`div`,{className:`text-destructive`,children:[`Map configuration required — declare `,(0,l.jsx)(`code`,{className:`font-mono`,children:`map.locationField`}),` `,`or `,(0,l.jsx)(`code`,{className:`font-mono`,children:`map.latitudeField`}),` +`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`map.longitudeField`})]})})})},D={filter:!0,sort:!0},O=(0,n.elementDataSourceBlock)(({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,l.jsx)(r.ElementDataSourceGate,{schema:e,mapping:D,dataSource:n,testId:`object-map`,errorTitle:`This map’s data source could not be resolved`,children:e=>(0,l.jsx)(E,{schema:e,dataSource:n,...t})})});n.ComponentRegistry.register(`object-map`,O,{namespace:`plugin-map`,label:`Object Map`,category:`view`,inputs:[{name:`objectName`,type:`string`,description:"ObjectQL object name. The record source is one of `data`, `staticData` and `objectName`, or the node’s `dataSource` binding; the `object-map` schema refuses a block that declares none of them."},{name:`map`,type:`object`,description:'The field configuration: `latitudeField` / `longitudeField` (or one `locationField` holding a `"lat,lng"` string, a `{ lat, lng }` object or a `[lat, lng]` pair) place each record’s marker, and a record with no readable coordinates is not plotted; `titleField` and `descriptionField` name what the marker popup shows; `zoom` and `center` (`[latitude, longitude]`) set the initial camera, which otherwise fits the markers; `style` is a MapLibre style URL, read after the node’s `mapStyle`.'},{name:`data`,type:`object`,description:"A `{ provider, … }` data-source configuration, read FIRST on the record-source ladder: a map carrying one never reaches `staticData` and never queries `objectName`. `{ provider: 'value', items }` plots those rows and `{ provider: 'object', object }` queries that object, both narrowed by `filter` and ordered by `sort`. The `api` provider is not implemented on the map and plots no markers. A bare array is not this key’s shape and is not a record source: the map falls through to `staticData`, then `objectName`, so inline rows belong under `staticData`."},{name:`staticData`,type:`array`,description:"Inline records, read SECOND on the record-source ladder: a `data` configuration wins and this key is then never reached, while `objectName` is read AFTER it, so a map carrying both plots these rows and never queries that object. `filter` and `sort` narrow and order these rows exactly as they do fetched ones."},{name:`filter`,type:`array`,description:"Base query filter in the rule-array form `[{ field, operator, value }, ...]`, narrowing the markers the map plots — fetched rows and inline (`staticData`, `{ provider: 'value' }`) rows alike. Context tokens such as `{current_user_id}` are resolved first, then the filter is lowered to `$filter` on the query. The MongoDB-style record form is not this key’s shape."},{name:`sort`,type:`array`,description:"Marker order in `[{ field, order }]` form, ordering the rows the map plots. Lowered to `$orderby` on the same query."},{name:`mapStyle`,type:`string`,description:"MapLibre style URL or spec, overriding the public demo tiles. Read before `map.style`; NOT the base node `style`, which is an inline CSS record"},{name:`navigation`,type:`object`,description:"What a marker click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the marker’s record in that overlay, but `split` opens nothing, because the map hands the split shell no main panel; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of the map’s `objectName` through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a map that names no `objectName`, there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. A click handler from a parent view outranks the whole key."},{name:`enableClustering`,type:`boolean`,description:"Group nearby markers into one numbered cluster. Absent, the map clusters only above 100 markers; `false` turns clustering off at any count."}]}),e.ObjectMap=E,e.ObjectMapRenderer=O});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/types/zod"),require("@object-ui/components"),require("@object-ui/permissions"),require("react-map-gl/maplibre"),require("maplibre-gl/dist/maplibre-gl.css"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@object-ui/types/zod`,`@object-ui/components`,`@object-ui/permissions`,`react-map-gl/maplibre`,`maplibre-gl/dist/maplibre-gl.css`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginMap={},e.React,e.ObjectUICore,e.ObjectUIReact,e.ObjectUITypesZod,e.ObjectUIComponents,e._object_ui_permissions,e.react_map_gl_maplibre,e.maplibre_gl_dist_maplibre_gl_css,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c,l){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var u=Object.create,d=Object.defineProperty,ee=Object.getOwnPropertyDescriptor,f=Object.getOwnPropertyNames,p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,h=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=f(t),a=0,o=i.length,s;a<o;a++)s=i[a],!m.call(e,s)&&s!==n&&d(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=ee(t,s))||r.enumerable});return e},g=(e,t,n)=>(n=e==null?{}:u(p(e)),h(t||!e||!e.__esModule||!m.call(e,`default`)?d(n,`default`,{value:e,enumerable:!0}):n,e));t=g(t,1),s=g(s,1);function _(e){return e>=-180&&e<180?e:((e+180)%360+360)%360-180}var te=e=>Math.min(85,Math.max(-85,e));function ne(e){if(e.length===0)return null;let t=e.map(([e])=>_(e)).sort((e,t)=>e-t),n=e.map(([,e])=>te(e)),r=t.length,i=t[0]+360-t[r-1],a=0;for(let e=1;e<r;e++){let n=t[e]-t[e-1];n>i&&(i=n,a=e)}let o=t[a],s=t[(a+r-1)%r],c=a===0?s:s+360;return[[o,Math.min(...n)],[c,Math.max(...n)]]}function re(e){let[[t,n],[r,i]]=e;return{longitude:_((t+r)/2),latitude:(n+i)/2}}var ie=`https://demotiles.maplibre.org/style.json`;function ae(){if(typeof document>`u`)return!0;try{let e=document.createElement(`canvas`).getContext(`webgl2`);return e?(e.getExtension(`WEBGL_lose_context`)?.loseContext(),!0):!1}catch{return!1}}var v=Object.keys(i.ObjectMapConfigSchema.shape).filter(e=>e!==`style`);function oe(e){return(0,n.resolveRecordSourceConfig)(e,`view-data`)}var y=()=>globalThis.process?.env?.NODE_ENV!==`production`,b=new Set;function x(e){if(!y())return;let t=e.filter;if(!t||typeof t!=`object`||Array.isArray(t)||!Object.prototype.hasOwnProperty.call(t,`map`))return;let n=t.map;if(!n||typeof n!=`object`)return;let r;try{r=`${e.type??`map`}::${e.objectName??``}::${JSON.stringify(n)}`}catch{r=`${e.type??`map`}::${e.objectName??``}::<unserializable>`}b.has(r)||(b.add(r),console.warn("[ObjectMap] `filter.map` is no longer read as map configuration, so this map has NO coordinate binding and renders the \"Map configuration required\" refusal (objectui#8169 — the `latitude` / `longitude` / `location` defaults are gone). `filter` is the query filter; the map config belongs under the declared `map` input — move it to `schema.map` (`{ type: 'object-map', map: { latitudeField, longitudeField, titleField } }`). The old spelling was never documented and could not survive a `dataSource` binding, whose merged filter is an `and` node with no `map` key at all (objectstack#7121). If `map` is genuinely a field you are filtering on, ignore this — the filter itself is passed through untouched. objectui#4034."))}var S=new Set;function C(e){if(!y())return;let t=e.style;if(typeof t!=`string`||t===``)return;let n=`${e.type??`map`}::${e.objectName??``}::${t}`;S.has(n)||(S.add(n),console.warn(`[ObjectMap] A top-level \`style\` is NOT read as a map style, so this map is rendering with the DEFAULT public demo tiles and \`${t}\` was dropped. \`style\` is the base schema's INLINE CSS key (a record of CSS properties), which every node may carry; the map style is \`mapStyle\` — named that way precisely to avoid this collision. Write \`mapStyle: '${t}'\` at the top level, or \`map: { style: '${t}' }\` in the declared config block. On a view, write that same declared \`map: { style: ... }\`: ObjectView / ListView flatten \`options.map\` through a whitelist of the keys \`ObjectMapConfigSchema\` declares, and that whitelist carries \`style\` out under the flat spelling \`mapStyle\` (objectui#9950), so the declared block arrives and is read. \`mapStyle\` is the TOP-LEVEL spelling only — inside the \`map\` block it is undeclared, and the flatten drops it. objectui#5017.`))}var w=new Set;function T(e){if(!y())return;let t=v.filter(t=>e[t]!==void 0);if(t.length===0)return;let n=`${e.type??`map`}::${e.objectName??``}::${t.join(`,`)}`;w.has(n)||(w.add(n),console.warn(`[ObjectMap] The \`map\` block configures this map, so these top-level keys are IGNORED: ${t.map(e=>`\`${e}\``).join(`, `)}. The \`map\` block is the authoring shape; the flat top-level spelling is the internal form ObjectView/ListView produce when they flatten \`options.map\`, and what the author wrote outranks it. Move anything you still need into \`map\`, or drop the \`map\` block. objectui#5018.`))}function se(e){x(e),C(e);let t=e.mapStyle||e.map?.style,n=e.map??null;if(n){let r=i.ObjectMapConfigSchema.safeParse(n);return r.success||console.warn(`[ObjectMap] Invalid map configuration:`,r.error.format()),T(e),{...n,style:t}}return e.locationField||e.latitudeField?{locationField:e.locationField,latitudeField:e.latitudeField,longitudeField:e.longitudeField,titleField:e.titleField,descriptionField:e.descriptionField,zoom:e.zoom,center:e.center,style:t}:{style:t}}function ce(e){return!!e.locationField||!!(e.latitudeField&&e.longitudeField)}function le(e,t){if(t.latitudeField&&t.longitudeField){let n=e[t.latitudeField],r=e[t.longitudeField];if(typeof n==`number`&&typeof r==`number`)return[n,r]}if(t.locationField){let n=e[t.locationField];if(typeof n==`object`&&n){let e=n.lat||n.latitude,t=n.lng||n.lon||n.longitude;if(typeof e==`number`&&typeof t==`number`)return[e,t]}if(typeof n==`string`){let e=n.split(`,`).map(e=>parseFloat(e.trim()));if(e.length===2&&!isNaN(e[0])&&!isNaN(e[1]))return[e[0],e[1]]}if(Array.isArray(n)&&n.length===2){let e=parseFloat(n[0]),t=parseFloat(n[1]);if(!isNaN(e)&&!isNaN(t))return[e,t]}}return null}function ue(e,t,n=50){if(e.length<=1||t>=15)return e.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1}));let r=n/2**t,i=new Map;e.forEach(e=>{let t=`${Math.floor(e.coordinates[0]/r)}:${Math.floor(e.coordinates[1]/r)}`;i.has(t)||i.set(t,[]),i.get(t).push(e)});let a=[];return i.forEach((e,t)=>{if(e.length===1)a.push({id:e[0].id,coordinates:e[0].coordinates,markers:e,isCluster:!1});else{let n=e.reduce((e,t)=>e+t.coordinates[0],0)/e.length,r=e.reduce((e,t)=>e+t.coordinates[1],0)/e.length;a.push({id:`cluster-${t}`,coordinates:[n,r],markers:e,isCluster:!0})}}),a}var E=({schema:e,dataSource:i,className:c,data:u,onMarkerClick:d,onRowClick:ee,onEdit:f,onDelete:p,enableClustering:m,clusterRadius:h=50})=>{let[g,_]=(0,t.useState)([]),[te,v]=(0,t.useState)(!0),[y,b]=(0,t.useState)(null),[x,S]=(0,t.useState)(null),[C,w]=(0,t.useState)(null),[T,E]=(0,t.useState)(``),D=(0,a.useIsMobile)(),O=(0,t.useRef)(null),[k,de]=(0,t.useState)(null),[fe,A]=(0,t.useState)(null),[pe,j]=(0,t.useState)(!1),[me,he]=(0,t.useState)(null),ge=(0,t.useCallback)(e=>{he(e?.error?.message||`Failed to load the map style/tiles.`)},[]),[_e]=(0,t.useState)(ae),ve=(0,t.useCallback)(()=>{if(typeof navigator>`u`||!navigator.geolocation){A(`Geolocation is not available in this browser.`);return}j(!0),A(null),navigator.geolocation.getCurrentPosition(e=>{let{longitude:t,latitude:n}=e.coords;de({lng:t,lat:n}),j(!1);try{O.current?.flyTo({center:[t,n],zoom:12,duration:800})}catch{}},e=>{j(!1),A(e.message||`Unable to retrieve location.`)},{enableHighAccuracy:!1,timeout:8e3,maximumAge:6e4})},[]),M=(0,t.useMemo)(()=>oe(e),[e]),N=(0,t.useMemo)(()=>se(e),[e]),P=M?.provider===`value`,F=M?.provider,I=M?.provider===`object`?M.object:void 0,L=M?.provider===`value`?M.items:void 0,ye=(0,n.resolveRecordSourceObjectName)(e,M),{ready:be,def:R}=(0,r.useSettledSchema)(ye??``,P?void 0:i),z=(0,o.usePermissions)(),B=!Array.isArray(u)&&F===`object`,V=(0,r.useDataInvalidation)(B?I:void 0),xe=(0,t.useRef)(V),Se=(0,t.useRef)(null),H=(0,t.useRef)(0),Ce=(0,r.useFilterScope)(),U=(0,r.useResolvedFilter)(e.filter,Ce);(0,t.useEffect)(()=>{if(B&&!be){v(!0);return}let t=[u,F,I,L,i,P,U,e.sort,R,z],r=Se.current,a=r!==null&&r.length===t.length&&t.every((e,t)=>Object.is(e,r[t])),o=V!==xe.current;xe.current=V;let s=o&&a,c=++H.current,l=()=>H.current===c,d=(e,n)=>{l()&&(_(e),S(n),b(null),Se.current=t)};return(async()=>{try{if(s||v(!0),Array.isArray(u)){d(u,null);return}if(P&&F===`value`){let t=await new n.ValueDataSource({items:L??[]}).find(``,{$filter:U,$orderby:(0,n.convertSortToQueryParams)(e.sort),...(0,n.nonGridRowCeilingQuery)()}),r=(0,n.applyNonGridRowCeiling)(t);d(r.rows,r);return}if(!i||typeof i.find!=`function`)throw Error(`DataSource required for the object provider`);if(F===`object`){let t=I,r=(0,n.buildExpandFields)(R?.fields),a=z?.isLoaded?r.filter(e=>z.checkField(t,e,`read`)):r,o=await i.find(t,{$filter:U,$orderby:(0,n.convertSortToQueryParams)(e.sort),...(0,n.nonGridRowCeilingQuery)(),...a.length>0?{$expand:a}:{}}),s=(0,n.applyNonGridRowCeiling)(o);d(s.rows,s)}}catch(e){s?console.error(`[ObjectMap] Failed to refresh data:`,e):l()&&b(e)}finally{l()&&v(!1)}})(),()=>{H.current+=1}},[u,F,I,L,i,P,U,e.sort,be,R,z,V,B]);let{markers:W,invalidCount:G}=(0,t.useMemo)(()=>{let e=0;return{markers:g.map((t,r)=>{let i=le(t,N);if(!i)return e++,null;let a=(0,n.getRecordDisplayName)(R,t,{titleField:N.titleField,fallback:`Marker`}),o=(0,n.recordDisplayValueAt)(t,N.descriptionField),[s,c]=i;return!isFinite(s)||!isFinite(c)||s<-90||s>90||c<-180||c>180?(e++,null):{id:t.id||t._id||`marker-${r}`,title:a,description:o,coordinates:[c,s],data:t}}).filter(e=>e!==null),invalidCount:e}},[g,N,R]),K=(0,t.useMemo)(()=>W.find(e=>e.id===C),[W,C]),[q,we]=(0,t.useState)(N.zoom||3),Te=(0,t.useCallback)(e=>{try{let t=e?.target?.getZoom?.();typeof t==`number`&&Number.isFinite(t)&&we(Math.round(t))}catch{}},[]),J=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:ee}),Ee=e=>{w(e.id),J.handleClick(e.data),d?.(e.data)},Y=(0,t.useMemo)(()=>{if(!T.trim())return W;let e=T.toLowerCase();return W.filter(t=>t.title?.toLowerCase().includes(e)||t.description?.toLowerCase().includes(e))},[W,T]),De=(0,t.useMemo)(()=>m??(e.enableClustering||Y.length>100)?ue(Y,q,h):Y.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1})),[Y,q,m,h,e]),X=(0,t.useMemo)(()=>ne(Y.map(e=>e.coordinates)),[Y]),Z=typeof N.center?.[0]==`number`?N.center[0]:void 0,Q=typeof N.center?.[1]==`number`?N.center[1]:void 0,$=typeof N.zoom==`number`?N.zoom:void 0,Oe=Z!==void 0||Q!==void 0||$!==void 0,ke=(0,t.useMemo)(()=>{if(X&&!Oe)return{bounds:X,fitBoundsOptions:{padding:48,maxZoom:12}};let e=X?re(X):{longitude:0,latitude:0};return{longitude:Q??e.longitude,latitude:Z??e.latitude,zoom:$??(X?3:2)}},[X,Oe,Q,Z,$]);return ce(N)?te?(0,l.jsx)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,l.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading map...`})})}):y?(0,l.jsx)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,l.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,y.message]})})}):(0,l.jsxs)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:[G>0&&(0,l.jsx)(`div`,{className:`mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded`,children:`${G} record${G===1?``:`s`} with missing or invalid coordinates excluded from the map.`}),W.length>0&&(0,l.jsx)(`div`,{className:`mb-2`,children:(0,l.jsx)(`input`,{type:`text`,value:T,onChange:e=>E(e.target.value),placeholder:`Search locations…`,className:`w-full px-3 py-2 text-sm border rounded-md bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring`})}),(0,l.jsxs)(`div`,{className:`relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full`,children:[_e?(0,l.jsxs)(s.default,{ref:e=>{O.current=e},initialViewState:ke,style:{width:`100%`,height:`100%`},mapStyle:N.style||ie,touchZoomRotate:!0,dragRotate:!0,touchPitch:!0,onLoad:Te,onZoom:e=>we(Math.round(e.viewState.zoom)),onError:ge,children:[me&&(0,l.jsxs)(`div`,{role:`alert`,className:`absolute inset-x-0 top-0 z-20 p-2 text-sm text-center text-amber-900 bg-amber-50 border-b border-amber-200`,children:[`Map failed to load (`,me,`). Markers below are still listed in the search box;`,` `,N.style?`check the configured map style URL.`:`configure a custom map style for production use.`]}),(0,l.jsx)(s.NavigationControl,{position:`top-right`,showCompass:!0,showZoom:!0}),(0,l.jsx)(`button`,{type:`button`,onClick:ve,disabled:pe,className:`absolute top-2 left-2 z-10 inline-flex items-center justify-center size-9 rounded-md bg-background/95 border shadow-sm hover:bg-background disabled:opacity-50`,"aria-label":`Show my location`,"data-testid":`map-geolocate`,children:(0,l.jsx)(`span`,{"aria-hidden":`true`,children:pe?`⏳`:`🧭`})}),k&&(0,l.jsx)(s.Marker,{longitude:k.lng,latitude:k.lat,anchor:`center`,children:(0,l.jsx)(`div`,{className:`size-3 rounded-full bg-blue-500 ring-4 ring-blue-500/30 shadow`,"aria-label":`Your location`,"data-testid":`map-user-location`})}),De.map(e=>e.isCluster?(0,l.jsx)(s.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`center`,onClick:t=>{t.originalEvent.stopPropagation();try{let t=Math.min(20,Math.max(q+2,8));O.current?.flyTo({center:[e.coordinates[0],e.coordinates[1]],zoom:t,duration:600})}catch{}},children:(0,l.jsx)(`div`,{className:`flex items-center justify-center rounded-full bg-primary text-primary-foreground font-bold text-xs cursor-pointer hover:scale-110 transition-transform shadow-md`,style:{width:Math.min(48,24+e.markers.length*2),height:Math.min(48,24+e.markers.length*2)},title:`${e.markers.length} markers`,"data-testid":`map-cluster`,children:e.markers.length})},e.id):(0,l.jsx)(s.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`bottom`,onClick:t=>{t.originalEvent.stopPropagation(),Ee(e.markers[0])},children:(0,l.jsx)(`div`,{className:`text-2xl cursor-pointer hover:scale-110 transition-transform`,children:`📍`})},e.id)),K&&!D&&(0,l.jsx)(s.Popup,{longitude:K.coordinates[0],latitude:K.coordinates[1],anchor:`top`,onClose:()=>w(null),closeOnClick:!1,children:(0,l.jsxs)(`div`,{className:`p-2 min-w-[150px] sm:min-w-[200px]`,children:[(0,l.jsx)(`h3`,{className:`font-bold text-sm mb-1`,children:K.title}),K.description&&(0,l.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:K.description}),(0,l.jsxs)(`div`,{className:`mt-2 text-xs flex gap-2`,children:[f&&(0,l.jsx)(`button`,{type:`button`,className:`text-blue-500 hover:underline`,onClick:()=>f(K.data),children:`Edit`}),p&&(0,l.jsx)(`button`,{type:`button`,className:`text-red-500 hover:underline`,onClick:()=>p(K.data),children:`Delete`})]})]})})]}):(0,l.jsxs)(`div`,{className:`flex h-full flex-col`,"data-testid":`map-webgl2-fallback`,children:[(0,l.jsx)(`div`,{role:`alert`,className:`p-2 text-sm text-center text-amber-900 bg-amber-50 border-b border-amber-200`,children:`Map failed to load (this browser does not provide WebGL2, which the map needs). The records are listed below; turn on hardware acceleration or use a browser with WebGL2 to see the map.`}),(0,l.jsxs)(`ul`,{className:`min-h-0 flex-1 overflow-y-auto divide-y bg-background`,"aria-label":`Locations`,children:[Y.length===0&&(0,l.jsx)(`li`,{className:`px-3 py-2 text-sm text-muted-foreground`,children:`No locations to list.`}),Y.map(e=>(0,l.jsx)(`li`,{children:(0,l.jsxs)(`button`,{type:`button`,onClick:()=>Ee(e),className:(0,a.cn)(`block w-full px-3 py-2 text-left hover:bg-accent focus:outline-none focus-visible:bg-accent`,e.id===C&&`bg-accent`),children:[(0,l.jsx)(`span`,{className:`block truncate text-sm font-medium`,children:e.title}),e.description&&(0,l.jsx)(`span`,{className:`block truncate text-xs text-muted-foreground`,children:e.description})]})},e.id))]})]}),K&&D&&(0,l.jsxs)(`div`,{className:`absolute inset-x-0 bottom-0 z-30 bg-background border-t shadow-lg rounded-t-2xl p-4 pb-[max(env(safe-area-inset-bottom),1rem)]`,role:`dialog`,"aria-label":`Location details`,"data-testid":`map-mobile-record-sheet`,children:[(0,l.jsx)(`div`,{className:`mx-auto mb-2 h-1 w-10 rounded-full bg-muted`,"aria-hidden":`true`}),(0,l.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,l.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold truncate`,children:K.title}),K.description&&(0,l.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-3`,children:K.description})]}),(0,l.jsx)(`button`,{type:`button`,onClick:()=>w(null),className:`text-muted-foreground hover:text-foreground text-lg leading-none px-2`,"aria-label":`Close details`,"data-testid":`map-mobile-record-close`,children:`×`})]}),(0,l.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-xs`,children:[f&&(0,l.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 rounded-md border bg-card hover:bg-accent`,onClick:()=>f(K.data),children:`Edit`}),p&&(0,l.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10`,onClick:()=>p(K.data),children:`Delete`})]})]}),fe&&(0,l.jsx)(`div`,{className:`absolute top-2 left-14 right-2 z-10 text-xs px-3 py-1.5 rounded-md bg-destructive/10 text-destructive border border-destructive/30`,children:fe})]}),x&&(0,l.jsx)(r.NonGridRowCeilingNote,{result:x}),J.isOverlay&&(0,l.jsx)(a.NavigationOverlay,{...J,title:`Location Details`,children:e=>(0,l.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,l.jsxs)(`div`,{className:`flex flex-col`,children:[(0,l.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,l.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]}):(0,l.jsx)(`div`,{className:(0,a.cn)(`min-w-0 overflow-hidden`,c),children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border p-4 text-center`,"data-testid":`map-missing-location-binding`,role:`alert`,children:(0,l.jsxs)(`div`,{className:`text-destructive`,children:[`Map configuration required — declare `,(0,l.jsx)(`code`,{className:`font-mono`,children:`map.locationField`}),` `,`or `,(0,l.jsx)(`code`,{className:`font-mono`,children:`map.latitudeField`}),` +`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`map.longitudeField`})]})})})},D={filter:!0,sort:!0},O=(0,n.elementDataSourceBlock)(({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{},{t:i}=(0,r.useObjectTranslation)();return(0,l.jsx)(r.ElementDataSourceGate,{schema:e,mapping:D,dataSource:n,testId:`object-map`,errorTitle:i(`element.map.sourceUnresolved`,{defaultValue:`This map’s data source could not be resolved`}),children:e=>(0,l.jsx)(E,{schema:e,dataSource:n,...t})})});n.ComponentRegistry.register(`object-map`,O,{namespace:`plugin-map`,label:`Object Map`,category:`view`,inputs:[{name:`objectName`,type:`string`,description:"ObjectQL object name. The record source is one of `data`, `staticData` and `objectName`, or the node’s `dataSource` binding; the `object-map` schema refuses a block that declares none of them."},{name:`map`,type:`object`,description:'The field configuration: `latitudeField` / `longitudeField` (or one `locationField` holding a `"lat,lng"` string, a `{ lat, lng }` object or a `[lat, lng]` pair) place each record’s marker, and a record with no readable coordinates is not plotted; `titleField` and `descriptionField` name what the marker popup shows; `zoom` and `center` (`[latitude, longitude]`) set the initial camera, which otherwise fits the markers; `style` is a MapLibre style URL, read after the node’s `mapStyle`.'},{name:`data`,type:`object`,description:"A `{ provider, … }` data-source configuration, read FIRST on the record-source ladder: a map carrying one never reaches `staticData` and never queries `objectName`. `{ provider: 'value', items }` plots those rows and `{ provider: 'object', object }` queries that object, both narrowed by `filter` and ordered by `sort`. A bare array is not this key’s shape and is not a record source: the map falls through to `staticData`, then `objectName`, so inline rows belong under `staticData`."},{name:`staticData`,type:`array`,description:"Inline records, read SECOND on the record-source ladder: a `data` configuration wins and this key is then never reached, while `objectName` is read AFTER it, so a map carrying both plots these rows and never queries that object. `filter` and `sort` narrow and order these rows exactly as they do fetched ones."},{name:`filter`,type:`array`,description:"Base query filter in the rule-array form `[{ field, operator, value }, ...]`, narrowing the markers the map plots — fetched rows and inline (`staticData`, `{ provider: 'value' }`) rows alike. Context tokens such as `{current_user_id}` are resolved first, then the filter is lowered to `$filter` on the query. The MongoDB-style record form is not this key’s shape."},{name:`sort`,type:`array`,description:"Marker order in `[{ field, order }]` form, ordering the rows the map plots. Lowered to `$orderby` on the same query."},{name:`mapStyle`,type:`string`,description:"MapLibre style URL or spec, overriding the public demo tiles. Read before `map.style`; NOT the base node `style`, which is an inline CSS record"},{name:`navigation`,type:`object`,description:"What a marker click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the marker’s record in that overlay, but `split` opens nothing, because the map hands the split shell no main panel; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of the map’s `objectName` through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a map that names no `objectName`, there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. A click handler from a parent view outranks the whole key."},{name:`enableClustering`,type:`boolean`,description:"Group nearby markers into one numbered cluster. Absent, the map clusters only above 100 markers; `false` turns clustering off at any count."}]}),e.ObjectMap=E,e.ObjectMapRenderer=O});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-map",
3
- "version": "17.7.0",
3
+ "version": "18.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Map visualization plugin for Object UI",
@@ -26,11 +26,11 @@
26
26
  "dependencies": {
27
27
  "maplibre-gl": "^6.4.1",
28
28
  "react-map-gl": "^8.1.2",
29
- "@object-ui/components": "17.7.0",
30
- "@object-ui/core": "17.7.0",
31
- "@object-ui/permissions": "17.7.0",
32
- "@object-ui/react": "17.7.0",
33
- "@object-ui/types": "17.7.0"
29
+ "@object-ui/components": "18.0.0",
30
+ "@object-ui/core": "18.0.0",
31
+ "@object-ui/permissions": "18.0.0",
32
+ "@object-ui/react": "18.0.0",
33
+ "@object-ui/types": "18.0.0"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "react": "^18.0.0 || ^19.0.0",
@@ -43,8 +43,8 @@
43
43
  "typescript": "^6.0.3",
44
44
  "vite": "^8.2.1",
45
45
  "vite-plugin-dts": "^5.0.3",
46
- "@object-ui/plugin-list": "17.7.0",
47
- "@object-ui/sdui-parser": "17.7.0"
46
+ "@object-ui/plugin-list": "18.0.0",
47
+ "@object-ui/sdui-parser": "18.0.0"
48
48
  },
49
49
  "keywords": [
50
50
  "objectui",