@object-ui/plugin-map 17.3.0 → 17.5.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 +204 -0
- package/README.md +0 -11
- package/dist/ObjectMap.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +146 -116
- package/dist/index.umd.cjs +1 -1
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,206 @@
|
|
|
1
1
|
# @object-ui/plugin-map
|
|
2
2
|
|
|
3
|
+
## 17.5.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d0c3b26: Every plain `<button>` now declares its `type`. HTML defaults an untyped button to
|
|
8
|
+
`type="submit"`, so any of these buttons would submit the form it was composed into
|
|
9
|
+
instead of running its own handler — a real risk for renderers (`drawer`, `tree-view`,
|
|
10
|
+
`navigation-overlay`) whose placement inside a form is a JSON metadata decision. 114
|
|
11
|
+
sites were converted to `type="button"`; no site was a genuine submit button, and the
|
|
12
|
+
DOM is otherwise unchanged.
|
|
13
|
+
|
|
14
|
+
The defect class is now closed mechanically by a new `object-ui/button-has-type` ESLint
|
|
15
|
+
rule (error), so the next untyped button fails CI at write time rather than being found
|
|
16
|
+
by a fourth audit round (objectui#4045, closing the objectui#3344 family).
|
|
17
|
+
|
|
18
|
+
- b388d0e: `object-map` reads its configuration from the declared `map` input only — `filter` is the query filter, and a map authored with both stopped rendering markers
|
|
19
|
+
|
|
20
|
+
`getMapConfig` probed every filter for a `map` key and, on a hit, used it as the MapConfig: `schema.filter.map`, plus a `schema.filter.map.style` half in the style chain. That shape predates the `{ name: 'map', type: 'object' }` input both registrations declare, and it gave `filter` two meanings inside one block — the query filter at `$filter: schema.filter`, and a configuration slot.
|
|
21
|
+
|
|
22
|
+
The probe was written as `'map' in schema.filter`, and `in` walks the prototype chain. The ordinary filter is an **array**, and every array inherits `Array.prototype.map` — so the probe matched, handed the component a _function_ as its map configuration, and the spread of a function is `{}`. The declared `schema.map` was never reached (it sat in the `else` branch), so a map authored with both `map` and `filter` — two documented inputs, no legacy shape required — lost `latitudeField` / `longitudeField` / `titleField`, failed `extractCoordinates` on every record, and rendered zero markers under a "N records with missing or invalid coordinates excluded from the map" banner. The only console output was `[ObjectMap] Invalid map configuration:` from the Zod parse of a function.
|
|
23
|
+
|
|
24
|
+
This was reachable two ways and both are fixed by the same deletion: an author writing `filter` alongside `map`, and the `dataSource` binding of objectstack#7121, whose merged filter is an `and` node — `['and', [...], [...]]`, still an array, still carrying `Array.prototype.map`.
|
|
25
|
+
|
|
26
|
+
Both legacy reads are gone; the map consumes only what it declares. The `map` config, the top-level `locationField` / `latitudeField` branch, and the `style` / `mapStyle` reads are untouched, and `filter` is passed to the query verbatim — a field genuinely named `map` still filters on it, and nothing is stripped from the author's filter.
|
|
27
|
+
|
|
28
|
+
A schema still carrying the legacy `filter.map` stash now gets a dev-mode warning naming the shape and pointing at `schema.map`, rather than silently falling back to the default field names. It is deliberately narrow: own properties only (so an inherited `map` method never triggers it) and object-valued only (so `filter: { map: 'x' }` reads as a filter on a field named `map`), and it warns once per distinct stash because `getMapConfig` runs on every render. Production behavior is unchanged beyond the configuration no longer being read.
|
|
29
|
+
|
|
30
|
+
- Updated dependencies [ceccdcf]
|
|
31
|
+
- Updated dependencies [d6e5124]
|
|
32
|
+
- Updated dependencies [debad27]
|
|
33
|
+
- Updated dependencies [dc2aa3e]
|
|
34
|
+
- Updated dependencies [ee66e2e]
|
|
35
|
+
- Updated dependencies [ee26e65]
|
|
36
|
+
- Updated dependencies [5900ac5]
|
|
37
|
+
- Updated dependencies [f650253]
|
|
38
|
+
- Updated dependencies [3d9769a]
|
|
39
|
+
- Updated dependencies [8f85f8b]
|
|
40
|
+
- Updated dependencies [d0c3b26]
|
|
41
|
+
- Updated dependencies [3fc2971]
|
|
42
|
+
- Updated dependencies [aca27fa]
|
|
43
|
+
- Updated dependencies [dde7283]
|
|
44
|
+
- Updated dependencies [4dadf0d]
|
|
45
|
+
- Updated dependencies [ae10a01]
|
|
46
|
+
- Updated dependencies [92876f0]
|
|
47
|
+
- Updated dependencies [f279deb]
|
|
48
|
+
- Updated dependencies [4b70d28]
|
|
49
|
+
- Updated dependencies [eb7f586]
|
|
50
|
+
- Updated dependencies [e901131]
|
|
51
|
+
- Updated dependencies [d9d3463]
|
|
52
|
+
- Updated dependencies [2a40f69]
|
|
53
|
+
- Updated dependencies [bec3e14]
|
|
54
|
+
- Updated dependencies [613b167]
|
|
55
|
+
- Updated dependencies [b4d3c22]
|
|
56
|
+
- Updated dependencies [1f9b905]
|
|
57
|
+
- Updated dependencies [cb13400]
|
|
58
|
+
- Updated dependencies [bc64bfe]
|
|
59
|
+
- Updated dependencies [abb0f81]
|
|
60
|
+
- Updated dependencies [38ab505]
|
|
61
|
+
- Updated dependencies [3e19fe7]
|
|
62
|
+
- Updated dependencies [b953a97]
|
|
63
|
+
- Updated dependencies [d7f3e30]
|
|
64
|
+
- Updated dependencies [7e4f0e5]
|
|
65
|
+
- Updated dependencies [a84385b]
|
|
66
|
+
- Updated dependencies [45e1949]
|
|
67
|
+
- Updated dependencies [92250d6]
|
|
68
|
+
- Updated dependencies [c1d939f]
|
|
69
|
+
- Updated dependencies [49ae9f4]
|
|
70
|
+
- Updated dependencies [a3ae404]
|
|
71
|
+
- Updated dependencies [bfdf3d4]
|
|
72
|
+
- Updated dependencies [bb68488]
|
|
73
|
+
- Updated dependencies [b1e42d0]
|
|
74
|
+
- Updated dependencies [2459a3e]
|
|
75
|
+
- Updated dependencies [d6aa172]
|
|
76
|
+
- Updated dependencies [fe52a04]
|
|
77
|
+
- Updated dependencies [3f5f87c]
|
|
78
|
+
- Updated dependencies [f5e1143]
|
|
79
|
+
- Updated dependencies [f148a64]
|
|
80
|
+
- Updated dependencies [bb68488]
|
|
81
|
+
- Updated dependencies [9461dd3]
|
|
82
|
+
- Updated dependencies [47f551b]
|
|
83
|
+
- Updated dependencies [ab04728]
|
|
84
|
+
- Updated dependencies [5bf09fd]
|
|
85
|
+
- @object-ui/react@17.5.0
|
|
86
|
+
- @object-ui/components@17.5.0
|
|
87
|
+
- @object-ui/core@17.5.0
|
|
88
|
+
- @object-ui/types@17.5.0
|
|
89
|
+
|
|
90
|
+
## 17.4.0
|
|
91
|
+
|
|
92
|
+
### Patch Changes
|
|
93
|
+
|
|
94
|
+
- 022002a: `PageComponentSchema.dataSource` now reaches the remaining object-bound public
|
|
95
|
+
blocks: `object-gantt` / `object-timeline` / `object-map` / `object-pivot` /
|
|
96
|
+
`object-master-detail-form` / `embeddable-form` / `record:line_items`
|
|
97
|
+
(objectstack#7121).
|
|
98
|
+
|
|
99
|
+
objectstack#6953 wired the spec's per-element data binding
|
|
100
|
+
(`dataSource: { object, view?, filter?, sort?, limit? }`) to the eight blocks it
|
|
101
|
+
named and left the same declaration inert on these seven. Each gates its fetch on
|
|
102
|
+
its own object key and nothing mapped `dataSource.object` onto it, so a page
|
|
103
|
+
written the way the spec documents rendered an empty gantt / an empty timeline
|
|
104
|
+
rail / a map with no markers / an empty cross-tab / a field-less form — with no
|
|
105
|
+
request and no diagnostic anywhere. Spec-valid metadata rendering nothing is the
|
|
106
|
+
objectstack#4413 shape.
|
|
107
|
+
|
|
108
|
+
Composition follows objectstack#5576's landed semantics unchanged, through the
|
|
109
|
+
shared `ElementDataSourceGate` (no change to it or to the resolution layer): a
|
|
110
|
+
named saved view supplies the baseline, a key written on the component itself
|
|
111
|
+
overrides it, an explicit binding key overrides both, `filter` AND-combines
|
|
112
|
+
("additional filter criteria" — a binding can narrow a view, never widen it), and
|
|
113
|
+
a `view` name that does not resolve renders a configuration error on every one of
|
|
114
|
+
these blocks instead of degrading to the object's full scope.
|
|
115
|
+
|
|
116
|
+
Each block maps **only** the keys it genuinely reads, which for this batch means
|
|
117
|
+
several keys stay deliberately unmapped rather than being parked somewhere
|
|
118
|
+
plausible:
|
|
119
|
+
|
|
120
|
+
- `object-gantt` and `object-map` take `object` / `filter` / `sort`; neither has a
|
|
121
|
+
row cap or a field-list read site.
|
|
122
|
+
- `object-pivot` takes `object` / `filter`; a cross-tab orders itself by its own
|
|
123
|
+
row/column grouping and cannot be computed over a truncated page.
|
|
124
|
+
- `object-timeline` takes `object` only — its fetch is
|
|
125
|
+
`find(objectName, { options: { $top: 100 } })`, with no filter/sort read site
|
|
126
|
+
at all, so a named view is error-checked and then contributes nothing.
|
|
127
|
+
- `embeddable-form` and `object-master-detail-form` take `object` only (the
|
|
128
|
+
parent object, in the master-detail case); a form that writes one record has no
|
|
129
|
+
collection query for `filter` / `sort` / `limit` to narrow.
|
|
130
|
+
- `record:line_items` takes `object` onto **`childObject`** — the collection it
|
|
131
|
+
actually lists — and nothing else: its query is the parent FK plus a fixed
|
|
132
|
+
`$top: 500`, and its `columns` are editable `GridColumn` objects rather than a
|
|
133
|
+
field-name projection a view could supply.
|
|
134
|
+
|
|
135
|
+
The per-block coverage table, including every residual gap named above, is in
|
|
136
|
+
`content/docs/guide/data-source.md`.
|
|
137
|
+
|
|
138
|
+
No behaviour change for a block that carries no `dataSource`: the binding-free
|
|
139
|
+
path returns the schema by reference, so nothing remounts and nothing refetches.
|
|
140
|
+
|
|
141
|
+
- 9ad21b6: `plugin-map` 加载时不再向控制台打印 `Registering object-map...`
|
|
142
|
+
|
|
143
|
+
`packages/plugin-map/src/index.tsx` 的注册调用之前留着一句调试输出
|
|
144
|
+
`console.log('Registering object-map...')`。它位于**模块作用域**,所以不是「渲染地图时打一行」,
|
|
145
|
+
而是**只要这个 plugin 被 import 就打一行**:console 应用的 `register-plugins` 一加载即触发,
|
|
146
|
+
单元测试里跟着刷,生产 bundle 同样保留 —— 使用者控制台里凭空多出一行来源不明的噪音。
|
|
147
|
+
|
|
148
|
+
同仓其余 18 个 plugin 的 `src/index.tsx` 注册处都没有这类输出,这一句是孤例
|
|
149
|
+
(`plugin-editor` 里唯一的 `console.log` 命中是 `defaultProps.value` 示例代码字符串,
|
|
150
|
+
不是会执行的语句)。纯噪音,不涉及任何行为:注册本身、`ObjectMap` 的渲染与取数都不读它。
|
|
151
|
+
|
|
152
|
+
顺带记一条搜索时确认的背景:仓库的 eslint 配置没有开 `no-console` 规则,所以这类遗留
|
|
153
|
+
调试输出没有任何自动化拦网 —— 这次是靠人工发现的。是否全仓开 `no-console`(以及
|
|
154
|
+
`ObjectMap.tsx` 里三处**有意**保留的 `console.warn`/`console.error` 诊断如何豁免)是一个
|
|
155
|
+
影响多个包的策略决定,已另行开单,不混进本 PR。
|
|
156
|
+
|
|
157
|
+
回潮钉在 `src/index.registration.test.tsx`:spy 掉 `console.log`/`info`/`debug` 后
|
|
158
|
+
`vi.resetModules()` 再 `import('./index')`,断言零输出。钉子刻意只覆盖这三个「噪音通道」,
|
|
159
|
+
不含 `warn`/`error` —— `ComponentRegistry.register()` 在缺 namespace、以及裸名 fallback
|
|
160
|
+
覆盖冲突时**按设计**会 `console.warn`(`packages/core/src/registry/Registry.ts`),
|
|
161
|
+
一刀切断言「零 console 输出」等于把 Registry 的诊断契约钉在这里,将来会因与「遗留调试输出」
|
|
162
|
+
无关的原因变红。钉子里还有一条非空断言:import 后校验 `object-map`/`map` 两个注册确实进了
|
|
163
|
+
registry,免得模块缓存导致 import 未真正执行、于是「没有输出」是因为**什么都没发生**而假绿。
|
|
164
|
+
|
|
165
|
+
- Updated dependencies [794c497]
|
|
166
|
+
- Updated dependencies [993336f]
|
|
167
|
+
- Updated dependencies [f0a625a]
|
|
168
|
+
- Updated dependencies [b5980f4]
|
|
169
|
+
- Updated dependencies [8aad9fd]
|
|
170
|
+
- Updated dependencies [6719877]
|
|
171
|
+
- Updated dependencies [56ff091]
|
|
172
|
+
- Updated dependencies [0cbdca8]
|
|
173
|
+
- Updated dependencies [d229dfa]
|
|
174
|
+
- Updated dependencies [ecae400]
|
|
175
|
+
- Updated dependencies [4bc6c23]
|
|
176
|
+
- Updated dependencies [d3e738a]
|
|
177
|
+
- Updated dependencies [c3b01a7]
|
|
178
|
+
- Updated dependencies [7ed3360]
|
|
179
|
+
- Updated dependencies [0fa5e4d]
|
|
180
|
+
- Updated dependencies [5bfaabd]
|
|
181
|
+
- Updated dependencies [e06810e]
|
|
182
|
+
- Updated dependencies [ab3ad4f]
|
|
183
|
+
- Updated dependencies [c2fd122]
|
|
184
|
+
- Updated dependencies [e24d767]
|
|
185
|
+
- Updated dependencies [aca561a]
|
|
186
|
+
- Updated dependencies [48132f7]
|
|
187
|
+
- Updated dependencies [0ef9dfd]
|
|
188
|
+
- Updated dependencies [1d723e3]
|
|
189
|
+
- Updated dependencies [0109f54]
|
|
190
|
+
- Updated dependencies [7e5bb5d]
|
|
191
|
+
- Updated dependencies [fbc23e0]
|
|
192
|
+
- Updated dependencies [e6fdbdc]
|
|
193
|
+
- Updated dependencies [54233b1]
|
|
194
|
+
- Updated dependencies [97b63d7]
|
|
195
|
+
- Updated dependencies [6bb454a]
|
|
196
|
+
- Updated dependencies [523be48]
|
|
197
|
+
- Updated dependencies [7e2b7e9]
|
|
198
|
+
- Updated dependencies [c1e1e6b]
|
|
199
|
+
- @object-ui/components@17.4.0
|
|
200
|
+
- @object-ui/react@17.4.0
|
|
201
|
+
- @object-ui/core@17.4.0
|
|
202
|
+
- @object-ui/types@17.4.0
|
|
203
|
+
|
|
3
204
|
## 17.3.0
|
|
4
205
|
|
|
5
206
|
### Patch Changes
|
|
@@ -1001,6 +1202,7 @@
|
|
|
1001
1202
|
Library builds (vite lib mode) now externalize every non-relative import instead of bundling third-party CJS dependencies into the published dist. This avoids inlined `require("react")` / `require("react-dom")` calls that cause `Calling \`require\` for "react" in an environment that doesn't expose the \`require\` function` runtime errors when consumer apps re-bundle the published dist.
|
|
1002
1203
|
|
|
1003
1204
|
Specifically fixes:
|
|
1205
|
+
|
|
1004
1206
|
- `@object-ui/plugin-dashboard` no longer inlines `react-grid-layout` (and its transitive `react-draggable` / `react-resizable` CJS bundles). `react-grid-layout` is now declared as a peer dependency so consumers install a single ESM-friendly copy.
|
|
1005
1207
|
- `@object-ui/components`, `@object-ui/plugin-calendar`, `@object-ui/plugin-charts`, `@object-ui/plugin-designer` no longer inline `react-i18next` / `i18next` / `use-sync-external-store` CJS shims.
|
|
1006
1208
|
- All plugin packages now use a unified `external: (id) => !/^[./]/.test(id) && !id.startsWith(__dirname)` rule, ensuring future additions of CJS deps are automatically externalized.
|
|
@@ -1055,11 +1257,13 @@
|
|
|
1055
1257
|
- e93fe35: Mobile UX round 3 — Gantt and Map
|
|
1056
1258
|
|
|
1057
1259
|
**@object-ui/plugin-gantt**
|
|
1260
|
+
|
|
1058
1261
|
- Added a sticky vertical "Today" marker on the timeline plus a one-tap **Jump to Today** toolbar button so on-call users can re-orient the view instantly on small screens.
|
|
1059
1262
|
- Added a **collapsible task list** (toolbar toggle + auto-collapse on the first narrow render) so the timeline area gets the full viewport on phones.
|
|
1060
1263
|
- Added **pinch-to-zoom** touch gestures on the timeline; wired `columnWidthOverride` state so the existing zoom buttons also respond (previously a no-op).
|
|
1061
1264
|
|
|
1062
1265
|
**@object-ui/plugin-map**
|
|
1266
|
+
|
|
1063
1267
|
- Added a **geolocate button** with the standard `navigator.geolocation.getCurrentPosition` permission flow, an inline error banner, a busy state, and a **user-location marker** (blue dot) the map flies to on success.
|
|
1064
1268
|
- **Cluster tap-through**: tapping a cluster now flies the map in (zoom + 2, capped at 20) instead of just sitting there.
|
|
1065
1269
|
- On mobile, the desktop popup is replaced by a **bottom-sheet record card** with safe-area padding and an explicit close button. Desktop continues to use the popup.
|
package/README.md
CHANGED
|
@@ -271,17 +271,6 @@ const schema = {
|
|
|
271
271
|
};
|
|
272
272
|
```
|
|
273
273
|
|
|
274
|
-
<!-- release-metadata:v3.3.0 -->
|
|
275
|
-
|
|
276
|
-
## Compatibility
|
|
277
|
-
|
|
278
|
-
- **React:** 18.x or 19.x
|
|
279
|
-
- **Node.js:** ≥ 18
|
|
280
|
-
- **TypeScript:** ≥ 5.0 (strict mode)
|
|
281
|
-
- **`@objectstack/spec`:** ^3.3.0
|
|
282
|
-
- **`@objectstack/client`:** ^3.3.0
|
|
283
|
-
- **Tailwind CSS:** ≥ 3.4 (for packages with UI)
|
|
284
|
-
|
|
285
274
|
## Links
|
|
286
275
|
|
|
287
276
|
- 📚 [Documentation](https://www.objectui.org/docs/plugins/plugin-map)
|
package/dist/ObjectMap.d.ts.map
CHANGED
|
@@ -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,gBAAgB,EAAE,UAAU,EAAY,MAAM,kBAAkB,CAAC;AAO/E,OAAO,kCAAkC,CAAC;AAqB1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,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,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;
|
|
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,gBAAgB,EAAE,UAAU,EAAY,MAAM,kBAAkB,CAAC;AAO/E,OAAO,kCAAkC,CAAC;AAqB1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,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,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AA+SD,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA4d9C,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
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,CAgB3C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
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, buildExpandFields as o, extractRecords as s } from "@object-ui/core";
|
|
3
|
-
import { useNavigationOverlay as
|
|
4
|
-
import { NavigationOverlay as
|
|
5
|
-
import { z as
|
|
6
|
-
import
|
|
3
|
+
import { ElementDataSourceGate as c, useNavigationOverlay as l, useSchemaContext as u } from "@object-ui/react";
|
|
4
|
+
import { NavigationOverlay as ee, cn as d, useIsMobile as f } from "@object-ui/components";
|
|
5
|
+
import { z as p } from "zod";
|
|
6
|
+
import te, { Marker as m, NavigationControl as h, Popup as ne } from "react-map-gl/maplibre";
|
|
7
7
|
import "maplibre-gl/dist/maplibre-gl.css";
|
|
8
|
-
import { jsx as
|
|
8
|
+
import { jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
9
9
|
//#region src/ObjectMap.tsx
|
|
10
|
-
var
|
|
11
|
-
latitudeField:
|
|
12
|
-
longitudeField:
|
|
13
|
-
locationField:
|
|
14
|
-
titleField:
|
|
15
|
-
descriptionField:
|
|
16
|
-
zoom:
|
|
17
|
-
center:
|
|
18
|
-
style:
|
|
19
|
-
}),
|
|
20
|
-
function
|
|
10
|
+
var v = p.object({
|
|
11
|
+
latitudeField: p.string().optional(),
|
|
12
|
+
longitudeField: p.string().optional(),
|
|
13
|
+
locationField: p.string().optional(),
|
|
14
|
+
titleField: p.string().optional(),
|
|
15
|
+
descriptionField: p.string().optional(),
|
|
16
|
+
zoom: p.number().optional(),
|
|
17
|
+
center: p.tuple([p.number(), p.number()]).optional(),
|
|
18
|
+
style: p.string().optional()
|
|
19
|
+
}), re = "https://demotiles.maplibre.org/style.json";
|
|
20
|
+
function ie(e) {
|
|
21
21
|
return e.data ? e.data : e.staticData ? {
|
|
22
22
|
provider: "value",
|
|
23
23
|
items: e.staticData
|
|
@@ -26,7 +26,7 @@ function g(e) {
|
|
|
26
26
|
object: e.objectName
|
|
27
27
|
} : null;
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function y(e) {
|
|
30
30
|
if (e) {
|
|
31
31
|
if (typeof e == "string") {
|
|
32
32
|
let t = e.split(" "), n = t[0], r = t[1]?.toLowerCase() === "desc" ? "desc" : "asc";
|
|
@@ -35,8 +35,24 @@ function oe(e) {
|
|
|
35
35
|
if (Array.isArray(e)) return e.reduce((e, t) => (t.field && t.order && (e[t.field] = t.order), e), {});
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
var b = () => globalThis.process?.env?.NODE_ENV !== "production", x = /* @__PURE__ */ new Set();
|
|
39
|
+
function S(e) {
|
|
40
|
+
if (!b()) return;
|
|
41
|
+
let t = e?.filter;
|
|
42
|
+
if (!t || typeof t != "object" || Array.isArray(t) || !Object.prototype.hasOwnProperty.call(t, "map")) return;
|
|
43
|
+
let n = t.map;
|
|
44
|
+
if (!n || typeof n != "object") return;
|
|
45
|
+
let r;
|
|
46
|
+
try {
|
|
47
|
+
r = `${e.type ?? "map"}::${e.objectName ?? ""}::${JSON.stringify(n)}`;
|
|
48
|
+
} catch {
|
|
49
|
+
r = `${e.type ?? "map"}::${e.objectName ?? ""}::<unserializable>`;
|
|
50
|
+
}
|
|
51
|
+
x.has(r) || (x.add(r), console.warn("[ObjectMap] `filter.map` is no longer read as map configuration, so this map is rendering with the DEFAULT field names (`latitude` / `longitude` / `name`). `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."));
|
|
52
|
+
}
|
|
53
|
+
function C(e) {
|
|
54
|
+
S(e);
|
|
55
|
+
let t = e.style || e.mapStyle || e.map?.style;
|
|
40
56
|
if (e.locationField || e.latitudeField) return {
|
|
41
57
|
locationField: e.locationField,
|
|
42
58
|
latitudeField: e.latitudeField,
|
|
@@ -47,9 +63,9 @@ function _(e) {
|
|
|
47
63
|
center: e.center,
|
|
48
64
|
style: t
|
|
49
65
|
};
|
|
50
|
-
let n = null;
|
|
51
|
-
if (
|
|
52
|
-
let e =
|
|
66
|
+
let n = e.map ? e.map : null;
|
|
67
|
+
if (n) {
|
|
68
|
+
let e = v.safeParse(n);
|
|
53
69
|
return e.success || console.warn("[ObjectMap] Invalid map configuration:", e.error.format()), {
|
|
54
70
|
...n,
|
|
55
71
|
style: n.style || t
|
|
@@ -66,7 +82,7 @@ function _(e) {
|
|
|
66
82
|
style: t
|
|
67
83
|
};
|
|
68
84
|
}
|
|
69
|
-
function
|
|
85
|
+
function ae(e, t) {
|
|
70
86
|
if (t.latitudeField && t.longitudeField) {
|
|
71
87
|
let n = e[t.latitudeField], r = e[t.longitudeField];
|
|
72
88
|
if (typeof n == "number" && typeof r == "number") return [n, r];
|
|
@@ -88,7 +104,7 @@ function v(e, t) {
|
|
|
88
104
|
}
|
|
89
105
|
return null;
|
|
90
106
|
}
|
|
91
|
-
function
|
|
107
|
+
function oe(e, t, n = 50) {
|
|
92
108
|
if (e.length <= 1 || t >= 15) return e.map((e) => ({
|
|
93
109
|
id: e.id,
|
|
94
110
|
coordinates: e.coordinates,
|
|
@@ -119,8 +135,8 @@ function se(e, t, n = 50) {
|
|
|
119
135
|
}
|
|
120
136
|
}), a;
|
|
121
137
|
}
|
|
122
|
-
var
|
|
123
|
-
let [
|
|
138
|
+
var w = ({ schema: a, dataSource: c, className: u, onMarkerClick: p, onRowClick: v, onEdit: b, onDelete: x, enableClustering: S, clusterRadius: w = 50, ...T }) => {
|
|
139
|
+
let [E, D] = i([]), [se, O] = i(!0), [k, A] = i(null), [j, M] = i(null), [N, P] = i(null), [F, ce] = i(""), I = f(), L = r(null), [R, le] = i(null), [z, B] = i(null), [V, H] = i(!1), [U, ue] = i(null), de = e((e) => {
|
|
124
140
|
ue(e?.error?.message || "Failed to load the map style/tiles.");
|
|
125
141
|
}, []), fe = e(() => {
|
|
126
142
|
if (typeof navigator > "u" || !navigator.geolocation) {
|
|
@@ -129,12 +145,12 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
129
145
|
}
|
|
130
146
|
H(!0), B(null), navigator.geolocation.getCurrentPosition((e) => {
|
|
131
147
|
let { longitude: t, latitude: n } = e.coords;
|
|
132
|
-
|
|
148
|
+
le({
|
|
133
149
|
lng: t,
|
|
134
150
|
lat: n
|
|
135
151
|
}), H(!1);
|
|
136
152
|
try {
|
|
137
|
-
|
|
153
|
+
L.current?.flyTo({
|
|
138
154
|
center: [t, n],
|
|
139
155
|
zoom: 12,
|
|
140
156
|
duration: 800
|
|
@@ -147,40 +163,40 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
147
163
|
timeout: 8e3,
|
|
148
164
|
maximumAge: 6e4
|
|
149
165
|
});
|
|
150
|
-
}, []), W =
|
|
166
|
+
}, []), W = ie(a), G = n(() => W, [JSON.stringify(W)]), K = C(a), q = G?.provider === "value";
|
|
151
167
|
t(() => {
|
|
152
168
|
(async () => {
|
|
153
169
|
try {
|
|
154
|
-
if (
|
|
155
|
-
let e =
|
|
170
|
+
if (O(!0), T.data) {
|
|
171
|
+
let e = T.data;
|
|
156
172
|
if (Array.isArray(e)) {
|
|
157
|
-
|
|
173
|
+
D(e), O(!1);
|
|
158
174
|
return;
|
|
159
175
|
}
|
|
160
176
|
}
|
|
161
177
|
if (a.data) {
|
|
162
178
|
let e = a.data;
|
|
163
179
|
if (Array.isArray(e)) {
|
|
164
|
-
|
|
180
|
+
D(e), O(!1);
|
|
165
181
|
return;
|
|
166
182
|
}
|
|
167
183
|
}
|
|
168
184
|
if (q && G?.provider === "value") {
|
|
169
|
-
|
|
185
|
+
D(G.items), O(!1);
|
|
170
186
|
return;
|
|
171
187
|
}
|
|
172
188
|
if (!c || typeof c.find != "function") throw Error("DataSource required for object/api providers");
|
|
173
189
|
if (G?.provider === "object") {
|
|
174
|
-
let e = G.object, t = o(
|
|
190
|
+
let e = G.object, t = o(j?.fields), n = await c.find(e, {
|
|
175
191
|
$filter: a.filter,
|
|
176
|
-
$orderby:
|
|
192
|
+
$orderby: y(a.sort),
|
|
177
193
|
...t.length > 0 ? { $expand: t } : {}
|
|
178
194
|
}), r = s(n);
|
|
179
|
-
|
|
180
|
-
} else G?.provider === "api" && (console.warn("API provider not yet implemented for ObjectMap"),
|
|
181
|
-
|
|
195
|
+
D(r);
|
|
196
|
+
} else G?.provider === "api" && (console.warn("API provider not yet implemented for ObjectMap"), D([]));
|
|
197
|
+
O(!1);
|
|
182
198
|
} catch (e) {
|
|
183
|
-
|
|
199
|
+
A(e), O(!1);
|
|
184
200
|
}
|
|
185
201
|
})();
|
|
186
202
|
}, [
|
|
@@ -189,7 +205,7 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
189
205
|
q,
|
|
190
206
|
a.filter,
|
|
191
207
|
a.sort,
|
|
192
|
-
|
|
208
|
+
j
|
|
193
209
|
]), t(() => {
|
|
194
210
|
!q && c && (async () => {
|
|
195
211
|
try {
|
|
@@ -197,7 +213,7 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
197
213
|
let e = G?.provider === "object" ? G.object : a.objectName;
|
|
198
214
|
if (!e) return;
|
|
199
215
|
let t = await c.getObjectSchema(e);
|
|
200
|
-
|
|
216
|
+
M(t);
|
|
201
217
|
} catch (e) {
|
|
202
218
|
console.error("Failed to fetch object schema:", e);
|
|
203
219
|
}
|
|
@@ -211,8 +227,8 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
211
227
|
let { markers: J, invalidCount: Y } = n(() => {
|
|
212
228
|
let e = 0;
|
|
213
229
|
return {
|
|
214
|
-
markers:
|
|
215
|
-
let r =
|
|
230
|
+
markers: E.map((t, n) => {
|
|
231
|
+
let r = ae(t, K);
|
|
216
232
|
if (!r) return e++, null;
|
|
217
233
|
let i = K.titleField ? t[K.titleField] : "Marker", a = K.descriptionField ? t[K.descriptionField] : void 0, [o, s] = r;
|
|
218
234
|
return !isFinite(o) || !isFinite(s) || o < -90 || o > 90 || s < -180 || s > 180 ? (e++, null) : {
|
|
@@ -225,15 +241,15 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
225
241
|
}).filter((e) => e !== null),
|
|
226
242
|
invalidCount: e
|
|
227
243
|
};
|
|
228
|
-
}, [
|
|
244
|
+
}, [E, K]), X = n(() => J.find((e) => e.id === N), [J, N]), [Z, pe] = i(K.zoom || 3), Q = l({
|
|
229
245
|
navigation: a.navigation,
|
|
230
246
|
objectName: a.objectName,
|
|
231
|
-
onRowClick:
|
|
247
|
+
onRowClick: v
|
|
232
248
|
}), $ = n(() => {
|
|
233
|
-
if (!
|
|
234
|
-
let e =
|
|
249
|
+
if (!F.trim()) return J;
|
|
250
|
+
let e = F.toLowerCase();
|
|
235
251
|
return J.filter((t) => t.title?.toLowerCase().includes(e) || t.description?.toLowerCase().includes(e));
|
|
236
|
-
}, [J,
|
|
252
|
+
}, [J, F]), me = n(() => S ?? (a.enableClustering || $.length > 100) ? oe($, Z, w) : $.map((e) => ({
|
|
237
253
|
id: e.id,
|
|
238
254
|
coordinates: e.coordinates,
|
|
239
255
|
markers: [e],
|
|
@@ -242,7 +258,7 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
242
258
|
$,
|
|
243
259
|
Z,
|
|
244
260
|
S,
|
|
245
|
-
|
|
261
|
+
w,
|
|
246
262
|
a
|
|
247
263
|
]), he = n(() => {
|
|
248
264
|
if (!$.length) return {
|
|
@@ -257,61 +273,61 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
257
273
|
zoom: K.zoom || 3
|
|
258
274
|
};
|
|
259
275
|
}, [$, K]);
|
|
260
|
-
return
|
|
261
|
-
className:
|
|
262
|
-
children: /* @__PURE__ */
|
|
276
|
+
return se ? /* @__PURE__ */ g("div", {
|
|
277
|
+
className: d("min-w-0 overflow-hidden", u),
|
|
278
|
+
children: /* @__PURE__ */ g("div", {
|
|
263
279
|
className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
|
|
264
|
-
children: /* @__PURE__ */
|
|
280
|
+
children: /* @__PURE__ */ g("div", {
|
|
265
281
|
className: "text-muted-foreground",
|
|
266
282
|
children: "Loading map..."
|
|
267
283
|
})
|
|
268
284
|
})
|
|
269
|
-
}) :
|
|
270
|
-
className:
|
|
271
|
-
children: /* @__PURE__ */
|
|
285
|
+
}) : k ? /* @__PURE__ */ g("div", {
|
|
286
|
+
className: d("min-w-0 overflow-hidden", u),
|
|
287
|
+
children: /* @__PURE__ */ g("div", {
|
|
272
288
|
className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
|
|
273
|
-
children: /* @__PURE__ */
|
|
289
|
+
children: /* @__PURE__ */ _("div", {
|
|
274
290
|
className: "text-destructive",
|
|
275
|
-
children: ["Error: ",
|
|
291
|
+
children: ["Error: ", k.message]
|
|
276
292
|
})
|
|
277
293
|
})
|
|
278
|
-
}) : /* @__PURE__ */
|
|
279
|
-
className:
|
|
294
|
+
}) : /* @__PURE__ */ _("div", {
|
|
295
|
+
className: d("min-w-0 overflow-hidden", u),
|
|
280
296
|
children: [
|
|
281
|
-
Y > 0 && /* @__PURE__ */
|
|
297
|
+
Y > 0 && /* @__PURE__ */ g("div", {
|
|
282
298
|
className: "mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded",
|
|
283
299
|
children: `${Y} record${Y === 1 ? "" : "s"} with missing or invalid coordinates excluded from the map.`
|
|
284
300
|
}),
|
|
285
|
-
J.length > 0 && /* @__PURE__ */
|
|
301
|
+
J.length > 0 && /* @__PURE__ */ g("div", {
|
|
286
302
|
className: "mb-2",
|
|
287
|
-
children: /* @__PURE__ */
|
|
303
|
+
children: /* @__PURE__ */ g("input", {
|
|
288
304
|
type: "text",
|
|
289
|
-
value:
|
|
290
|
-
onChange: (e) =>
|
|
305
|
+
value: F,
|
|
306
|
+
onChange: (e) => ce(e.target.value),
|
|
291
307
|
placeholder: "Search locations…",
|
|
292
308
|
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"
|
|
293
309
|
})
|
|
294
310
|
}),
|
|
295
|
-
/* @__PURE__ */
|
|
311
|
+
/* @__PURE__ */ _("div", {
|
|
296
312
|
className: "relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full",
|
|
297
313
|
children: [
|
|
298
|
-
/* @__PURE__ */
|
|
314
|
+
/* @__PURE__ */ _(te, {
|
|
299
315
|
ref: (e) => {
|
|
300
|
-
|
|
316
|
+
L.current = e;
|
|
301
317
|
},
|
|
302
318
|
initialViewState: he,
|
|
303
319
|
style: {
|
|
304
320
|
width: "100%",
|
|
305
321
|
height: "100%"
|
|
306
322
|
},
|
|
307
|
-
mapStyle: K.style ||
|
|
323
|
+
mapStyle: K.style || re,
|
|
308
324
|
touchZoomRotate: !0,
|
|
309
325
|
dragRotate: !0,
|
|
310
326
|
touchPitch: !0,
|
|
311
327
|
onZoom: (e) => pe(Math.round(e.viewState.zoom)),
|
|
312
328
|
onError: de,
|
|
313
329
|
children: [
|
|
314
|
-
U && /* @__PURE__ */
|
|
330
|
+
U && /* @__PURE__ */ _("div", {
|
|
315
331
|
role: "alert",
|
|
316
332
|
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",
|
|
317
333
|
children: [
|
|
@@ -322,34 +338,34 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
322
338
|
K.style ? "check the configured map style URL." : "configure a custom map style for production use."
|
|
323
339
|
]
|
|
324
340
|
}),
|
|
325
|
-
/* @__PURE__ */
|
|
341
|
+
/* @__PURE__ */ g(h, {
|
|
326
342
|
position: "top-right",
|
|
327
343
|
showCompass: !0,
|
|
328
344
|
showZoom: !0
|
|
329
345
|
}),
|
|
330
|
-
/* @__PURE__ */
|
|
346
|
+
/* @__PURE__ */ g("button", {
|
|
331
347
|
type: "button",
|
|
332
348
|
onClick: fe,
|
|
333
349
|
disabled: V,
|
|
334
350
|
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",
|
|
335
351
|
"aria-label": "Show my location",
|
|
336
352
|
"data-testid": "map-geolocate",
|
|
337
|
-
children: /* @__PURE__ */
|
|
353
|
+
children: /* @__PURE__ */ g("span", {
|
|
338
354
|
"aria-hidden": "true",
|
|
339
355
|
children: V ? "⏳" : "🧭"
|
|
340
356
|
})
|
|
341
357
|
}),
|
|
342
|
-
|
|
343
|
-
longitude:
|
|
344
|
-
latitude:
|
|
358
|
+
R && /* @__PURE__ */ g(m, {
|
|
359
|
+
longitude: R.lng,
|
|
360
|
+
latitude: R.lat,
|
|
345
361
|
anchor: "center",
|
|
346
|
-
children: /* @__PURE__ */
|
|
362
|
+
children: /* @__PURE__ */ g("div", {
|
|
347
363
|
className: "size-3 rounded-full bg-blue-500 ring-4 ring-blue-500/30 shadow",
|
|
348
364
|
"aria-label": "Your location",
|
|
349
365
|
"data-testid": "map-user-location"
|
|
350
366
|
})
|
|
351
367
|
}),
|
|
352
|
-
me.map((e) => e.isCluster ? /* @__PURE__ */
|
|
368
|
+
me.map((e) => e.isCluster ? /* @__PURE__ */ g(m, {
|
|
353
369
|
longitude: e.coordinates[0],
|
|
354
370
|
latitude: e.coordinates[1],
|
|
355
371
|
anchor: "center",
|
|
@@ -357,14 +373,14 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
357
373
|
t.originalEvent.stopPropagation();
|
|
358
374
|
try {
|
|
359
375
|
let t = Math.min(20, Math.max(Z + 2, 8));
|
|
360
|
-
|
|
376
|
+
L.current?.flyTo({
|
|
361
377
|
center: [e.coordinates[0], e.coordinates[1]],
|
|
362
378
|
zoom: t,
|
|
363
379
|
duration: 600
|
|
364
380
|
});
|
|
365
381
|
} catch {}
|
|
366
382
|
},
|
|
367
|
-
children: /* @__PURE__ */
|
|
383
|
+
children: /* @__PURE__ */ g("div", {
|
|
368
384
|
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",
|
|
369
385
|
style: {
|
|
370
386
|
width: Math.min(48, 24 + e.markers.length * 2),
|
|
@@ -374,44 +390,46 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
374
390
|
"data-testid": "map-cluster",
|
|
375
391
|
children: e.markers.length
|
|
376
392
|
})
|
|
377
|
-
}, e.id) : /* @__PURE__ */
|
|
393
|
+
}, e.id) : /* @__PURE__ */ g(m, {
|
|
378
394
|
longitude: e.coordinates[0],
|
|
379
395
|
latitude: e.coordinates[1],
|
|
380
396
|
anchor: "bottom",
|
|
381
397
|
onClick: (t) => {
|
|
382
398
|
t.originalEvent.stopPropagation();
|
|
383
399
|
let n = e.markers[0];
|
|
384
|
-
|
|
400
|
+
P(n.id), Q.handleClick(n.data), p?.(n.data);
|
|
385
401
|
},
|
|
386
|
-
children: /* @__PURE__ */
|
|
402
|
+
children: /* @__PURE__ */ g("div", {
|
|
387
403
|
className: "text-2xl cursor-pointer hover:scale-110 transition-transform",
|
|
388
404
|
children: "📍"
|
|
389
405
|
})
|
|
390
406
|
}, e.id)),
|
|
391
|
-
X && !
|
|
407
|
+
X && !I && /* @__PURE__ */ g(ne, {
|
|
392
408
|
longitude: X.coordinates[0],
|
|
393
409
|
latitude: X.coordinates[1],
|
|
394
410
|
anchor: "top",
|
|
395
|
-
onClose: () =>
|
|
411
|
+
onClose: () => P(null),
|
|
396
412
|
closeOnClick: !1,
|
|
397
|
-
children: /* @__PURE__ */
|
|
413
|
+
children: /* @__PURE__ */ _("div", {
|
|
398
414
|
className: "p-2 min-w-[150px] sm:min-w-[200px]",
|
|
399
415
|
children: [
|
|
400
|
-
/* @__PURE__ */
|
|
416
|
+
/* @__PURE__ */ g("h3", {
|
|
401
417
|
className: "font-bold text-sm mb-1",
|
|
402
418
|
children: X.title
|
|
403
419
|
}),
|
|
404
|
-
X.description && /* @__PURE__ */
|
|
420
|
+
X.description && /* @__PURE__ */ g("p", {
|
|
405
421
|
className: "text-xs text-muted-foreground",
|
|
406
422
|
children: X.description
|
|
407
423
|
}),
|
|
408
|
-
/* @__PURE__ */
|
|
424
|
+
/* @__PURE__ */ _("div", {
|
|
409
425
|
className: "mt-2 text-xs flex gap-2",
|
|
410
|
-
children: [b && /* @__PURE__ */
|
|
426
|
+
children: [b && /* @__PURE__ */ g("button", {
|
|
427
|
+
type: "button",
|
|
411
428
|
className: "text-blue-500 hover:underline",
|
|
412
429
|
onClick: () => b(X.data),
|
|
413
430
|
children: "Edit"
|
|
414
|
-
}), x && /* @__PURE__ */
|
|
431
|
+
}), x && /* @__PURE__ */ g("button", {
|
|
432
|
+
type: "button",
|
|
415
433
|
className: "text-red-500 hover:underline",
|
|
416
434
|
onClick: () => x(X.data),
|
|
417
435
|
children: "Delete"
|
|
@@ -422,43 +440,45 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
422
440
|
})
|
|
423
441
|
]
|
|
424
442
|
}),
|
|
425
|
-
X &&
|
|
443
|
+
X && I && /* @__PURE__ */ _("div", {
|
|
426
444
|
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)]",
|
|
427
445
|
role: "dialog",
|
|
428
446
|
"aria-label": "Location details",
|
|
429
447
|
"data-testid": "map-mobile-record-sheet",
|
|
430
448
|
children: [
|
|
431
|
-
/* @__PURE__ */
|
|
449
|
+
/* @__PURE__ */ g("div", {
|
|
432
450
|
className: "mx-auto mb-2 h-1 w-10 rounded-full bg-muted",
|
|
433
451
|
"aria-hidden": "true"
|
|
434
452
|
}),
|
|
435
|
-
/* @__PURE__ */
|
|
453
|
+
/* @__PURE__ */ _("div", {
|
|
436
454
|
className: "flex items-start justify-between gap-3",
|
|
437
|
-
children: [/* @__PURE__ */
|
|
455
|
+
children: [/* @__PURE__ */ _("div", {
|
|
438
456
|
className: "min-w-0 flex-1",
|
|
439
|
-
children: [/* @__PURE__ */
|
|
457
|
+
children: [/* @__PURE__ */ g("h3", {
|
|
440
458
|
className: "text-sm font-semibold truncate",
|
|
441
459
|
children: X.title
|
|
442
|
-
}), X.description && /* @__PURE__ */
|
|
460
|
+
}), X.description && /* @__PURE__ */ g("p", {
|
|
443
461
|
className: "mt-1 text-xs text-muted-foreground line-clamp-3",
|
|
444
462
|
children: X.description
|
|
445
463
|
})]
|
|
446
|
-
}), /* @__PURE__ */
|
|
464
|
+
}), /* @__PURE__ */ g("button", {
|
|
447
465
|
type: "button",
|
|
448
|
-
onClick: () =>
|
|
466
|
+
onClick: () => P(null),
|
|
449
467
|
className: "text-muted-foreground hover:text-foreground text-lg leading-none px-2",
|
|
450
468
|
"aria-label": "Close details",
|
|
451
469
|
"data-testid": "map-mobile-record-close",
|
|
452
470
|
children: "×"
|
|
453
471
|
})]
|
|
454
472
|
}),
|
|
455
|
-
/* @__PURE__ */
|
|
473
|
+
/* @__PURE__ */ _("div", {
|
|
456
474
|
className: "mt-3 flex flex-wrap gap-2 text-xs",
|
|
457
|
-
children: [b && /* @__PURE__ */
|
|
475
|
+
children: [b && /* @__PURE__ */ g("button", {
|
|
476
|
+
type: "button",
|
|
458
477
|
className: "px-3 py-1.5 rounded-md border bg-card hover:bg-accent",
|
|
459
478
|
onClick: () => b(X.data),
|
|
460
479
|
children: "Edit"
|
|
461
|
-
}), x && /* @__PURE__ */
|
|
480
|
+
}), x && /* @__PURE__ */ g("button", {
|
|
481
|
+
type: "button",
|
|
462
482
|
className: "px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10",
|
|
463
483
|
onClick: () => x(X.data),
|
|
464
484
|
children: "Delete"
|
|
@@ -466,23 +486,23 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
466
486
|
})
|
|
467
487
|
]
|
|
468
488
|
}),
|
|
469
|
-
z && /* @__PURE__ */
|
|
489
|
+
z && /* @__PURE__ */ g("div", {
|
|
470
490
|
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",
|
|
471
491
|
children: z
|
|
472
492
|
})
|
|
473
493
|
]
|
|
474
494
|
}),
|
|
475
|
-
Q.isOverlay && /* @__PURE__ */
|
|
495
|
+
Q.isOverlay && /* @__PURE__ */ g(ee, {
|
|
476
496
|
...Q,
|
|
477
497
|
title: "Location Details",
|
|
478
|
-
children: (e) => /* @__PURE__ */
|
|
498
|
+
children: (e) => /* @__PURE__ */ g("div", {
|
|
479
499
|
className: "space-y-3",
|
|
480
|
-
children: Object.entries(e).map(([e, t]) => /* @__PURE__ */
|
|
500
|
+
children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ _("div", {
|
|
481
501
|
className: "flex flex-col",
|
|
482
|
-
children: [/* @__PURE__ */
|
|
502
|
+
children: [/* @__PURE__ */ g("span", {
|
|
483
503
|
className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
|
|
484
504
|
children: e.replace(/_/g, " ")
|
|
485
|
-
}), /* @__PURE__ */
|
|
505
|
+
}), /* @__PURE__ */ g("span", {
|
|
486
506
|
className: "text-sm",
|
|
487
507
|
children: String(t ?? "—")
|
|
488
508
|
})]
|
|
@@ -491,15 +511,25 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
491
511
|
})
|
|
492
512
|
]
|
|
493
513
|
});
|
|
494
|
-
},
|
|
495
|
-
|
|
496
|
-
|
|
514
|
+
}, T = {
|
|
515
|
+
filter: !0,
|
|
516
|
+
sort: !0
|
|
517
|
+
}, E = ({ schema: e, ...t }) => {
|
|
518
|
+
let { dataSource: n } = u() || {};
|
|
519
|
+
return /* @__PURE__ */ g(c, {
|
|
497
520
|
schema: e,
|
|
521
|
+
mapping: T,
|
|
498
522
|
dataSource: n,
|
|
499
|
-
|
|
523
|
+
testId: "object-map",
|
|
524
|
+
errorTitle: "This map’s data source could not be resolved",
|
|
525
|
+
children: (e) => /* @__PURE__ */ g(w, {
|
|
526
|
+
schema: e,
|
|
527
|
+
dataSource: n,
|
|
528
|
+
...t
|
|
529
|
+
})
|
|
500
530
|
});
|
|
501
531
|
};
|
|
502
|
-
|
|
532
|
+
a.register("object-map", E, {
|
|
503
533
|
namespace: "plugin-map",
|
|
504
534
|
label: "Object Map",
|
|
505
535
|
category: "view",
|
|
@@ -514,7 +544,7 @@ console.log("Registering object-map..."), a.register("object-map", b, {
|
|
|
514
544
|
label: "Map Config",
|
|
515
545
|
description: "latitudeField, longitudeField, titleField"
|
|
516
546
|
}]
|
|
517
|
-
}), a.register("map",
|
|
547
|
+
}), a.register("map", E, {
|
|
518
548
|
namespace: "view",
|
|
519
549
|
label: "Map View",
|
|
520
550
|
category: "view",
|
|
@@ -531,4 +561,4 @@ console.log("Registering object-map..."), a.register("object-map", b, {
|
|
|
531
561
|
}]
|
|
532
562
|
});
|
|
533
563
|
//#endregion
|
|
534
|
-
export {
|
|
564
|
+
export { w as ObjectMap, E as ObjectMapRenderer };
|
package/dist/index.umd.cjs
CHANGED
|
@@ -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/components"),require("zod"),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/components`,`zod`,`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.ObjectUIComponents,e.zod,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){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var l=Object.create,u=Object.defineProperty,d=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&&u(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=d(t,s))||r.enumerable});return e},g=(e,t,n)=>(n=e==null?{}:l(p(e)),h(t||!e||!e.__esModule||!m.call(e,`default`)?u(n,`default`,{value:e,enumerable:!0}):n,e));t=g(t,1),o=g(o,1);var _=a.z.object({latitudeField:a.z.string().optional(),longitudeField:a.z.string().optional(),locationField:a.z.string().optional(),titleField:a.z.string().optional(),descriptionField:a.z.string().optional(),zoom:a.z.number().optional(),center:a.z.tuple([a.z.number(),a.z.number()]).optional(),style:a.z.string().optional()}),ee=`https://demotiles.maplibre.org/style.json`;function te(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function v(e){if(e){if(typeof e==`string`){let t=e.split(` `),n=t[0],r=t[1]?.toLowerCase()===`desc`?`desc`:`asc`;return{[n]:r}}if(Array.isArray(e))return e.reduce((e,t)=>(t.field&&t.order&&(e[t.field]=t.order),e),{})}}function y(e){let t=e.style||e.mapStyle||e.filter?.map?.style||e.map?.style;if(e.locationField||e.latitudeField)return{locationField:e.locationField,latitudeField:e.latitudeField,longitudeField:e.longitudeField,titleField:e.titleField||`name`,descriptionField:e.descriptionField,zoom:e.zoom,center:e.center,style:t};let n=null;if(e.filter&&typeof e.filter==`object`&&`map`in e.filter?n=e.filter.map:e.map&&(n=e.map),n){let e=_.safeParse(n);return e.success||console.warn(`[ObjectMap] Invalid map configuration:`,e.error.format()),{...n,style:n.style||t}}return{latitudeField:`latitude`,longitudeField:`longitude`,locationField:`location`,titleField:`name`,descriptionField:`description`,zoom:10,center:[0,0],style:t}}function b(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 x(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 S=({schema:e,dataSource:a,className:s,onMarkerClick:l,onRowClick:u,onEdit:d,onDelete:f,enableClustering:p,clusterRadius:m=50,...h})=>{let[g,_]=(0,t.useState)([]),[S,C]=(0,t.useState)(!0),[w,T]=(0,t.useState)(null),[E,D]=(0,t.useState)(null),[O,k]=(0,t.useState)(null),[A,j]=(0,t.useState)(``),M=(0,i.useIsMobile)(),N=(0,t.useRef)(null),[P,F]=(0,t.useState)(null),[I,L]=(0,t.useState)(null),[R,z]=(0,t.useState)(!1),[B,V]=(0,t.useState)(null),ne=(0,t.useCallback)(e=>{V(e?.error?.message||`Failed to load the map style/tiles.`)},[]),H=(0,t.useCallback)(()=>{if(typeof navigator>`u`||!navigator.geolocation){L(`Geolocation is not available in this browser.`);return}z(!0),L(null),navigator.geolocation.getCurrentPosition(e=>{let{longitude:t,latitude:n}=e.coords;F({lng:t,lat:n}),z(!1);try{N.current?.flyTo({center:[t,n],zoom:12,duration:800})}catch{}},e=>{z(!1),L(e.message||`Unable to retrieve location.`)},{enableHighAccuracy:!1,timeout:8e3,maximumAge:6e4})},[]),U=te(e),W=(0,t.useMemo)(()=>U,[JSON.stringify(U)]),G=y(e),K=W?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(C(!0),h.data){let e=h.data;if(Array.isArray(e)){_(e),C(!1);return}}if(e.data){let t=e.data;if(Array.isArray(t)){_(t),C(!1);return}}if(K&&W?.provider===`value`){_(W.items),C(!1);return}if(!a||typeof a.find!=`function`)throw Error(`DataSource required for object/api providers`);if(W?.provider===`object`){let t=W.object,r=(0,n.buildExpandFields)(E?.fields),i=await a.find(t,{$filter:e.filter,$orderby:v(e.sort),...r.length>0?{$expand:r}:{}}),o=(0,n.extractRecords)(i);_(o)}else W?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectMap`),_([]));C(!1)}catch(e){T(e),C(!1)}})()},[W,a,K,e.filter,e.sort,E]),(0,t.useEffect)(()=>{!K&&a&&(async()=>{try{if(!a)return;let t=W?.provider===`object`?W.object:e.objectName;if(!t)return;let n=await a.getObjectSchema(t);D(n)}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,a,K,W]);let{markers:q,invalidCount:J}=(0,t.useMemo)(()=>{let e=0;return{markers:g.map((t,n)=>{let r=b(t,G);if(!r)return e++,null;let i=G.titleField?t[G.titleField]:`Marker`,a=G.descriptionField?t[G.descriptionField]:void 0,[o,s]=r;return!isFinite(o)||!isFinite(s)||o<-90||o>90||s<-180||s>180?(e++,null):{id:t.id||t._id||`marker-${n}`,title:i,description:a,coordinates:[s,o],data:t}}).filter(e=>e!==null),invalidCount:e}},[g,G]),Y=(0,t.useMemo)(()=>q.find(e=>e.id===O),[q,O]),[X,Z]=(0,t.useState)(G.zoom||3),Q=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:u}),$=(0,t.useMemo)(()=>{if(!A.trim())return q;let e=A.toLowerCase();return q.filter(t=>t.title?.toLowerCase().includes(e)||t.description?.toLowerCase().includes(e))},[q,A]),re=(0,t.useMemo)(()=>p??(e.enableClustering||$.length>100)?x($,X,m):$.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1})),[$,X,p,m,e]),ie=(0,t.useMemo)(()=>{if(!$.length)return{longitude:G.center?.[1]||0,latitude:G.center?.[0]||0,zoom:G.zoom||2};let e=$.map(e=>e.coordinates[0]),t=$.map(e=>e.coordinates[1]),n=Math.min(...e),r=Math.max(...e),i=Math.min(...t),a=Math.max(...t);return{longitude:(n+r)/2,latitude:(i+a)/2,zoom:G.zoom||3}},[$,G]);return S?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading map...`})})}):w?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,w.message]})})}):(0,c.jsxs)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:[J>0&&(0,c.jsx)(`div`,{className:`mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded`,children:`${J} record${J===1?``:`s`} with missing or invalid coordinates excluded from the map.`}),q.length>0&&(0,c.jsx)(`div`,{className:`mb-2`,children:(0,c.jsx)(`input`,{type:`text`,value:A,onChange:e=>j(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,c.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,c.jsxs)(o.default,{ref:e=>{N.current=e},initialViewState:ie,style:{width:`100%`,height:`100%`},mapStyle:G.style||ee,touchZoomRotate:!0,dragRotate:!0,touchPitch:!0,onZoom:e=>Z(Math.round(e.viewState.zoom)),onError:ne,children:[B&&(0,c.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 (`,B,`). Markers below are still listed in the search box;`,` `,G.style?`check the configured map style URL.`:`configure a custom map style for production use.`]}),(0,c.jsx)(o.NavigationControl,{position:`top-right`,showCompass:!0,showZoom:!0}),(0,c.jsx)(`button`,{type:`button`,onClick:H,disabled:R,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,c.jsx)(`span`,{"aria-hidden":`true`,children:R?`⏳`:`🧭`})}),P&&(0,c.jsx)(o.Marker,{longitude:P.lng,latitude:P.lat,anchor:`center`,children:(0,c.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`})}),re.map(e=>e.isCluster?(0,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`center`,onClick:t=>{t.originalEvent.stopPropagation();try{let t=Math.min(20,Math.max(X+2,8));N.current?.flyTo({center:[e.coordinates[0],e.coordinates[1]],zoom:t,duration:600})}catch{}},children:(0,c.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,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`bottom`,onClick:t=>{t.originalEvent.stopPropagation();let n=e.markers[0];k(n.id),Q.handleClick(n.data),l?.(n.data)},children:(0,c.jsx)(`div`,{className:`text-2xl cursor-pointer hover:scale-110 transition-transform`,children:`📍`})},e.id)),Y&&!M&&(0,c.jsx)(o.Popup,{longitude:Y.coordinates[0],latitude:Y.coordinates[1],anchor:`top`,onClose:()=>k(null),closeOnClick:!1,children:(0,c.jsxs)(`div`,{className:`p-2 min-w-[150px] sm:min-w-[200px]`,children:[(0,c.jsx)(`h3`,{className:`font-bold text-sm mb-1`,children:Y.title}),Y.description&&(0,c.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:Y.description}),(0,c.jsxs)(`div`,{className:`mt-2 text-xs flex gap-2`,children:[d&&(0,c.jsx)(`button`,{className:`text-blue-500 hover:underline`,onClick:()=>d(Y.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{className:`text-red-500 hover:underline`,onClick:()=>f(Y.data),children:`Delete`})]})]})})]}),Y&&M&&(0,c.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,c.jsx)(`div`,{className:`mx-auto mb-2 h-1 w-10 rounded-full bg-muted`,"aria-hidden":`true`}),(0,c.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,c.jsx)(`h3`,{className:`text-sm font-semibold truncate`,children:Y.title}),Y.description&&(0,c.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-3`,children:Y.description})]}),(0,c.jsx)(`button`,{type:`button`,onClick:()=>k(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,c.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-xs`,children:[d&&(0,c.jsx)(`button`,{className:`px-3 py-1.5 rounded-md border bg-card hover:bg-accent`,onClick:()=>d(Y.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{className:`px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10`,onClick:()=>f(Y.data),children:`Delete`})]})]}),I&&(0,c.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:I})]}),Q.isOverlay&&(0,c.jsx)(i.NavigationOverlay,{...Q,title:`Location Details`,children:e=>(0,c.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,c.jsxs)(`div`,{className:`flex flex-col`,children:[(0,c.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,c.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]})},C=({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,c.jsx)(S,{schema:e,dataSource:n,...t})};console.log(`Registering object-map...`),n.ComponentRegistry.register(`object-map`,C,{namespace:`plugin-map`,label:`Object Map`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),n.ComponentRegistry.register(`map`,C,{namespace:`view`,label:`Map View`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),e.ObjectMap=S,e.ObjectMapRenderer=C});
|
|
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/components"),require("zod"),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/components`,`zod`,`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.ObjectUIComponents,e.zod,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){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var l=Object.create,u=Object.defineProperty,d=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&&u(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=d(t,s))||r.enumerable});return e},g=(e,t,n)=>(n=e==null?{}:l(p(e)),h(t||!e||!e.__esModule||!m.call(e,`default`)?u(n,`default`,{value:e,enumerable:!0}):n,e));t=g(t,1),o=g(o,1);var _=a.z.object({latitudeField:a.z.string().optional(),longitudeField:a.z.string().optional(),locationField:a.z.string().optional(),titleField:a.z.string().optional(),descriptionField:a.z.string().optional(),zoom:a.z.number().optional(),center:a.z.tuple([a.z.number(),a.z.number()]).optional(),style:a.z.string().optional()}),ee=`https://demotiles.maplibre.org/style.json`;function te(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function v(e){if(e){if(typeof e==`string`){let t=e.split(` `),n=t[0],r=t[1]?.toLowerCase()===`desc`?`desc`:`asc`;return{[n]:r}}if(Array.isArray(e))return e.reduce((e,t)=>(t.field&&t.order&&(e[t.field]=t.order),e),{})}}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 is rendering with the DEFAULT field names (`latitude` / `longitude` / `name`). `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."))}function S(e){x(e);let t=e.style||e.mapStyle||e.map?.style;if(e.locationField||e.latitudeField)return{locationField:e.locationField,latitudeField:e.latitudeField,longitudeField:e.longitudeField,titleField:e.titleField||`name`,descriptionField:e.descriptionField,zoom:e.zoom,center:e.center,style:t};let n=e.map?e.map:null;if(n){let e=_.safeParse(n);return e.success||console.warn(`[ObjectMap] Invalid map configuration:`,e.error.format()),{...n,style:n.style||t}}return{latitudeField:`latitude`,longitudeField:`longitude`,locationField:`location`,titleField:`name`,descriptionField:`description`,zoom:10,center:[0,0],style:t}}function C(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 w(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 T=({schema:e,dataSource:a,className:s,onMarkerClick:l,onRowClick:u,onEdit:d,onDelete:f,enableClustering:p,clusterRadius:m=50,...h})=>{let[g,_]=(0,t.useState)([]),[y,b]=(0,t.useState)(!0),[x,T]=(0,t.useState)(null),[E,D]=(0,t.useState)(null),[O,k]=(0,t.useState)(null),[A,ne]=(0,t.useState)(``),j=(0,i.useIsMobile)(),M=(0,t.useRef)(null),[N,P]=(0,t.useState)(null),[F,I]=(0,t.useState)(null),[L,R]=(0,t.useState)(!1),[z,B]=(0,t.useState)(null),V=(0,t.useCallback)(e=>{B(e?.error?.message||`Failed to load the map style/tiles.`)},[]),H=(0,t.useCallback)(()=>{if(typeof navigator>`u`||!navigator.geolocation){I(`Geolocation is not available in this browser.`);return}R(!0),I(null),navigator.geolocation.getCurrentPosition(e=>{let{longitude:t,latitude:n}=e.coords;P({lng:t,lat:n}),R(!1);try{M.current?.flyTo({center:[t,n],zoom:12,duration:800})}catch{}},e=>{R(!1),I(e.message||`Unable to retrieve location.`)},{enableHighAccuracy:!1,timeout:8e3,maximumAge:6e4})},[]),U=te(e),W=(0,t.useMemo)(()=>U,[JSON.stringify(U)]),G=S(e),K=W?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(b(!0),h.data){let e=h.data;if(Array.isArray(e)){_(e),b(!1);return}}if(e.data){let t=e.data;if(Array.isArray(t)){_(t),b(!1);return}}if(K&&W?.provider===`value`){_(W.items),b(!1);return}if(!a||typeof a.find!=`function`)throw Error(`DataSource required for object/api providers`);if(W?.provider===`object`){let t=W.object,r=(0,n.buildExpandFields)(E?.fields),i=await a.find(t,{$filter:e.filter,$orderby:v(e.sort),...r.length>0?{$expand:r}:{}}),o=(0,n.extractRecords)(i);_(o)}else W?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectMap`),_([]));b(!1)}catch(e){T(e),b(!1)}})()},[W,a,K,e.filter,e.sort,E]),(0,t.useEffect)(()=>{!K&&a&&(async()=>{try{if(!a)return;let t=W?.provider===`object`?W.object:e.objectName;if(!t)return;let n=await a.getObjectSchema(t);D(n)}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,a,K,W]);let{markers:q,invalidCount:J}=(0,t.useMemo)(()=>{let e=0;return{markers:g.map((t,n)=>{let r=C(t,G);if(!r)return e++,null;let i=G.titleField?t[G.titleField]:`Marker`,a=G.descriptionField?t[G.descriptionField]:void 0,[o,s]=r;return!isFinite(o)||!isFinite(s)||o<-90||o>90||s<-180||s>180?(e++,null):{id:t.id||t._id||`marker-${n}`,title:i,description:a,coordinates:[s,o],data:t}}).filter(e=>e!==null),invalidCount:e}},[g,G]),Y=(0,t.useMemo)(()=>q.find(e=>e.id===O),[q,O]),[X,Z]=(0,t.useState)(G.zoom||3),Q=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:u}),$=(0,t.useMemo)(()=>{if(!A.trim())return q;let e=A.toLowerCase();return q.filter(t=>t.title?.toLowerCase().includes(e)||t.description?.toLowerCase().includes(e))},[q,A]),re=(0,t.useMemo)(()=>p??(e.enableClustering||$.length>100)?w($,X,m):$.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1})),[$,X,p,m,e]),ie=(0,t.useMemo)(()=>{if(!$.length)return{longitude:G.center?.[1]||0,latitude:G.center?.[0]||0,zoom:G.zoom||2};let e=$.map(e=>e.coordinates[0]),t=$.map(e=>e.coordinates[1]),n=Math.min(...e),r=Math.max(...e),i=Math.min(...t),a=Math.max(...t);return{longitude:(n+r)/2,latitude:(i+a)/2,zoom:G.zoom||3}},[$,G]);return y?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading map...`})})}):x?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,x.message]})})}):(0,c.jsxs)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:[J>0&&(0,c.jsx)(`div`,{className:`mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded`,children:`${J} record${J===1?``:`s`} with missing or invalid coordinates excluded from the map.`}),q.length>0&&(0,c.jsx)(`div`,{className:`mb-2`,children:(0,c.jsx)(`input`,{type:`text`,value:A,onChange:e=>ne(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,c.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,c.jsxs)(o.default,{ref:e=>{M.current=e},initialViewState:ie,style:{width:`100%`,height:`100%`},mapStyle:G.style||ee,touchZoomRotate:!0,dragRotate:!0,touchPitch:!0,onZoom:e=>Z(Math.round(e.viewState.zoom)),onError:V,children:[z&&(0,c.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 (`,z,`). Markers below are still listed in the search box;`,` `,G.style?`check the configured map style URL.`:`configure a custom map style for production use.`]}),(0,c.jsx)(o.NavigationControl,{position:`top-right`,showCompass:!0,showZoom:!0}),(0,c.jsx)(`button`,{type:`button`,onClick:H,disabled:L,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,c.jsx)(`span`,{"aria-hidden":`true`,children:L?`⏳`:`🧭`})}),N&&(0,c.jsx)(o.Marker,{longitude:N.lng,latitude:N.lat,anchor:`center`,children:(0,c.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`})}),re.map(e=>e.isCluster?(0,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`center`,onClick:t=>{t.originalEvent.stopPropagation();try{let t=Math.min(20,Math.max(X+2,8));M.current?.flyTo({center:[e.coordinates[0],e.coordinates[1]],zoom:t,duration:600})}catch{}},children:(0,c.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,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`bottom`,onClick:t=>{t.originalEvent.stopPropagation();let n=e.markers[0];k(n.id),Q.handleClick(n.data),l?.(n.data)},children:(0,c.jsx)(`div`,{className:`text-2xl cursor-pointer hover:scale-110 transition-transform`,children:`📍`})},e.id)),Y&&!j&&(0,c.jsx)(o.Popup,{longitude:Y.coordinates[0],latitude:Y.coordinates[1],anchor:`top`,onClose:()=>k(null),closeOnClick:!1,children:(0,c.jsxs)(`div`,{className:`p-2 min-w-[150px] sm:min-w-[200px]`,children:[(0,c.jsx)(`h3`,{className:`font-bold text-sm mb-1`,children:Y.title}),Y.description&&(0,c.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:Y.description}),(0,c.jsxs)(`div`,{className:`mt-2 text-xs flex gap-2`,children:[d&&(0,c.jsx)(`button`,{type:`button`,className:`text-blue-500 hover:underline`,onClick:()=>d(Y.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{type:`button`,className:`text-red-500 hover:underline`,onClick:()=>f(Y.data),children:`Delete`})]})]})})]}),Y&&j&&(0,c.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,c.jsx)(`div`,{className:`mx-auto mb-2 h-1 w-10 rounded-full bg-muted`,"aria-hidden":`true`}),(0,c.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,c.jsx)(`h3`,{className:`text-sm font-semibold truncate`,children:Y.title}),Y.description&&(0,c.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-3`,children:Y.description})]}),(0,c.jsx)(`button`,{type:`button`,onClick:()=>k(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,c.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-xs`,children:[d&&(0,c.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 rounded-md border bg-card hover:bg-accent`,onClick:()=>d(Y.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10`,onClick:()=>f(Y.data),children:`Delete`})]})]}),F&&(0,c.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:F})]}),Q.isOverlay&&(0,c.jsx)(i.NavigationOverlay,{...Q,title:`Location Details`,children:e=>(0,c.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,c.jsxs)(`div`,{className:`flex flex-col`,children:[(0,c.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,c.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]})},E={filter:!0,sort:!0},D=({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,c.jsx)(r.ElementDataSourceGate,{schema:e,mapping:E,dataSource:n,testId:`object-map`,errorTitle:`This map’s data source could not be resolved`,children:e=>(0,c.jsx)(T,{schema:e,dataSource:n,...t})})};n.ComponentRegistry.register(`object-map`,D,{namespace:`plugin-map`,label:`Object Map`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),n.ComponentRegistry.register(`map`,D,{namespace:`view`,label:`Map View`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),e.ObjectMap=T,e.ObjectMapRenderer=D});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/plugin-map",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Map visualization plugin for Object UI",
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@objectstack/spec": "^17.0.0-rc.
|
|
28
|
-
"lucide-react": "^1.
|
|
29
|
-
"maplibre-gl": "^6.
|
|
27
|
+
"@objectstack/spec": "^17.0.0-rc.6",
|
|
28
|
+
"lucide-react": "^1.29.0",
|
|
29
|
+
"maplibre-gl": "^6.2.0",
|
|
30
30
|
"react-map-gl": "^8.1.2",
|
|
31
31
|
"zod": "^4.4.3",
|
|
32
|
-
"@object-ui/components": "17.
|
|
33
|
-
"@object-ui/core": "17.
|
|
34
|
-
"@object-ui/react": "17.
|
|
35
|
-
"@object-ui/types": "17.
|
|
32
|
+
"@object-ui/components": "17.5.0",
|
|
33
|
+
"@object-ui/core": "17.5.0",
|
|
34
|
+
"@object-ui/react": "17.5.0",
|
|
35
|
+
"@object-ui/types": "17.5.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@types/react-dom": "19.2.4",
|
|
44
44
|
"@vitejs/plugin-react": "^6.0.5",
|
|
45
45
|
"typescript": "^6.0.3",
|
|
46
|
-
"vite": "^8.2.
|
|
46
|
+
"vite": "^8.2.1",
|
|
47
47
|
"vite-plugin-dts": "^5.0.3"
|
|
48
48
|
},
|
|
49
49
|
"keywords": [
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"build": "vite build",
|
|
74
74
|
"test": "vitest run",
|
|
75
75
|
"test:watch": "vitest",
|
|
76
|
-
"type-check": "tsc --noEmit",
|
|
76
|
+
"type-check": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
77
77
|
"lint": "eslint ."
|
|
78
78
|
}
|
|
79
79
|
}
|