@wipco/sdui 0.1.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/dist/rich.js ADDED
@@ -0,0 +1,684 @@
1
+ import { HoistedStyle, Spinner, EmptyState } from './chunk-AR2JYE75.js';
2
+ export { DatePicker, DateRangePicker } from './chunk-AR2JYE75.js';
3
+ import { useRef, useCallback, useMemo, useState, useEffect, useLayoutEffect } from 'react';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
+
6
+ function useOptionalModule(load) {
7
+ const [state, setState] = useState({ status: "loading" });
8
+ useEffect(() => {
9
+ let alive = true;
10
+ load().then(
11
+ (module) => {
12
+ if (alive) setState({ status: "ready", module });
13
+ },
14
+ (error) => {
15
+ if (!alive) return;
16
+ console.warn("[sdui] \uC120\uD0DD \uC758\uC874\uC131 \uB85C\uB4DC \uC2E4\uD328 \u2014 \uD50C\uB808\uC774\uC2A4\uD640\uB354\uB85C \uB300\uCCB4\uD569\uB2C8\uB2E4", error);
17
+ setState({ status: "missing" });
18
+ }
19
+ );
20
+ return () => {
21
+ alive = false;
22
+ };
23
+ }, [load]);
24
+ return state;
25
+ }
26
+ function DependencyPlaceholder({
27
+ packageName,
28
+ purpose,
29
+ height,
30
+ loading = false
31
+ }) {
32
+ return /* @__PURE__ */ jsx(
33
+ "div",
34
+ {
35
+ style: {
36
+ minHeight: height,
37
+ display: "flex",
38
+ alignItems: "center",
39
+ justifyContent: "center",
40
+ border: "1px solid var(--wp-border-subtle)",
41
+ borderRadius: "var(--wp-radius-md)",
42
+ background: "var(--wp-surface-sunken)"
43
+ },
44
+ children: loading ? /* @__PURE__ */ jsx(Spinner, { label: `${purpose} \uC900\uBE44 \uC911` }) : /* @__PURE__ */ jsxs(EmptyState, { tight: true, icon: "box", title: `${purpose}\uB97C \uADF8\uB9AC\uB824\uBA74 ${packageName} \uD328\uD0A4\uC9C0\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4`, children: [
45
+ "\uC120\uD0DD \uC758\uC874\uC131\uC774\uB77C \uAE30\uBCF8 \uC124\uCE58\uC5D0\uB294 \uD3EC\uD568\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 ",
46
+ /* @__PURE__ */ jsxs("code", { children: [
47
+ "pnpm add ",
48
+ packageName
49
+ ] }),
50
+ " \uD6C4 \uB2E4\uC2DC \uC5F4\uC5B4 \uC8FC\uC138\uC694."
51
+ ] })
52
+ }
53
+ );
54
+ }
55
+ var loadRecharts = () => import('recharts');
56
+ var SERIES_FALLBACK = [
57
+ "#1d2c60",
58
+ "#0a73c9",
59
+ "#c9aa49",
60
+ "#12805a",
61
+ "#ca1a1d",
62
+ "#8e9bc2",
63
+ "#5b6577",
64
+ "#a5cdf1"
65
+ ];
66
+ function useSeriesPalette(ref) {
67
+ const [palette, setPalette] = useState(SERIES_FALLBACK);
68
+ useLayoutEffect(() => {
69
+ const el = ref.current;
70
+ if (el === null) return;
71
+ const computed = getComputedStyle(el);
72
+ const next = SERIES_FALLBACK.map(
73
+ (fallback, i) => computed.getPropertyValue(`--wp-series-${i + 1}`).trim() || fallback
74
+ );
75
+ setPalette((prev) => prev.every((color, i) => color === next[i]) ? prev : next);
76
+ }, [ref]);
77
+ return palette;
78
+ }
79
+ var formatNumber = (v) => v.toLocaleString("ko-KR", { maximumFractionDigits: 1 });
80
+ var formatCurrency = (v) => {
81
+ const sign = v < 0 ? "-" : "";
82
+ const abs = Math.abs(v);
83
+ if (abs >= 1e8) {
84
+ const eok = abs / 1e8;
85
+ return `${sign}${eok.toLocaleString("ko-KR", { maximumFractionDigits: eok >= 100 ? 0 : 1 })}\uC5B5`;
86
+ }
87
+ if (abs >= 1e4) {
88
+ return `${sign}${Math.round(abs / 1e4).toLocaleString("ko-KR")}\uB9CC`;
89
+ }
90
+ return `${sign}${abs.toLocaleString("ko-KR")}`;
91
+ };
92
+ var formatPercent = (v) => `${v.toLocaleString("ko-KR", { maximumFractionDigits: 1 })}%`;
93
+ var getFormatter = (format) => {
94
+ if (format === "currency") return formatCurrency;
95
+ if (format === "percent") return formatPercent;
96
+ return formatNumber;
97
+ };
98
+ var tooltipBoxStyle = {
99
+ background: "var(--wp-surface-card)",
100
+ border: "1px solid var(--wp-border-subtle)",
101
+ borderRadius: "var(--wp-radius-md)",
102
+ boxShadow: "var(--wp-shadow-lg)",
103
+ padding: "var(--wp-space-2) var(--wp-space-3)",
104
+ minWidth: 128
105
+ };
106
+ var dotStyle = (color) => ({
107
+ width: 8,
108
+ height: 8,
109
+ borderRadius: "var(--wp-radius-full)",
110
+ background: color,
111
+ flexShrink: 0
112
+ });
113
+ function renderTooltipContent(props, format) {
114
+ const { active, payload, label } = props;
115
+ if (!active || !payload || payload.length === 0) return null;
116
+ return /* @__PURE__ */ jsxs("div", { style: tooltipBoxStyle, children: [
117
+ label !== void 0 && label !== null && label !== "" && /* @__PURE__ */ jsx("div", { className: "wp-label", style: { marginBottom: "var(--wp-space-1)" }, children: label }),
118
+ /* @__PURE__ */ jsx("div", { style: { display: "grid", gap: 2 }, children: payload.filter((entry) => entry.type !== "none").map((entry, i) => {
119
+ const fillFromDatum = entry.payload !== null && typeof entry.payload === "object" ? entry.payload.fill : void 0;
120
+ const color = entry.color ?? fillFromDatum ?? "var(--wp-text-muted)";
121
+ const value = typeof entry.value === "number" ? format(entry.value) : String(entry.value ?? "");
122
+ return /* @__PURE__ */ jsxs(
123
+ "div",
124
+ {
125
+ className: "wp-body-sm",
126
+ style: { display: "flex", alignItems: "center", gap: "var(--wp-space-2)" },
127
+ children: [
128
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: dotStyle(color) }),
129
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--wp-text-muted)" }, children: entry.name }),
130
+ /* @__PURE__ */ jsx(
131
+ "span",
132
+ {
133
+ style: {
134
+ marginLeft: "auto",
135
+ paddingLeft: "var(--wp-space-3)",
136
+ color: "var(--wp-text-strong)",
137
+ fontWeight: 500,
138
+ fontVariantNumeric: "tabular-nums"
139
+ },
140
+ children: value
141
+ }
142
+ )
143
+ ]
144
+ },
145
+ i
146
+ );
147
+ }) })
148
+ ] });
149
+ }
150
+ function HtmlLegend({ items }) {
151
+ return /* @__PURE__ */ jsx(
152
+ "div",
153
+ {
154
+ style: {
155
+ display: "flex",
156
+ flexWrap: "wrap",
157
+ justifyContent: "center",
158
+ gap: "var(--wp-space-1) var(--wp-space-4)",
159
+ marginTop: "var(--wp-space-2)"
160
+ },
161
+ children: items.map((item, i) => /* @__PURE__ */ jsxs(
162
+ "span",
163
+ {
164
+ className: "wp-caption",
165
+ style: { display: "inline-flex", alignItems: "center", gap: "var(--wp-space-1)" },
166
+ children: [
167
+ item.dashed ? /* @__PURE__ */ jsx(
168
+ "span",
169
+ {
170
+ "aria-hidden": true,
171
+ style: { width: 12, height: 0, borderTop: `2px dashed ${item.color}`, flexShrink: 0 }
172
+ }
173
+ ) : /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: dotStyle(item.color) }),
174
+ item.label
175
+ ]
176
+ },
177
+ `${item.label}-${i}`
178
+ ))
179
+ }
180
+ );
181
+ }
182
+ var axisTick = { fill: "var(--wp-text-muted)", fontSize: 12 };
183
+ function Chart({
184
+ type,
185
+ data,
186
+ xKey,
187
+ series,
188
+ height = 300,
189
+ valueFormat = "number",
190
+ legend = true,
191
+ donutCenter,
192
+ emptyText
193
+ }) {
194
+ const hostRef = useRef(null);
195
+ const palette = useSeriesPalette(hostRef);
196
+ const recharts = useOptionalModule(loadRecharts);
197
+ const resolveColor = useCallback(
198
+ (color, index) => {
199
+ if (!color) return palette[index % palette.length];
200
+ if (/^[1-8]$/.test(color)) return palette[Number(color) - 1];
201
+ return color;
202
+ },
203
+ [palette]
204
+ );
205
+ const format = useMemo(() => getFormatter(valueFormat), [valueFormat]);
206
+ const rows = Array.isArray(data) ? data : [];
207
+ const seriesList = Array.isArray(series) ? series : [];
208
+ const shell = (body) => /* @__PURE__ */ jsx("div", { ref: hostRef, children: body });
209
+ if (recharts.status !== "ready") {
210
+ return shell(
211
+ /* @__PURE__ */ jsx(
212
+ DependencyPlaceholder,
213
+ {
214
+ packageName: "recharts",
215
+ purpose: "\uCC28\uD2B8",
216
+ height,
217
+ loading: recharts.status === "loading"
218
+ }
219
+ )
220
+ );
221
+ }
222
+ if (rows.length === 0 || seriesList.length === 0) {
223
+ return shell(
224
+ /* @__PURE__ */ jsx("div", { style: { minHeight: height, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(EmptyState, { tight: true, title: emptyText ?? "\uD45C\uC2DC\uD560 \uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4", children: "\uB370\uC774\uD130\uAC00 \uC9D1\uACC4\uB418\uBA74 \uCC28\uD2B8\uAC00 \uC5EC\uAE30\uC5D0 \uADF8\uB824\uC9D1\uB2C8\uB2E4." }) })
225
+ );
226
+ }
227
+ const {
228
+ Bar,
229
+ BarChart,
230
+ CartesianGrid,
231
+ Cell,
232
+ ComposedChart,
233
+ Line,
234
+ LineChart,
235
+ Pie,
236
+ PieChart,
237
+ ResponsiveContainer,
238
+ Tooltip,
239
+ XAxis,
240
+ YAxis
241
+ } = recharts.module;
242
+ const tooltipContent = (props) => renderTooltipContent(props, format);
243
+ if (type === "donut" || type === "pie") {
244
+ const nameKey = xKey ?? "name";
245
+ const valueKey = seriesList[0].key;
246
+ const sliceColor = (row, i) => resolveColor(typeof row.color === "string" ? row.color : void 0, i);
247
+ const legendItems2 = rows.map((row, i) => ({
248
+ label: String(row[nameKey] ?? `\uD56D\uBAA9 ${i + 1}`),
249
+ color: sliceColor(row, i)
250
+ }));
251
+ return shell(
252
+ /* @__PURE__ */ jsxs(Fragment, { children: [
253
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: "100%", height }, children: [
254
+ /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { children: [
255
+ /* @__PURE__ */ jsx(Tooltip, { content: tooltipContent }),
256
+ /* @__PURE__ */ jsx(
257
+ Pie,
258
+ {
259
+ data: rows,
260
+ dataKey: valueKey,
261
+ nameKey,
262
+ innerRadius: type === "donut" ? "60%" : 0,
263
+ outerRadius: "88%",
264
+ paddingAngle: type === "donut" ? 1 : 0,
265
+ stroke: "var(--wp-surface-card)",
266
+ strokeWidth: 2,
267
+ isAnimationActive: false,
268
+ children: rows.map((row, i) => /* @__PURE__ */ jsx(Cell, { fill: sliceColor(row, i) }, i))
269
+ }
270
+ )
271
+ ] }) }),
272
+ type === "donut" && donutCenter && /* @__PURE__ */ jsxs(
273
+ "div",
274
+ {
275
+ style: {
276
+ position: "absolute",
277
+ inset: 0,
278
+ display: "flex",
279
+ flexDirection: "column",
280
+ alignItems: "center",
281
+ justifyContent: "center",
282
+ gap: 2,
283
+ pointerEvents: "none",
284
+ textAlign: "center"
285
+ },
286
+ children: [
287
+ donutCenter.value !== void 0 && /* @__PURE__ */ jsx("span", { className: "wp-metric-sm", children: donutCenter.value }),
288
+ donutCenter.label !== void 0 && /* @__PURE__ */ jsx("span", { className: "wp-caption", children: donutCenter.label })
289
+ ]
290
+ }
291
+ )
292
+ ] }),
293
+ legend && /* @__PURE__ */ jsx(HtmlLegend, { items: legendItems2 })
294
+ ] })
295
+ );
296
+ }
297
+ const kindOf = (s) => {
298
+ if (type === "bar") return "bar";
299
+ if (type === "line") return s.kind === "dashed-line" ? "dashed-line" : "line";
300
+ return s.kind ?? "bar";
301
+ };
302
+ const lastInStack = /* @__PURE__ */ new Map();
303
+ seriesList.forEach((s, i) => {
304
+ if (kindOf(s) === "bar" && s.stack) lastInStack.set(s.stack, i);
305
+ });
306
+ const barRadius = (s, i) => !s.stack || lastInStack.get(s.stack) === i ? [3, 3, 0, 0] : [0, 0, 0, 0];
307
+ const hasBar = seriesList.some((s) => kindOf(s) === "bar");
308
+ const legendItems = seriesList.map((s, i) => ({
309
+ label: s.label ?? s.key,
310
+ color: resolveColor(s.color, i),
311
+ dashed: kindOf(s) === "dashed-line"
312
+ }));
313
+ const marks = seriesList.map((s, i) => {
314
+ const color = resolveColor(s.color, i);
315
+ const name = s.label ?? s.key;
316
+ if (kindOf(s) === "bar") {
317
+ return /* @__PURE__ */ jsx(
318
+ Bar,
319
+ {
320
+ dataKey: s.key,
321
+ name,
322
+ fill: color,
323
+ stackId: s.stack,
324
+ maxBarSize: 48,
325
+ radius: barRadius(s, i),
326
+ isAnimationActive: false
327
+ },
328
+ s.key
329
+ );
330
+ }
331
+ return /* @__PURE__ */ jsx(
332
+ Line,
333
+ {
334
+ type: "monotone",
335
+ dataKey: s.key,
336
+ name,
337
+ stroke: color,
338
+ strokeWidth: 2,
339
+ strokeDasharray: kindOf(s) === "dashed-line" ? "6 4" : void 0,
340
+ dot: false,
341
+ activeDot: { r: 4, strokeWidth: 2, stroke: "var(--wp-surface-card)" },
342
+ isAnimationActive: false
343
+ },
344
+ s.key
345
+ );
346
+ });
347
+ const axes = /* @__PURE__ */ jsxs(Fragment, { children: [
348
+ /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--wp-divider)", vertical: false }),
349
+ /* @__PURE__ */ jsx(
350
+ XAxis,
351
+ {
352
+ dataKey: xKey,
353
+ tickLine: false,
354
+ axisLine: { stroke: "var(--wp-border-subtle)" },
355
+ tick: axisTick,
356
+ tickMargin: 6
357
+ }
358
+ ),
359
+ /* @__PURE__ */ jsx(
360
+ YAxis,
361
+ {
362
+ tickLine: false,
363
+ axisLine: false,
364
+ tick: axisTick,
365
+ tickFormatter: (v) => format(v),
366
+ width: 52
367
+ }
368
+ ),
369
+ /* @__PURE__ */ jsx(
370
+ Tooltip,
371
+ {
372
+ cursor: hasBar ? { fill: "var(--wp-surface-sunken)", fillOpacity: 0.5 } : { stroke: "var(--wp-border-subtle)", strokeDasharray: "3 3" },
373
+ content: tooltipContent
374
+ }
375
+ )
376
+ ] });
377
+ const margin = { top: 8, right: 8, bottom: 0, left: 0 };
378
+ const cartesian = type === "bar" ? /* @__PURE__ */ jsxs(BarChart, { data: rows, margin, children: [
379
+ axes,
380
+ marks
381
+ ] }) : type === "line" ? /* @__PURE__ */ jsxs(LineChart, { data: rows, margin, children: [
382
+ axes,
383
+ marks
384
+ ] }) : /* @__PURE__ */ jsxs(ComposedChart, { data: rows, margin, children: [
385
+ axes,
386
+ marks
387
+ ] });
388
+ return shell(
389
+ /* @__PURE__ */ jsxs(Fragment, { children: [
390
+ /* @__PURE__ */ jsx("div", { style: { width: "100%", height }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: cartesian }) }),
391
+ legend && seriesList.length > 1 && /* @__PURE__ */ jsx(HtmlLegend, { items: legendItems })
392
+ ] })
393
+ );
394
+ }
395
+ var loadOl = async () => {
396
+ const [
397
+ map,
398
+ view,
399
+ tileLayer,
400
+ osm,
401
+ vectorLayer,
402
+ vectorSource,
403
+ feature,
404
+ point,
405
+ overlay,
406
+ style,
407
+ circle,
408
+ fill,
409
+ stroke,
410
+ proj,
411
+ extent,
412
+ controls,
413
+ interactions
414
+ ] = await Promise.all([
415
+ import('ol/Map'),
416
+ import('ol/View'),
417
+ import('ol/layer/Tile'),
418
+ import('ol/source/OSM'),
419
+ import('ol/layer/Vector'),
420
+ import('ol/source/Vector'),
421
+ import('ol/Feature'),
422
+ import('ol/geom/Point'),
423
+ import('ol/Overlay'),
424
+ import('ol/style/Style'),
425
+ import('ol/style/Circle'),
426
+ import('ol/style/Fill'),
427
+ import('ol/style/Stroke'),
428
+ import('ol/proj'),
429
+ import('ol/extent'),
430
+ import('ol/control/defaults'),
431
+ import('ol/interaction/defaults')
432
+ ]);
433
+ return {
434
+ Map: map.default,
435
+ View: view.default,
436
+ TileLayer: tileLayer.default,
437
+ OSM: osm.default,
438
+ VectorLayer: vectorLayer.default,
439
+ VectorSource: vectorSource.default,
440
+ Feature: feature.default,
441
+ Point: point.default,
442
+ Overlay: overlay.default,
443
+ Style: style.default,
444
+ CircleStyle: circle.default,
445
+ Fill: fill.default,
446
+ Stroke: stroke.default,
447
+ fromLonLat: proj.fromLonLat,
448
+ boundingExtent: extent.boundingExtent,
449
+ defaultControls: controls.defaults,
450
+ defaultInteractions: interactions.defaults
451
+ };
452
+ };
453
+ var ALWAYS_LABEL_MAX = 3;
454
+ var FIT_MAX_ZOOM = 16;
455
+ var DEFAULT_CENTER = [126.978, 37.5665];
456
+ var TONE_TOKENS = {
457
+ brand: { token: "--wp-action-primary-bg", fallback: "#1d2c60" },
458
+ danger: { token: "--wp-action-danger-bg", fallback: "#ca1a1d" },
459
+ info: { token: "--wp-text-info", fallback: "#0a63ad" }
460
+ };
461
+ function resolveToken(el, token, fallback) {
462
+ const value = getComputedStyle(el).getPropertyValue(token).trim();
463
+ return value !== "" ? value : fallback;
464
+ }
465
+ function createLabelElement(text) {
466
+ const el = document.createElement("div");
467
+ el.className = "wp-caption wp-map__label";
468
+ el.textContent = text;
469
+ Object.assign(el.style, {
470
+ background: "var(--wp-surface-card)",
471
+ color: "var(--wp-text-default)",
472
+ border: "1px solid var(--wp-border-subtle)",
473
+ borderRadius: "var(--wp-radius-sm)",
474
+ boxShadow: "var(--wp-shadow-sm)",
475
+ padding: "var(--wp-space-1) var(--wp-space-2)",
476
+ whiteSpace: "nowrap",
477
+ pointerEvents: "none"
478
+ });
479
+ return el;
480
+ }
481
+ function MapPreview({
482
+ markers,
483
+ center,
484
+ zoom,
485
+ height = 280,
486
+ interactive = true
487
+ }) {
488
+ const containerRef = useRef(null);
489
+ const [ready, setReady] = useState(false);
490
+ const ol = useOptionalModule(loadOl);
491
+ const olModule = ol.status === "ready" ? ol.module : null;
492
+ const markersKey = useMemo(() => JSON.stringify(Array.isArray(markers) ? markers : []), [markers]);
493
+ const centerLat = center?.lat;
494
+ const centerLng = center?.lng;
495
+ useEffect(() => {
496
+ const container = containerRef.current;
497
+ if (container === null || olModule === null) return;
498
+ const {
499
+ Map: OlMap,
500
+ View,
501
+ TileLayer,
502
+ OSM,
503
+ VectorLayer,
504
+ VectorSource,
505
+ Feature,
506
+ Point,
507
+ Overlay,
508
+ Style,
509
+ CircleStyle,
510
+ Fill,
511
+ Stroke,
512
+ fromLonLat,
513
+ boundingExtent,
514
+ defaultControls,
515
+ defaultInteractions
516
+ } = olModule;
517
+ const markerList = JSON.parse(markersKey);
518
+ const strokeColor = resolveToken(container, "--wp-white", "#ffffff");
519
+ const toneStyles = {};
520
+ Object.keys(TONE_TOKENS).forEach((tone) => {
521
+ const { token, fallback } = TONE_TOKENS[tone];
522
+ toneStyles[tone] = new Style({
523
+ image: new CircleStyle({
524
+ radius: 7,
525
+ fill: new Fill({ color: resolveToken(container, token, fallback) }),
526
+ stroke: new Stroke({ color: strokeColor, width: 2 })
527
+ })
528
+ });
529
+ });
530
+ const features = markerList.map((marker, index) => {
531
+ const feature = new Feature({ geometry: new Point(fromLonLat([marker.lng, marker.lat])) });
532
+ feature.set("markerIndex", index);
533
+ feature.setStyle(toneStyles[marker.tone ?? "brand"]);
534
+ return feature;
535
+ });
536
+ const map = new OlMap({
537
+ target: container,
538
+ layers: [new TileLayer({ source: new OSM() }), new VectorLayer({ source: new VectorSource({ features }) })],
539
+ // OSM 라이선스상 저작자 표기(Attribution)는 항상 유지한다.
540
+ controls: defaultControls({ attribution: true, rotate: false, zoom: interactive }),
541
+ interactions: interactive ? defaultInteractions() : defaultInteractions({
542
+ altShiftDragRotate: false,
543
+ doubleClickZoom: false,
544
+ dragPan: false,
545
+ keyboard: false,
546
+ mouseWheelZoom: false,
547
+ pinchRotate: false,
548
+ pinchZoom: false,
549
+ shiftDragZoom: false
550
+ }),
551
+ view: new View({
552
+ center: fromLonLat(
553
+ centerLat !== void 0 && centerLng !== void 0 ? [centerLng, centerLat] : markerList.length > 0 ? [markerList[0].lng, markerList[0].lat] : DEFAULT_CENTER
554
+ ),
555
+ zoom: zoom ?? (markerList.length === 0 ? 11 : 15)
556
+ })
557
+ });
558
+ if (centerLat === void 0 && markerList.length > 1) {
559
+ map.getView().fit(boundingExtent(markerList.map((marker) => fromLonLat([marker.lng, marker.lat]))), {
560
+ padding: [48, 48, 48, 48],
561
+ maxZoom: zoom ?? FIT_MAX_ZOOM
562
+ });
563
+ }
564
+ const alwaysShow = markerList.length <= ALWAYS_LABEL_MAX;
565
+ const overlays = new Array(markerList.length).fill(null);
566
+ markerList.forEach((marker, index) => {
567
+ if (marker.label === void 0 || marker.label === "") return;
568
+ const overlay = new Overlay({
569
+ element: createLabelElement(marker.label),
570
+ positioning: "bottom-center",
571
+ offset: [0, -12],
572
+ stopEvent: false
573
+ });
574
+ if (alwaysShow) overlay.setPosition(fromLonLat([marker.lng, marker.lat]));
575
+ map.addOverlay(overlay);
576
+ overlays[index] = overlay;
577
+ });
578
+ if (interactive && !alwaysShow) {
579
+ map.on("pointermove", (event) => {
580
+ const feature = map.forEachFeatureAtPixel(event.pixel, (hit) => hit);
581
+ const hoverIndex = feature !== void 0 && feature !== null ? feature.get("markerIndex") : -1;
582
+ overlays.forEach((overlay, index) => {
583
+ if (overlay === null) return;
584
+ const positioned = overlay;
585
+ if (index === hoverIndex) {
586
+ const marker = markerList[index];
587
+ positioned.setPosition(fromLonLat([marker.lng, marker.lat]));
588
+ } else {
589
+ positioned.setPosition(void 0);
590
+ }
591
+ });
592
+ map.getTargetElement().style.cursor = hoverIndex >= 0 ? "pointer" : "";
593
+ });
594
+ }
595
+ setReady(true);
596
+ return () => {
597
+ map.setTarget(void 0);
598
+ setReady(false);
599
+ };
600
+ }, [olModule, markersKey, centerLat, centerLng, zoom, interactive]);
601
+ if (ol.status !== "ready") {
602
+ return /* @__PURE__ */ jsx(
603
+ DependencyPlaceholder,
604
+ {
605
+ packageName: "ol",
606
+ purpose: "\uC704\uCE58 \uBBF8\uB9AC\uBCF4\uAE30 \uC9C0\uB3C4",
607
+ height,
608
+ loading: ol.status === "loading"
609
+ }
610
+ );
611
+ }
612
+ return /* @__PURE__ */ jsxs(
613
+ "figure",
614
+ {
615
+ className: "wp-map",
616
+ style: { display: "flex", flexDirection: "column", gap: "var(--wp-space-2)", margin: 0, width: "100%" },
617
+ children: [
618
+ /* @__PURE__ */ jsx(HoistedStyle, { id: "wp-mappreview", css: MAP_CSS }),
619
+ /* @__PURE__ */ jsxs(
620
+ "div",
621
+ {
622
+ style: {
623
+ position: "relative",
624
+ height,
625
+ width: "100%",
626
+ borderRadius: "var(--wp-radius-md)",
627
+ border: "1px solid var(--wp-border-subtle)",
628
+ overflow: "hidden",
629
+ background: "var(--wp-surface-sunken)"
630
+ },
631
+ children: [
632
+ /* @__PURE__ */ jsx(
633
+ "div",
634
+ {
635
+ ref: containerRef,
636
+ className: "wp-map__canvas",
637
+ "aria-label": "\uC704\uCE58 \uBBF8\uB9AC\uBCF4\uAE30 \uC9C0\uB3C4",
638
+ style: { position: "absolute", inset: 0 }
639
+ }
640
+ ),
641
+ !ready && /* @__PURE__ */ jsx(
642
+ "div",
643
+ {
644
+ style: {
645
+ position: "absolute",
646
+ inset: 0,
647
+ display: "flex",
648
+ alignItems: "center",
649
+ justifyContent: "center"
650
+ },
651
+ children: /* @__PURE__ */ jsx(Spinner, { label: "\uC9C0\uB3C4 \uC900\uBE44 \uC911" })
652
+ }
653
+ )
654
+ ]
655
+ }
656
+ ),
657
+ /* @__PURE__ */ jsx("figcaption", { className: "wp-caption", style: { color: "var(--wp-text-subtle)" }, children: "\uC9C0\uB3C4 \uD0C0\uC77C: OpenStreetMap \u2014 \uB124\uD2B8\uC6CC\uD06C \uBBF8\uC5F0\uACB0 \uC2DC \uD0C0\uC77C\uC774 \uD45C\uC2DC\uB418\uC9C0 \uC54A\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4" })
658
+ ]
659
+ }
660
+ );
661
+ }
662
+ var MAP_CSS = `
663
+ .wp-map .ol-viewport,.wp-map .ol-unselectable{-webkit-tap-highlight-color:transparent;user-select:none}
664
+ .wp-map .ol-selectable{user-select:text}
665
+ .wp-map .ol-grab{cursor:grab}
666
+ .wp-map .ol-grabbing{cursor:grabbing}
667
+ .wp-map .ol-control{position:absolute;display:flex;gap:2px;padding:2px;border-radius:var(--wp-radius-sm);background:rgba(255,255,255,0.72)}
668
+ .wp-map .ol-zoom{top:var(--wp-space-2);left:var(--wp-space-2);flex-direction:column}
669
+ .wp-map .ol-control button{display:flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;border:none;border-radius:var(--wp-radius-sm);background:var(--wp-action-primary-bg);color:var(--wp-action-primary-fg);font:inherit;font-size:14px;font-weight:700;line-height:1;cursor:pointer}
670
+ .wp-map .ol-control button:hover{background:var(--wp-action-primary-bg-hover)}
671
+ .wp-map .ol-control button:focus-visible{outline:2px solid var(--wp-border-focus);outline-offset:1px}
672
+ .wp-map .ol-attribution{right:var(--wp-space-2);bottom:var(--wp-space-2);max-width:calc(100% - 16px);flex-flow:row-reverse;align-items:center}
673
+ .wp-map .ol-attribution ul{display:flex;gap:var(--wp-space-2);margin:0;padding:0 var(--wp-space-1);list-style:none;font-size:10.5px;color:var(--wp-text-muted)}
674
+ .wp-map .ol-attribution a{color:var(--wp-text-link)}
675
+ .wp-map .ol-attribution.ol-collapsed ul{display:none}
676
+ `;
677
+
678
+ // src/rich.ts
679
+ var richComponents = {
680
+ Chart,
681
+ MapPreview
682
+ };
683
+
684
+ export { Chart, MapPreview, richComponents };