@wipco/sdui 0.15.0 → 0.16.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.
@@ -1,8 +1,7 @@
1
1
  import { IconButton } from './chunk-WIDDHR7L.js';
2
- import { boxed } from './chunk-SAN4IX6N.js';
3
2
  import { useState, useRef, useCallback, useEffect } from 'react';
4
3
  import { createPortal } from 'react-dom';
5
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
5
 
7
6
  var MIN_SCALE = 1;
8
7
  var MAX_SCALE = 8;
@@ -12,8 +11,7 @@ var INITIAL_VIEW = { scale: 1, x: 0, y: 0 };
12
11
  function clamp(value, min, max) {
13
12
  return Math.min(max, Math.max(min, value));
14
13
  }
15
- function ImageLightboxImpl({ src, alt, thumbClassName, thumbStyle, children }) {
16
- const [open, setOpen] = useState(false);
14
+ function ImageViewer({ src, alt, open, onClose }) {
17
15
  const [view, setView] = useState(INITIAL_VIEW);
18
16
  const [dragging, setDragging] = useState(false);
19
17
  const stageRef = useRef(null);
@@ -21,16 +19,11 @@ function ImageLightboxImpl({ src, alt, thumbClassName, thumbStyle, children }) {
21
19
  const viewRef = useRef(view);
22
20
  viewRef.current = view;
23
21
  const dragRef = useRef(null);
24
- const openViewer = (event) => {
25
- event.stopPropagation();
26
- setView(INITIAL_VIEW);
27
- setOpen(true);
28
- };
29
22
  const close = useCallback(() => {
30
23
  dragRef.current = null;
31
24
  setDragging(false);
32
- setOpen(false);
33
- }, []);
25
+ onClose();
26
+ }, [onClose]);
34
27
  const clampOffset = useCallback((x, y, scale) => {
35
28
  const stage = stageRef.current;
36
29
  const img = imgRef.current;
@@ -54,7 +47,11 @@ function ImageLightboxImpl({ src, alt, thumbClassName, thumbStyle, children }) {
54
47
  const cy = clientY - rect.top - rect.height / 2;
55
48
  const px = (cx - prev.x) / prev.scale;
56
49
  const py = (cy - prev.y) / prev.scale;
57
- const next = clampOffset(cx - px * nextScale, cy - py * nextScale, nextScale);
50
+ const next = clampOffset(
51
+ cx - px * nextScale,
52
+ cy - py * nextScale,
53
+ nextScale
54
+ );
58
55
  setView({ scale: nextScale, x: next.x, y: next.y });
59
56
  },
60
57
  [clampOffset]
@@ -69,6 +66,9 @@ function ImageLightboxImpl({ src, alt, thumbClassName, thumbStyle, children }) {
69
66
  [zoomAt]
70
67
  );
71
68
  const resetView = useCallback(() => setView(INITIAL_VIEW), []);
69
+ useEffect(() => {
70
+ if (open) setView(INITIAL_VIEW);
71
+ }, [open]);
72
72
  useEffect(() => {
73
73
  if (!open) return;
74
74
  const onKeyDown = (event) => {
@@ -117,7 +117,11 @@ function ImageLightboxImpl({ src, alt, thumbClassName, thumbStyle, children }) {
117
117
  const dx = event.clientX - drag.startX;
118
118
  const dy = event.clientY - drag.startY;
119
119
  if (Math.abs(dx) + Math.abs(dy) > DRAG_CLOSE_THRESHOLD) drag.moved = true;
120
- const next = clampOffset(drag.originX + dx, drag.originY + dy, viewRef.current.scale);
120
+ const next = clampOffset(
121
+ drag.originX + dx,
122
+ drag.originY + dy,
123
+ viewRef.current.scale
124
+ );
121
125
  setView((prev) => ({ ...prev, x: next.x, y: next.y }));
122
126
  };
123
127
  const endDrag = (event) => {
@@ -138,7 +142,8 @@ function ImageLightboxImpl({ src, alt, thumbClassName, thumbStyle, children }) {
138
142
  };
139
143
  const zoomPercent = Math.round(view.scale * 100);
140
144
  const isInitial = view.scale === 1 && view.x === 0 && view.y === 0;
141
- const overlay = open ? createPortal(
145
+ if (!open || typeof document === "undefined") return null;
146
+ return createPortal(
142
147
  /* @__PURE__ */ jsxs(
143
148
  "div",
144
149
  {
@@ -264,48 +269,7 @@ function ImageLightboxImpl({ src, alt, thumbClassName, thumbStyle, children }) {
264
269
  }
265
270
  ),
266
271
  document.body
267
- ) : null;
268
- if (children) {
269
- return /* @__PURE__ */ jsxs(Fragment, { children: [
270
- /* @__PURE__ */ jsx(
271
- "span",
272
- {
273
- style: { display: "contents" },
274
- onClick: openViewer,
275
- onKeyDown: (event) => {
276
- if (event.key === "Enter" || event.key === " ") {
277
- event.preventDefault();
278
- openViewer(event);
279
- }
280
- },
281
- children
282
- }
283
- ),
284
- overlay
285
- ] });
286
- }
287
- return /* @__PURE__ */ jsxs(Fragment, { children: [
288
- /* @__PURE__ */ jsx(
289
- "img",
290
- {
291
- src,
292
- alt: alt ?? "",
293
- role: "button",
294
- tabIndex: 0,
295
- className: thumbClassName,
296
- style: { cursor: "zoom-in", ...thumbStyle },
297
- onClick: openViewer,
298
- onKeyDown: (event) => {
299
- if (event.key === "Enter" || event.key === " ") {
300
- event.preventDefault();
301
- openViewer(event);
302
- }
303
- }
304
- }
305
- ),
306
- overlay
307
- ] });
272
+ );
308
273
  }
309
- var ImageLightbox = boxed(ImageLightboxImpl, "ImageLightbox");
310
274
 
311
- export { ImageLightbox };
275
+ export { ImageViewer };
@@ -0,0 +1,73 @@
1
+ import { ImageViewer } from './chunk-THEP3VWY.js';
2
+ import { boxed } from './chunk-SAN4IX6N.js';
3
+ import { useState } from 'react';
4
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
+
6
+ function ImageLightboxImpl({
7
+ src,
8
+ alt,
9
+ thumbClassName,
10
+ thumbStyle,
11
+ children
12
+ }) {
13
+ const [open, setOpen] = useState(false);
14
+ const openViewer = (event) => {
15
+ event.stopPropagation();
16
+ setOpen(true);
17
+ };
18
+ const overlay = /* @__PURE__ */ jsx(
19
+ ImageViewer,
20
+ {
21
+ src,
22
+ alt,
23
+ open,
24
+ onClose: () => setOpen(false)
25
+ }
26
+ );
27
+ if (children) {
28
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
29
+ /* @__PURE__ */ jsx(
30
+ "span",
31
+ {
32
+ style: { display: "contents" },
33
+ onClick: openViewer,
34
+ onKeyDown: (event) => {
35
+ if (event.key === "Enter" || event.key === " ") {
36
+ event.preventDefault();
37
+ openViewer(event);
38
+ }
39
+ },
40
+ children
41
+ }
42
+ ),
43
+ overlay
44
+ ] });
45
+ }
46
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
47
+ /* @__PURE__ */ jsx(
48
+ "img",
49
+ {
50
+ src,
51
+ alt: alt ?? "",
52
+ role: "button",
53
+ tabIndex: 0,
54
+ className: thumbClassName,
55
+ style: { cursor: "zoom-in", ...thumbStyle },
56
+ onClick: openViewer,
57
+ onKeyDown: (event) => {
58
+ if (event.key === "Enter" || event.key === " ") {
59
+ event.preventDefault();
60
+ openViewer(event);
61
+ }
62
+ }
63
+ }
64
+ ),
65
+ overlay
66
+ ] });
67
+ }
68
+ var ImageLightbox = boxed(
69
+ ImageLightboxImpl,
70
+ "ImageLightbox"
71
+ );
72
+
73
+ export { ImageLightbox };
package/dist/index.d.ts CHANGED
@@ -507,8 +507,8 @@ interface SduiNumberCell {
507
507
  *
508
508
  * **사진 값은 언제나 눌러서 크게 볼 수 있다.** 확대를 옵션으로 두면 스펙마다 켜고 끄는
509
509
  * 자리가 생기고, 켜지 않은 화면에서는 목록의 작은 썸네일이 사실상 못 보는 사진이 된다.
510
- * 원본 보기는 사진이라는 값 자체의 성질로 본다 — `Dialog`(코어)만 있으면 되므로
511
- * `widgets/ImageLightbox`를 끌어올 이유가 없다(코어는 위젯을 import하지 않는다).
510
+ * 원본 보기는 사진이라는 값 자체의 성질로 본다. 뷰어는 코어의 `ImageViewer` 하나뿐이라
511
+ * (휠 줌·드래그 패닝·툴바) 목록·카드 표지·상세 첨부가 전부 같게 동작한다.
512
512
  *
513
513
  * **크게 볼 수 있는 것은 실제로 뜬 사진뿐이다.** URL이 없으면, 그리고 URL이 있어도
514
514
  * 로딩이 실패하면(끊긴 링크·삭제된 객체) 자리표시자 상자로 떨어지고 눌리지 않는다 —
@@ -1741,4 +1741,34 @@ declare class NodeErrorBoundary extends React__default.Component<Props, State> {
1741
1741
  render(): string | number | bigint | boolean | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | React__default.JSX.Element | null | undefined;
1742
1742
  }
1743
1743
 
1744
- export { Actions, type ActionsProps, Alert, type AlertProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Can, type CanProps, Card, type CardProps, type CascadingSearchOption, Checkbox, type CheckboxProps, Col, type ColProps, type CustomActionHandler, type CustomValidator, DatePickerProps, DateRangePickerProps, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, Icon, IconButton, type IconButtonProps, type IconProps, Input, type InputProps, type Justify, type KeyValueItem, KeyValueList, type KeyValueListProps, type MeterTone, NodeErrorBoundary, PageHead, type PageHeadProps, Pagination, type PaginationProps, ProgressBar, type ProgressBarProps, Radio, type RadioProps, RemoteSearchResults, type RemoteSearchResultsProps, ResultTable, type ResultTableColumn, type ResultTableProps, Row, type RowProps, SduiAction, type SduiAdapter, type SduiAssetContext, type SduiAssetResolver, type SduiBadgeCell, SduiBoxProps, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, SduiColumnsScale, SduiContainerLayoutProps, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, SduiGapScale, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, type SduiImageCell, type SduiLinkCell, type SduiNumberCell, SduiPage, SduiPermissionProvider, type SduiProgressCell, SduiPropValue, type SduiRegistry, SduiRenderer, type SduiRendererProps, type SduiRowCondition, SduiRule, type SduiRuntime, type SduiSearchAction, type SduiSearchColumn, SduiSearchDataProvider, SduiSearchResults, type SduiSearchResultsProps, type SduiTagCell, SduiTextAlignScale, type SduiTextCell, SduiWeightScale, type SearchAction, type SearchColumn, type SearchFetcher, type SearchField, type SearchFilter, type SearchOption, type SearchPage, SearchResults, type SearchResultsProps, type SearchRow, SearchToolbar, type SearchValues, type SearchViewItem, Section, type SectionProps, SegmentedControl, type SegmentedControlProps, type SegmentedItem, Select, type SelectOption, type SelectOptionRecord, type SelectProps, Show, type ShowProps, SidebarNav, type SidebarNavItem, type SidebarNavProps, type SidebarNavSection, type SortDir, SortHandle, type SortHandleProps, SortableList, type SortableListProps, Spacer, type SpacerProps, type SpecIssue, Spinner, type SpinnerProps, StatCard, type StatCardProps, Switch, type SwitchProps, type TabItem, Table, type TableColumn, type TableProps, Tabs, type TabsProps, Tag, type TagProps, Text, type TextPreset, type TextProps, Textarea, type TextareaProps, Toast, type ToastProps, Tooltip, type TooltipProps, boxed, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, defaultAdapter, defaultRegistry, imageRenderer, includesLooseSearch, joinMultiValue, normalizePageSizes, normalizeSearchText, searchFieldKeys, searchValuesFromParams, sortableDropIndex, sortableMove, splitMultiValue, useRemoteSearchPage, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec };
1744
+ /**
1745
+ * 원본 보기 오버레이 — 사진을 크게 보는 단 하나의 구현.
1746
+ *
1747
+ * 목록 셀(`search/cells.tsx`)·카드 표지·상세의 첨부 사진(`widgets/ImageLightbox`)이
1748
+ * 전부 이것을 쓴다. 예전에는 위젯에만 있어서 코어의 셀은 확대를 흉내조차 낼 수 없었고,
1749
+ * 그 자리를 다른 방식(다이얼로그)으로 메우자 **같은 사진인데 화면마다 확대가 달랐다.**
1750
+ */
1751
+
1752
+ interface ImageViewerProps {
1753
+ /** 원본 이미지 URL */
1754
+ src: string;
1755
+ alt?: string;
1756
+ /** 열림 여부 — 트리거는 부르는 쪽이 소유한다 */
1757
+ open: boolean;
1758
+ onClose: () => void;
1759
+ }
1760
+ /**
1761
+ * 원본 보기 오버레이. 트리거(썸네일·표 칸·카드 표지…)는 부르는 쪽이 그리고,
1762
+ * 여기서는 **열린 뒤의 전부**를 맡는다 — 휠 줌(커서 앵커)·드래그 패닝·툴바·
1763
+ * Escape·배경 클릭·본문 스크롤 잠금.
1764
+ *
1765
+ * 사진을 크게 보는 자리가 화면마다 다르면 안 되므로(목록 셀·카드 표지·상세 첨부)
1766
+ * 구현은 여기 하나뿐이다. `widgets/ImageLightbox`도 이것을 감싼 트리거일 뿐이다.
1767
+ *
1768
+ * **포털이지만 React 이벤트는 트리거 쪽 트리로 버블한다** — 그래서 오버레이 뿌리에서
1769
+ * click·pointerdown·dblclick 전파를 끊는다. 이게 없으면 목록에서 연 뷰어의 사진을
1770
+ * 눌렀을 때 그 행의 rowClick(상세 이동)이 함께 발동한다.
1771
+ */
1772
+ declare function ImageViewer({ src, alt, open, onClose }: ImageViewerProps): React__default.ReactPortal | null;
1773
+
1774
+ export { Actions, type ActionsProps, Alert, type AlertProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Can, type CanProps, Card, type CardProps, type CascadingSearchOption, Checkbox, type CheckboxProps, Col, type ColProps, type CustomActionHandler, type CustomValidator, DatePickerProps, DateRangePickerProps, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, Icon, IconButton, type IconButtonProps, type IconProps, ImageViewer, type ImageViewerProps, Input, type InputProps, type Justify, type KeyValueItem, KeyValueList, type KeyValueListProps, type MeterTone, NodeErrorBoundary, PageHead, type PageHeadProps, Pagination, type PaginationProps, ProgressBar, type ProgressBarProps, Radio, type RadioProps, RemoteSearchResults, type RemoteSearchResultsProps, ResultTable, type ResultTableColumn, type ResultTableProps, Row, type RowProps, SduiAction, type SduiAdapter, type SduiAssetContext, type SduiAssetResolver, type SduiBadgeCell, SduiBoxProps, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, SduiColumnsScale, SduiContainerLayoutProps, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, SduiGapScale, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, type SduiImageCell, type SduiLinkCell, type SduiNumberCell, SduiPage, SduiPermissionProvider, type SduiProgressCell, SduiPropValue, type SduiRegistry, SduiRenderer, type SduiRendererProps, type SduiRowCondition, SduiRule, type SduiRuntime, type SduiSearchAction, type SduiSearchColumn, SduiSearchDataProvider, SduiSearchResults, type SduiSearchResultsProps, type SduiTagCell, SduiTextAlignScale, type SduiTextCell, SduiWeightScale, type SearchAction, type SearchColumn, type SearchFetcher, type SearchField, type SearchFilter, type SearchOption, type SearchPage, SearchResults, type SearchResultsProps, type SearchRow, SearchToolbar, type SearchValues, type SearchViewItem, Section, type SectionProps, SegmentedControl, type SegmentedControlProps, type SegmentedItem, Select, type SelectOption, type SelectOptionRecord, type SelectProps, Show, type ShowProps, SidebarNav, type SidebarNavItem, type SidebarNavProps, type SidebarNavSection, type SortDir, SortHandle, type SortHandleProps, SortableList, type SortableListProps, Spacer, type SpacerProps, type SpecIssue, Spinner, type SpinnerProps, StatCard, type StatCardProps, Switch, type SwitchProps, type TabItem, Table, type TableColumn, type TableProps, Tabs, type TabsProps, Tag, type TagProps, Text, type TextPreset, type TextProps, Textarea, type TextareaProps, Toast, type ToastProps, Tooltip, type TooltipProps, boxed, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, defaultAdapter, defaultRegistry, imageRenderer, includesLooseSearch, joinMultiValue, normalizePageSizes, normalizeSearchText, searchFieldKeys, searchValuesFromParams, sortableDropIndex, sortableMove, splitMultiValue, useRemoteSearchPage, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec };
package/dist/index.js CHANGED
@@ -1,14 +1,15 @@
1
1
  import { DEV, HoistedStyle, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, DateRangePicker, DatePicker, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-Q2EUB5UV.js';
2
2
  export { DatePicker, DateRangePicker, defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-Q2EUB5UV.js';
3
+ import { ImageViewer } from './chunk-THEP3VWY.js';
4
+ export { ImageViewer } from './chunk-THEP3VWY.js';
3
5
  import { normalizeSearchFields, searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-GZB6YLUI.js';
4
6
  export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-GZB6YLUI.js';
5
- import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagination, Icon, Card, Badge, ProgressBar, Tag, Dialog, Toast, Textarea, Tabs, Table, Switch, StatCard, Input, IconButton, Field, Alert, warnOnce } from './chunk-WIDDHR7L.js';
7
+ import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagination, Icon, Card, Badge, ProgressBar, Tag, Toast, Textarea, Tabs, Table, Switch, StatCard, Input, IconButton, Field, Alert, warnOnce, Dialog } from './chunk-WIDDHR7L.js';
6
8
  export { Alert, Avatar, Badge, Breadcrumb, Button, Card, Checkbox, Dialog, EmptyState, Field, Icon, IconButton, Input, Pagination, ProgressBar, Radio, SegmentedControl, Select, SidebarNav, Spinner, StatCard, Switch, Table, Tabs, Tag, Textarea, Toast, Tooltip } from './chunk-WIDDHR7L.js';
7
9
  import { boxed, mergeStyle, containerLayoutStyle, joinClass, columnsClass, typographyStyle, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-SAN4IX6N.js';
8
10
  export { CHILD_LAYOUT_PROPS, LAYOUT_CSS, boxed, childLayoutFrom, columnsClass, containerLayoutStyle, joinClass, mergeStyle, typographyStyle } from './chunk-SAN4IX6N.js';
9
11
  import React, { createContext, useState, useMemo, useContext, useRef, useEffect, useCallback } from 'react';
10
12
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
- import { createPortal } from 'react-dom';
12
13
 
13
14
  // src/asset-url.ts
14
15
  var FETCHING_URL_PROPS = /* @__PURE__ */ new Set([
@@ -320,29 +321,6 @@ function Show({ when, children }) {
320
321
  function Divider({ style, className }) {
321
322
  return /* @__PURE__ */ jsx("hr", { className: joinClass("wp-divider", className), style });
322
323
  }
323
- function SduiDialog(props) {
324
- const { onClose } = props;
325
- useEffect(() => {
326
- if (!onClose) return;
327
- const onKeyDown = (event) => {
328
- if (event.key === "Escape") onClose();
329
- };
330
- document.addEventListener("keydown", onKeyDown);
331
- return () => document.removeEventListener("keydown", onKeyDown);
332
- }, [onClose]);
333
- return /* @__PURE__ */ jsx(
334
- "div",
335
- {
336
- style: { position: "fixed", inset: 0, zIndex: "var(--wp-z-dialog)" },
337
- onClick: (event) => {
338
- if (onClose && event.target instanceof HTMLElement && event.target.classList.contains("wp-overlay")) {
339
- onClose();
340
- }
341
- },
342
- children: /* @__PURE__ */ jsx(Dialog, { ...props })
343
- }
344
- );
345
- }
346
324
  function imageRenderer(cell, key, width = cell.width ?? 72) {
347
325
  const height = cell.height ?? 52;
348
326
  return (row) => /* @__PURE__ */ jsx(
@@ -406,10 +384,7 @@ function ImageCellView({
406
384
  )
407
385
  }
408
386
  ),
409
- open && typeof document !== "undefined" ? createPortal(
410
- /* @__PURE__ */ jsx(SduiDialog, { size: "xl", title: alt || "\uC0AC\uC9C4", onClose: () => setOpen(false), children: /* @__PURE__ */ jsx("img", { className: "wp-imagecell__full", src: url, alt }) }),
411
- document.body
412
- ) : null
387
+ /* @__PURE__ */ jsx(ImageViewer, { src: url, alt, open, onClose: () => setOpen(false) })
413
388
  ] });
414
389
  }
415
390
  function toNumber(value) {
@@ -1380,6 +1355,29 @@ function RemoteSearchResultsImpl({
1380
1355
  }
1381
1356
  var SduiSearchResults = boxed(SduiSearchResultsImpl, "SduiSearchResults");
1382
1357
  var RemoteSearchResults = boxed(RemoteSearchResultsImpl, "RemoteSearchResults");
1358
+ function SduiDialog(props) {
1359
+ const { onClose } = props;
1360
+ useEffect(() => {
1361
+ if (!onClose) return;
1362
+ const onKeyDown = (event) => {
1363
+ if (event.key === "Escape") onClose();
1364
+ };
1365
+ document.addEventListener("keydown", onKeyDown);
1366
+ return () => document.removeEventListener("keydown", onKeyDown);
1367
+ }, [onClose]);
1368
+ return /* @__PURE__ */ jsx(
1369
+ "div",
1370
+ {
1371
+ style: { position: "fixed", inset: 0, zIndex: "var(--wp-z-dialog)" },
1372
+ onClick: (event) => {
1373
+ if (onClose && event.target instanceof HTMLElement && event.target.classList.contains("wp-overlay")) {
1374
+ onClose();
1375
+ }
1376
+ },
1377
+ children: /* @__PURE__ */ jsx(Dialog, { ...props })
1378
+ }
1379
+ );
1380
+ }
1383
1381
  var SduiRuntimeContext = createContext(null);
1384
1382
  function useSduiRuntime() {
1385
1383
  const runtime = useContext(SduiRuntimeContext);
package/dist/styles.css CHANGED
@@ -593,10 +593,6 @@
593
593
  border-radius: inherit;
594
594
  }
595
595
  .wp-imagecell__btn:focus-visible { outline: 2px solid var(--wp-navy-600); outline-offset: 2px; }
596
- .wp-imagecell__full {
597
- display: block; max-width: 100%; max-height: min(72vh, 720px); margin: 0 auto;
598
- object-fit: contain; border-radius: var(--wp-radius-md);
599
- }
600
596
  .wp-card__title { font-size: 14px; font-weight: 700; color: var(--wp-text-strong); }
601
597
  .wp-card__sub { font-size: 12px; color: var(--wp-text-muted); margin-top: 2px; }
602
598
  .wp-card__body { padding: 20px; display: flex; flex-direction: column; gap: var(--wp-space-4); min-width: 0; }
@@ -1,3 +1,4 @@
1
- export { ImageLightbox } from '../chunk-NYAZHZEG.js';
1
+ export { ImageLightbox } from '../chunk-XPBZMECW.js';
2
+ import '../chunk-THEP3VWY.js';
2
3
  import '../chunk-WIDDHR7L.js';
3
4
  import '../chunk-SAN4IX6N.js';
@@ -18,8 +18,8 @@ import { TreeView } from '../chunk-PYSTET2C.js';
18
18
  export { TreeView, buildTreeNodes } from '../chunk-PYSTET2C.js';
19
19
  import { EventCalendar } from '../chunk-C3JY6GA3.js';
20
20
  export { EventCalendar } from '../chunk-C3JY6GA3.js';
21
- import { ImageLightbox } from '../chunk-NYAZHZEG.js';
22
- export { ImageLightbox } from '../chunk-NYAZHZEG.js';
21
+ import { ImageLightbox } from '../chunk-XPBZMECW.js';
22
+ export { ImageLightbox } from '../chunk-XPBZMECW.js';
23
23
  import { InlineEdit } from '../chunk-KT3ZVBLN.js';
24
24
  export { InlineEdit } from '../chunk-KT3ZVBLN.js';
25
25
  import { JsonField } from '../chunk-JVBZRDC2.js';
@@ -32,6 +32,7 @@ import { PeriodFilter } from '../chunk-M3TDEPD2.js';
32
32
  export { PeriodFilter } from '../chunk-M3TDEPD2.js';
33
33
  import { PrintSheet } from '../chunk-MYJ2KEIP.js';
34
34
  export { PrintSheet } from '../chunk-MYJ2KEIP.js';
35
+ import '../chunk-THEP3VWY.js';
35
36
  export { AutocompleteField, toAutocompleteOptions } from '../chunk-3MS4UWWZ.js';
36
37
  import '../chunk-GZB6YLUI.js';
37
38
  import { ColumnBoard } from '../chunk-C4JRSZGS.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipco/sdui",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "WIPCO 서버 주도 UI(SDUI) 렌더러 — JSON 페이지 스펙을 React 컴포넌트로 렌더링",
5
5
  "keywords": [
6
6
  "sdui",