@wipco/sdui 1.5.0 → 1.6.1

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.
Files changed (143) hide show
  1. package/dist/{DatePicker-C_TT_SOw.d.ts → DatePicker-DX9juElE.d.ts} +10 -1
  2. package/dist/{chunk-7P7N43JV.js → chunk-34BABTH4.js} +2 -2
  3. package/dist/{chunk-DMLDKW7K.js → chunk-37BNG4DT.js} +1 -1
  4. package/dist/{chunk-5WW4MBRO.js → chunk-3JTBOABA.js} +6 -2
  5. package/dist/{chunk-HBIIEYKW.js → chunk-3PCR73OC.js} +4 -4
  6. package/dist/{chunk-VY7MVBSE.js → chunk-3PT5OBOU.js} +2 -2
  7. package/dist/{chunk-YVTV4ZV6.js → chunk-4YPPL7JK.js} +1 -1
  8. package/dist/{chunk-E6ISNQK3.js → chunk-6YBSBC77.js} +31 -8
  9. package/dist/{chunk-YWUDBLO6.js → chunk-7G6J6QFC.js} +2 -2
  10. package/dist/{chunk-UV6HHFEW.js → chunk-A57GKV5F.js} +129 -68
  11. package/dist/{chunk-I45EUZC6.js → chunk-AJ3KDBEE.js} +4 -2
  12. package/dist/chunk-BITS7UJY.js +333 -0
  13. package/dist/{chunk-DOL57OOP.js → chunk-BV37UCDF.js} +3 -3
  14. package/dist/chunk-CSZCWBOE.js +256 -0
  15. package/dist/{chunk-XGFDY43I.js → chunk-CUFGH3LB.js} +88 -18
  16. package/dist/{chunk-A6LAIGUS.js → chunk-EGFDELSF.js} +7 -4
  17. package/dist/{chunk-JIV4YHCZ.js → chunk-EJIWOD7W.js} +1 -1
  18. package/dist/{chunk-CXW6KT6X.js → chunk-ESAFQXEU.js} +3 -3
  19. package/dist/{chunk-N5RKM6IC.js → chunk-EUSC5NMZ.js} +4 -4
  20. package/dist/{chunk-RWSH2MBU.js → chunk-FP32LNFK.js} +73 -19
  21. package/dist/{chunk-44TDRCKR.js → chunk-GKYUDTMI.js} +5 -5
  22. package/dist/chunk-GSM664TX.js +38 -0
  23. package/dist/{chunk-I5SD7XRA.js → chunk-GSXD52XG.js} +3 -3
  24. package/dist/{chunk-O4IISNE7.js → chunk-IB2ZPUTF.js} +51 -12
  25. package/dist/{chunk-YOZN35HD.js → chunk-IIRVHSNK.js} +3 -3
  26. package/dist/{chunk-FNMS7OB7.js → chunk-J7BZF4T4.js} +5 -5
  27. package/dist/{chunk-KO6OEY3G.js → chunk-JHFA5RDN.js} +3 -13
  28. package/dist/{chunk-DKVSM5HX.js → chunk-KDKRFWIF.js} +6 -6
  29. package/dist/chunk-KO3EUNWB.js +380 -0
  30. package/dist/{chunk-JYAR7D5U.js → chunk-NLSR3JYU.js} +2 -2
  31. package/dist/{chunk-ZORQPB6B.js → chunk-O4EMQWCV.js} +325 -360
  32. package/dist/{chunk-2HLXCKK7.js → chunk-OCYJ2ZOV.js} +2 -2
  33. package/dist/{chunk-OQ52XMGG.js → chunk-OKNF2SBB.js} +4 -4
  34. package/dist/{chunk-GNA6SX2H.js → chunk-OQ7A3SFM.js} +2 -2
  35. package/dist/{chunk-A5XQOEVH.js → chunk-PCFH74RD.js} +4 -4
  36. package/dist/{chunk-BEM2YS7U.js → chunk-SGGIWPP6.js} +3 -3
  37. package/dist/{chunk-NIJUVTEW.js → chunk-TB7G5DXQ.js} +3 -3
  38. package/dist/{chunk-GZBY7I4Y.js → chunk-TWUKNUUQ.js} +66 -10
  39. package/dist/{chunk-WPSK2CB5.js → chunk-UC725BGW.js} +16 -5
  40. package/dist/{chunk-ZFNFPXPR.js → chunk-US3K6Q5T.js} +2 -2
  41. package/dist/{chunk-MPT7WJG2.js → chunk-USNPJEXH.js} +5 -5
  42. package/dist/{chunk-SAPBDJJQ.js → chunk-UZZLMPRW.js} +2 -2
  43. package/dist/{chunk-Q4SWUINA.js → chunk-VAXRTBJH.js} +1 -1
  44. package/dist/{chunk-RYBBPFI7.js → chunk-VQKX5PJ4.js} +4 -4
  45. package/dist/chunk-VR5MFUD2.js +106 -0
  46. package/dist/{chunk-JZXU22PE.js → chunk-VSNHDHGS.js} +208 -117
  47. package/dist/{chunk-2YP5N4VV.js → chunk-VZOQRQAR.js} +1 -1
  48. package/dist/{chunk-AXGF4M57.js → chunk-XAXROQKB.js} +1 -1
  49. package/dist/{chunk-IZ3JA2BR.js → chunk-XFKNU6QN.js} +3 -3
  50. package/dist/{chunk-GTGS2QRL.js → chunk-XUVWIRZJ.js} +3 -3
  51. package/dist/{chunk-RNOUXUBO.js → chunk-YYAGE733.js} +323 -59
  52. package/dist/index.d.ts +449 -91
  53. package/dist/index.js +1060 -138
  54. package/dist/{layout-C3nRXMwb.d.ts → layout-DmRikwZb.d.ts} +5 -4
  55. package/dist/meta.d.ts +1 -1
  56. package/dist/meta.js +351 -25
  57. package/dist/rich/ExcelUploadCard.d.ts +1 -1
  58. package/dist/rich/ExcelUploadCard.js +5 -4
  59. package/dist/rich.d.ts +22 -3
  60. package/dist/rich.js +304 -35
  61. package/dist/styles.css +119 -4
  62. package/dist/{types-COjGKgmd.d.ts → types-CMikpoN5.d.ts} +65 -2
  63. package/dist/widgets/ApprovalLineEditor.d.ts +1 -1
  64. package/dist/widgets/ApprovalLineEditor.js +9 -8
  65. package/dist/widgets/ApprovalOverridesEditor.d.ts +1 -1
  66. package/dist/widgets/ApprovalOverridesEditor.js +11 -10
  67. package/dist/widgets/ApprovalStepper.d.ts +29 -4
  68. package/dist/widgets/ApprovalStepper.js +3 -3
  69. package/dist/widgets/AutocompleteField.d.ts +1 -1
  70. package/dist/widgets/AutocompleteField.js +9 -8
  71. package/dist/widgets/ColumnBoard.d.ts +1 -1
  72. package/dist/widgets/ColumnBoard.js +3 -3
  73. package/dist/widgets/DiffView.d.ts +1 -1
  74. package/dist/widgets/DiffView.js +3 -3
  75. package/dist/widgets/Disclosure.d.ts +1 -1
  76. package/dist/widgets/Disclosure.js +3 -3
  77. package/dist/widgets/EventCalendar.d.ts +5 -1
  78. package/dist/widgets/EventCalendar.js +5 -3
  79. package/dist/widgets/FileDropzone.d.ts +1 -1
  80. package/dist/widgets/FileDropzone.js +9 -7
  81. package/dist/widgets/ImageLightbox.d.ts +1 -1
  82. package/dist/widgets/ImageLightbox.js +7 -5
  83. package/dist/widgets/InlineEdit.d.ts +1 -1
  84. package/dist/widgets/InlineEdit.js +3 -3
  85. package/dist/widgets/JsonField.d.ts +1 -1
  86. package/dist/widgets/JsonField.js +3 -3
  87. package/dist/widgets/LiveClock.d.ts +1 -1
  88. package/dist/widgets/LiveClock.js +2 -2
  89. package/dist/widgets/OptionSchemaEditor.d.ts +1 -1
  90. package/dist/widgets/OptionSchemaEditor.js +4 -4
  91. package/dist/widgets/OptionValueFields.d.ts +1 -1
  92. package/dist/widgets/OptionValueFields.js +4 -4
  93. package/dist/widgets/OrgChart.d.ts +1 -1
  94. package/dist/widgets/OrgChart.js +4 -4
  95. package/dist/widgets/OrgChartBoard.d.ts +15 -33
  96. package/dist/widgets/OrgChartBoard.js +10 -8
  97. package/dist/widgets/PeriodFilter.d.ts +1 -1
  98. package/dist/widgets/PeriodFilter.js +6 -5
  99. package/dist/widgets/PermissionMatrixEditor.d.ts +34 -2
  100. package/dist/widgets/PermissionMatrixEditor.js +6 -4
  101. package/dist/widgets/PositionSelect.d.ts +1 -1
  102. package/dist/widgets/PositionSelect.js +5 -4
  103. package/dist/widgets/PrintSheet.d.ts +15 -2
  104. package/dist/widgets/PrintSheet.js +3 -3
  105. package/dist/widgets/ProfileEditDiffCard.d.ts +1 -1
  106. package/dist/widgets/ProfileEditDiffCard.js +5 -4
  107. package/dist/widgets/QRDisplay.d.ts +1 -1
  108. package/dist/widgets/QRDisplay.js +5 -4
  109. package/dist/widgets/RankBoard.d.ts +1 -1
  110. package/dist/widgets/RankBoard.js +8 -6
  111. package/dist/widgets/RecordSheet.d.ts +1 -1
  112. package/dist/widgets/RecordSheet.js +2 -2
  113. package/dist/widgets/RoleMemberPicker.d.ts +1 -1
  114. package/dist/widgets/RoleMemberPicker.js +6 -5
  115. package/dist/widgets/SearchableMultiPicker.d.ts +1 -1
  116. package/dist/widgets/SearchableMultiPicker.js +7 -6
  117. package/dist/widgets/SecureScreen.d.ts +1 -1
  118. package/dist/widgets/SecureScreen.js +3 -3
  119. package/dist/widgets/StackedMeter.d.ts +1 -1
  120. package/dist/widgets/StackedMeter.js +2 -2
  121. package/dist/widgets/StagePeriodEditor.d.ts +1 -1
  122. package/dist/widgets/StagePeriodEditor.js +6 -5
  123. package/dist/widgets/Strip.d.ts +1 -1
  124. package/dist/widgets/Strip.js +2 -2
  125. package/dist/widgets/SummaryTable.d.ts +1 -1
  126. package/dist/widgets/SummaryTable.js +2 -2
  127. package/dist/widgets/TagInput.d.ts +1 -1
  128. package/dist/widgets/TagInput.js +3 -3
  129. package/dist/widgets/TagMultiSelect.d.ts +1 -1
  130. package/dist/widgets/TagMultiSelect.js +5 -4
  131. package/dist/widgets/Timeline.d.ts +1 -1
  132. package/dist/widgets/Timeline.js +4 -4
  133. package/dist/widgets/TreePicker.d.ts +1 -1
  134. package/dist/widgets/TreePicker.js +8 -7
  135. package/dist/widgets/TreeView.d.ts +17 -3
  136. package/dist/widgets/TreeView.js +7 -6
  137. package/dist/widgets/index.d.ts +3 -3
  138. package/dist/widgets/index.js +84 -83
  139. package/package.json +1 -1
  140. package/dist/chunk-LFEJLOFN.js +0 -352
  141. package/dist/chunk-MMIGOPO5.js +0 -111
  142. package/dist/chunk-TFGNKFL2.js +0 -39
  143. package/dist/chunk-XQPTSEJC.js +0 -135
@@ -0,0 +1,333 @@
1
+ import { HoistedStyle } from './chunk-RIZRM7OO.js';
2
+ import { MOBILE_MEDIA_QUERY } from './chunk-GSM664TX.js';
3
+ import React, { useSyncExternalStore, useRef, useEffect } from 'react';
4
+ import { createPortal } from 'react-dom';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ var OVERLAY_ROOT_ID = "wp-overlay-root";
8
+ function isMobileViewport() {
9
+ return typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(MOBILE_MEDIA_QUERY).matches : false;
10
+ }
11
+ var DOCUMENT_POSITION_FOLLOWING = 4;
12
+ function getOverlayRoot() {
13
+ if (typeof document === "undefined") return null;
14
+ const existing = document.getElementById(OVERLAY_ROOT_ID);
15
+ if (existing) return existing;
16
+ const created = document.createElement("div");
17
+ created.id = OVERLAY_ROOT_ID;
18
+ document.body.appendChild(created);
19
+ return created;
20
+ }
21
+ var layers = [];
22
+ var nextId = 0;
23
+ var subscribers = /* @__PURE__ */ new Set();
24
+ var keyListenerBound = false;
25
+ function emit() {
26
+ layers = layers.slice();
27
+ subscribers.forEach((fn) => fn());
28
+ }
29
+ function topLayer(list) {
30
+ let best;
31
+ let bestNode = null;
32
+ for (const layer of list) {
33
+ const node = layer.node();
34
+ if (!best) {
35
+ best = layer;
36
+ bestNode = node;
37
+ continue;
38
+ }
39
+ if (!node) continue;
40
+ if (!bestNode) {
41
+ best = layer;
42
+ bestNode = node;
43
+ continue;
44
+ }
45
+ if (bestNode.compareDocumentPosition(node) & DOCUMENT_POSITION_FOLLOWING) {
46
+ best = layer;
47
+ bestNode = node;
48
+ }
49
+ }
50
+ return best;
51
+ }
52
+ function layerHoldsTop(list, id) {
53
+ const top = topLayer(list);
54
+ if (!top) return false;
55
+ if (top.id === id) return true;
56
+ const mine = list.find((l) => l.id === id)?.node();
57
+ const topNode = top.node();
58
+ return !!mine && !!topNode && mine.contains(topNode);
59
+ }
60
+ function escapeTopmost() {
61
+ topLayer(layers)?.onEscape();
62
+ }
63
+ function handleKeyDown(event) {
64
+ if (event.key === "Tab") {
65
+ trapTab(event);
66
+ return;
67
+ }
68
+ if (event.key !== "Escape") return;
69
+ escapeTopmost();
70
+ }
71
+ var TABBABLE = 'a[href], area[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), iframe, [contenteditable="true"], [tabindex]:not([tabindex="-1"])';
72
+ function tabbablesIn(root) {
73
+ return Array.from(root.querySelectorAll(TABBABLE)).filter((el) => {
74
+ if (el.tabIndex < 0) return false;
75
+ if (el.closest("[inert]")) return false;
76
+ return typeof el.getClientRects !== "function" || el.getClientRects().length > 0 || !hasLayout();
77
+ });
78
+ }
79
+ function hasLayout() {
80
+ return typeof document !== "undefined" && document.documentElement.getClientRects().length > 0;
81
+ }
82
+ function topModal() {
83
+ return topLayer(layers.filter((layer) => layer.modal));
84
+ }
85
+ function trapTab(event) {
86
+ const modal = topModal();
87
+ const root = modal?.node();
88
+ if (!modal || !root) return;
89
+ const active = typeof document !== "undefined" ? document.activeElement : null;
90
+ if (active instanceof HTMLElement && !root.contains(active) && active.closest(".wp-anchored-pop")) return;
91
+ const stops = tabbablesIn(root);
92
+ const container = root.querySelector('[role="dialog"]');
93
+ if (stops.length === 0) {
94
+ event.preventDefault();
95
+ (container ?? root).focus?.();
96
+ return;
97
+ }
98
+ const first = stops[0];
99
+ const last = stops[stops.length - 1];
100
+ const inside = active instanceof HTMLElement && root.contains(active);
101
+ if (!inside) {
102
+ event.preventDefault();
103
+ (event.shiftKey ? last : first).focus();
104
+ return;
105
+ }
106
+ if (event.shiftKey && (active === first || active === container)) {
107
+ event.preventDefault();
108
+ last.focus();
109
+ } else if (!event.shiftKey && active === last) {
110
+ event.preventDefault();
111
+ first.focus();
112
+ }
113
+ }
114
+ var FIELD = "input, select, textarea";
115
+ var TEXT_INPUT_TYPES = /* @__PURE__ */ new Set(["", "text", "search", "email", "tel", "url", "number", "password"]);
116
+ function isPlainTextField(el) {
117
+ if (el.matches(":disabled") || el.hasAttribute("readonly")) return false;
118
+ if (el.getAttribute("aria-haspopup") || el.getAttribute("role") === "combobox") return false;
119
+ if (el.tagName === "INPUT") return TEXT_INPUT_TYPES.has((el.getAttribute("type") ?? "").toLowerCase());
120
+ return true;
121
+ }
122
+ function initialFocusTarget(root, preferField) {
123
+ const explicit = root.querySelector("[autofocus], [data-autofocus]");
124
+ if (explicit) return explicit;
125
+ const container = root.querySelector('[role="dialog"]');
126
+ if (preferField) {
127
+ const body = root.querySelector(".wp-dialog__body") ?? container ?? root;
128
+ const firstField = Array.from(body.querySelectorAll(FIELD)).find(
129
+ (el) => !(el.tagName === "INPUT" && el.getAttribute("type") === "hidden") && !el.closest("[inert]")
130
+ );
131
+ if (firstField && isPlainTextField(firstField)) return firstField;
132
+ }
133
+ if (container) {
134
+ if (!container.hasAttribute("tabindex")) container.setAttribute("tabindex", "-1");
135
+ return container;
136
+ }
137
+ return tabbablesIn(root)[0] ?? null;
138
+ }
139
+ var pendingRestores = [];
140
+ var restoreTimer = null;
141
+ function scheduleRestore(target) {
142
+ if (target) pendingRestores.push(target);
143
+ if (restoreTimer) return;
144
+ restoreTimer = setTimeout(() => {
145
+ restoreTimer = null;
146
+ const candidates = pendingRestores;
147
+ pendingRestores = [];
148
+ const active = document.activeElement;
149
+ if (active && active !== document.body && active.isConnected) return;
150
+ const target2 = [...candidates].reverse().find((el) => el.isConnected);
151
+ if (target2) {
152
+ target2.focus({ preventScroll: true });
153
+ return;
154
+ }
155
+ const root = topModal()?.node();
156
+ if (root) initialFocusTarget(root, !isMobileViewport())?.focus({ preventScroll: true });
157
+ }, 0);
158
+ }
159
+ function takeRestoreTarget() {
160
+ const inherited = [...pendingRestores].reverse().find((el) => el.isConnected);
161
+ if (inherited) {
162
+ pendingRestores = pendingRestores.filter((el) => el !== inherited);
163
+ return inherited;
164
+ }
165
+ if (typeof document === "undefined") return null;
166
+ const active = document.activeElement;
167
+ return active instanceof HTMLElement && active !== document.body ? active : null;
168
+ }
169
+ var HISTORY_MARK = "__wpModal";
170
+ var TOKEN_PREFIX = Date.now().toString(36);
171
+ var tokenSeq = 0;
172
+ var pushedToken = "";
173
+ var historyPushed = false;
174
+ var pushedPath = "";
175
+ var pushedLength = 0;
176
+ var ignorePops = 0;
177
+ var popBound = false;
178
+ var reconcileTimer = null;
179
+ function historyModals() {
180
+ return layers.filter((layer) => layer.modal && layer.history);
181
+ }
182
+ function canUseHistory() {
183
+ return typeof window !== "undefined" && typeof window.history?.pushState === "function";
184
+ }
185
+ function pushHistoryEntry() {
186
+ if (historyPushed || !canUseHistory() || !isMobileViewport()) return;
187
+ const current = window.history.state;
188
+ tokenSeq += 1;
189
+ pushedToken = `${TOKEN_PREFIX}-${tokenSeq}`;
190
+ window.history.pushState({ ...current ?? {}, [HISTORY_MARK]: pushedToken }, "", window.location.href);
191
+ historyPushed = true;
192
+ pushedPath = window.location.pathname;
193
+ pushedLength = window.history.length;
194
+ if (!popBound) {
195
+ window.addEventListener("popstate", handlePopState);
196
+ popBound = true;
197
+ }
198
+ }
199
+ function reconcileHistory() {
200
+ reconcileTimer = null;
201
+ if (!canUseHistory()) return;
202
+ const open = historyModals().length > 0;
203
+ if (open && !historyPushed) {
204
+ pushHistoryEntry();
205
+ return;
206
+ }
207
+ if (!open && historyPushed) {
208
+ historyPushed = false;
209
+ if (window.location.pathname === pushedPath && window.history.length === pushedLength) {
210
+ ignorePops += 1;
211
+ window.history.back();
212
+ }
213
+ }
214
+ }
215
+ function scheduleReconcile(delay = 0) {
216
+ if (!canUseHistory()) return;
217
+ if (reconcileTimer) clearTimeout(reconcileTimer);
218
+ reconcileTimer = setTimeout(reconcileHistory, delay);
219
+ }
220
+ function handlePopState() {
221
+ if (ignorePops > 0) {
222
+ ignorePops -= 1;
223
+ return;
224
+ }
225
+ if (!historyPushed) return;
226
+ const landed = window.history.state;
227
+ if (landed?.[HISTORY_MARK] === pushedToken) return;
228
+ historyPushed = false;
229
+ if (historyModals().length === 0) return;
230
+ escapeTopmost();
231
+ scheduleReconcile(300);
232
+ }
233
+ function push(layer) {
234
+ layers.push(layer);
235
+ if (!keyListenerBound && typeof document !== "undefined") {
236
+ document.addEventListener("keydown", handleKeyDown);
237
+ keyListenerBound = true;
238
+ }
239
+ if (layer.modal && layer.history) pushHistoryEntry();
240
+ emit();
241
+ }
242
+ function remove(id) {
243
+ const removed = layers.find((l) => l.id === id);
244
+ layers = layers.filter((l) => l.id !== id);
245
+ if (removed?.modal && removed.history) scheduleReconcile();
246
+ emit();
247
+ }
248
+ function subscribe(fn) {
249
+ subscribers.add(fn);
250
+ return () => {
251
+ subscribers.delete(fn);
252
+ };
253
+ }
254
+ var snapshot = () => layers;
255
+ var serverSnapshot = () => [];
256
+ function useOverlayLayer(active, onEscape, nodeRef) {
257
+ return useLayer(active, onEscape, nodeRef, false, false);
258
+ }
259
+ var anyModalSnapshot = () => layers.some((layer) => layer.modal === true);
260
+ var anyModalServerSnapshot = () => false;
261
+ function useAnyModalOpen() {
262
+ return useSyncExternalStore(subscribe, anyModalSnapshot, anyModalServerSnapshot);
263
+ }
264
+ function useLayer(active, onEscape, nodeRef, modal, history) {
265
+ const idRef = useRef(0);
266
+ if (idRef.current === 0) idRef.current = ++nextId;
267
+ const escapeRef = useRef(onEscape);
268
+ escapeRef.current = onEscape;
269
+ const nodeRefRef = useRef(nodeRef);
270
+ nodeRefRef.current = nodeRef;
271
+ useEffect(() => {
272
+ if (!active) return;
273
+ const id2 = idRef.current;
274
+ push({
275
+ id: id2,
276
+ onEscape: () => escapeRef.current?.(),
277
+ node: () => nodeRefRef.current?.current ?? null,
278
+ modal,
279
+ history
280
+ });
281
+ return () => remove(id2);
282
+ }, [active, modal, history]);
283
+ const current = useSyncExternalStore(subscribe, snapshot, serverSnapshot);
284
+ const id = idRef.current;
285
+ return {
286
+ isTop: active && topLayer(current)?.id === id,
287
+ holdsTop: active && layerHoldsTop(current, id)
288
+ };
289
+ }
290
+ var OverlayContainerContext = React.createContext(null);
291
+ function OverlayLayer({
292
+ onClose,
293
+ children
294
+ }) {
295
+ const ref = useRef(null);
296
+ const container = React.useContext(OverlayContainerContext);
297
+ const { holdsTop } = useLayer(true, onClose, ref, true, container === null);
298
+ const restoreRef = useRef(null);
299
+ useEffect(() => {
300
+ restoreRef.current = takeRestoreTarget();
301
+ return () => scheduleRestore(restoreRef.current);
302
+ }, []);
303
+ const focusedRef = useRef(false);
304
+ useEffect(() => {
305
+ const root2 = ref.current;
306
+ root2?.toggleAttribute("inert", !holdsTop);
307
+ if (!root2 || !holdsTop || focusedRef.current) return;
308
+ focusedRef.current = true;
309
+ if (document.activeElement && root2.contains(document.activeElement)) return;
310
+ initialFocusTarget(root2, !isMobileViewport())?.focus({ preventScroll: true });
311
+ }, [holdsTop]);
312
+ const layer = /* @__PURE__ */ jsxs(
313
+ "div",
314
+ {
315
+ ref,
316
+ className: "wp-overlay-layer",
317
+ onClick: (event) => {
318
+ if (onClose && event.target instanceof HTMLElement && event.target.classList.contains("wp-overlay")) {
319
+ onClose();
320
+ }
321
+ },
322
+ children: [
323
+ /* @__PURE__ */ jsx(HoistedStyle, { id: "wp-overlay-focus", css: OVERLAY_FOCUS_CSS }),
324
+ children
325
+ ]
326
+ }
327
+ );
328
+ const root = container ?? getOverlayRoot();
329
+ return root ? createPortal(layer, root) : layer;
330
+ }
331
+ var OVERLAY_FOCUS_CSS = `.wp-overlay-layer [role="dialog"][tabindex="-1"]:focus{outline:none}`;
332
+
333
+ export { OverlayContainerContext, OverlayLayer, getOverlayRoot, useAnyModalOpen, useOverlayLayer };
@@ -1,7 +1,7 @@
1
1
  import { fetchAllJobPositions } from './chunk-XRHR452N.js';
2
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-KO6OEY3G.js';
3
- import { Select, Button } from './chunk-RNOUXUBO.js';
4
- import { boxed } from './chunk-5WW4MBRO.js';
2
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-JHFA5RDN.js';
3
+ import { Select, Button } from './chunk-YYAGE733.js';
4
+ import { boxed } from './chunk-3JTBOABA.js';
5
5
  import { useRef, useState, useEffect, useMemo } from 'react';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
7
 
@@ -0,0 +1,256 @@
1
+ import { useRef, useState, useCallback, useEffect } from 'react';
2
+
3
+ // src/widgets/usePanZoomCanvas.ts
4
+ var MIN_ZOOM = 0.35;
5
+ var MAX_ZOOM = 1.8;
6
+ var PINCH_CLICK_GRACE_MS = 400;
7
+ var PAN_SLOP_PX = 6;
8
+ var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
9
+ function applyZoom(current, nextScale, focal) {
10
+ const scale = clamp(nextScale, MIN_ZOOM, MAX_ZOOM);
11
+ return {
12
+ scale,
13
+ x: focal.x - (focal.x - current.x) / current.scale * scale,
14
+ y: focal.y - (focal.y - current.y) / current.scale * scale
15
+ };
16
+ }
17
+ function applyPinch(start, startDistance, startMid, distance, mid) {
18
+ const ratio = startDistance > 0 ? distance / startDistance : 1;
19
+ const zoomed = applyZoom(start, start.scale * ratio, startMid);
20
+ return { ...zoomed, x: zoomed.x + mid.x - startMid.x, y: zoomed.y + mid.y - startMid.y };
21
+ }
22
+ function usePanZoomCanvas(options) {
23
+ const { stopSelector, initialView } = options;
24
+ const viewportRef = useRef(null);
25
+ const dragRef = useRef(null);
26
+ const interactedRef = useRef(false);
27
+ const pointersRef = useRef(/* @__PURE__ */ new Map());
28
+ const pinchRef = useRef(null);
29
+ const pendingRef = useRef(null);
30
+ const gestureEndedAtRef = useRef(0);
31
+ const dragFromStopRef = useRef(false);
32
+ const viewRef = useRef(initialView);
33
+ const [view, setViewState] = useState(initialView);
34
+ const setView = useCallback((next) => {
35
+ setViewState((current) => {
36
+ const resolved = typeof next === "function" ? next(current) : next;
37
+ viewRef.current = resolved;
38
+ return resolved;
39
+ });
40
+ }, []);
41
+ const [dragging, setDragging] = useState(false);
42
+ const [nativeFullscreen, setNativeFullscreen] = useState(false);
43
+ const [pseudoFullscreen, setPseudoFullscreen] = useState(false);
44
+ const isFullscreen = nativeFullscreen || pseudoFullscreen;
45
+ useEffect(() => {
46
+ const handleFullscreenChange = () => {
47
+ setNativeFullscreen(document.fullscreenElement === viewportRef.current);
48
+ };
49
+ document.addEventListener("fullscreenchange", handleFullscreenChange);
50
+ return () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
51
+ }, []);
52
+ useEffect(() => {
53
+ if (!pseudoFullscreen) return;
54
+ const onKey = (event) => {
55
+ if (event.key === "Escape") setPseudoFullscreen(false);
56
+ };
57
+ document.addEventListener("keydown", onKey);
58
+ return () => document.removeEventListener("keydown", onKey);
59
+ }, [pseudoFullscreen]);
60
+ useEffect(() => {
61
+ const viewport = viewportRef.current;
62
+ if (!viewport) return;
63
+ const onTouchMove = (event) => {
64
+ if (event.touches.length >= 2 && event.cancelable) event.preventDefault();
65
+ };
66
+ viewport.addEventListener("touchmove", onTouchMove, { passive: false });
67
+ return () => viewport.removeEventListener("touchmove", onTouchMove);
68
+ }, []);
69
+ useEffect(() => {
70
+ const viewport = viewportRef.current;
71
+ if (!viewport) return;
72
+ const onWheel = (event) => {
73
+ event.preventDefault();
74
+ interactedRef.current = true;
75
+ const rect = viewport.getBoundingClientRect();
76
+ const focal = { x: event.clientX - rect.left, y: event.clientY - rect.top };
77
+ setView(
78
+ (current) => applyZoom(current, current.scale * (event.deltaY > 0 ? 0.9 : 1.1), focal)
79
+ );
80
+ };
81
+ viewport.addEventListener("wheel", onWheel, { passive: false });
82
+ return () => viewport.removeEventListener("wheel", onWheel);
83
+ }, []);
84
+ const viewportCenter = useCallback(() => {
85
+ const rect = viewportRef.current?.getBoundingClientRect();
86
+ if (!rect) return { x: 0, y: 0 };
87
+ return { x: rect.width / 2, y: rect.height / 2 };
88
+ }, []);
89
+ const zoomAt = useCallback((nextScale, focal) => {
90
+ interactedRef.current = true;
91
+ setView((current) => applyZoom(current, nextScale, focal));
92
+ }, []);
93
+ const localPoint = (event) => {
94
+ const rect = event.currentTarget.getBoundingClientRect();
95
+ return { x: event.clientX - rect.left, y: event.clientY - rect.top };
96
+ };
97
+ const pinchGeometry = () => {
98
+ const [a, b] = [...pointersRef.current.values()];
99
+ return {
100
+ distance: Math.hypot(b.x - a.x, b.y - a.y),
101
+ mid: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 }
102
+ };
103
+ };
104
+ const restartPan = (pointerId, point, event) => {
105
+ const rect = event.currentTarget.getBoundingClientRect();
106
+ dragRef.current = {
107
+ pointerId,
108
+ startX: point.x + rect.left,
109
+ startY: point.y + rect.top,
110
+ originX: viewRef.current.x,
111
+ originY: viewRef.current.y
112
+ };
113
+ dragFromStopRef.current = true;
114
+ };
115
+ const capturePointer = (event, pointerId) => {
116
+ try {
117
+ event.currentTarget.setPointerCapture(pointerId);
118
+ } catch {
119
+ }
120
+ };
121
+ const startPan = (event, pointerId, start, fromStop) => {
122
+ interactedRef.current = true;
123
+ dragRef.current = {
124
+ pointerId,
125
+ startX: start.x,
126
+ startY: start.y,
127
+ originX: viewRef.current.x,
128
+ originY: viewRef.current.y
129
+ };
130
+ dragFromStopRef.current = fromStop;
131
+ setDragging(true);
132
+ capturePointer(event, pointerId);
133
+ };
134
+ const handlePointerDown = (event) => {
135
+ const onStop = Boolean(event.target.closest(stopSelector));
136
+ if (onStop && event.pointerType !== "touch") return;
137
+ pointersRef.current.set(event.pointerId, localPoint(event));
138
+ if (pointersRef.current.size === 2) {
139
+ interactedRef.current = true;
140
+ dragRef.current = null;
141
+ pendingRef.current = null;
142
+ const { distance, mid } = pinchGeometry();
143
+ pinchRef.current = { start: viewRef.current, distance, mid };
144
+ for (const pointerId of pointersRef.current.keys()) capturePointer(event, pointerId);
145
+ setDragging(true);
146
+ return;
147
+ }
148
+ if (pointersRef.current.size > 2) return;
149
+ if (onStop || event.pointerType === "touch" && !isFullscreen) {
150
+ pendingRef.current = { pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, fromStop: onStop };
151
+ return;
152
+ }
153
+ startPan(event, event.pointerId, { x: event.clientX, y: event.clientY }, false);
154
+ };
155
+ const handleClickCapture = (event) => {
156
+ const dragFromStop = dragRef.current !== null && dragFromStopRef.current;
157
+ if (pinchRef.current || dragFromStop || Date.now() - gestureEndedAtRef.current < PINCH_CLICK_GRACE_MS) {
158
+ event.preventDefault();
159
+ event.stopPropagation();
160
+ }
161
+ };
162
+ const handlePointerMove = (event) => {
163
+ if (!pointersRef.current.has(event.pointerId)) return;
164
+ pointersRef.current.set(event.pointerId, localPoint(event));
165
+ const pinch = pinchRef.current;
166
+ if (pinch && pointersRef.current.size >= 2) {
167
+ const { distance, mid } = pinchGeometry();
168
+ setView(applyPinch(pinch.start, pinch.distance, pinch.mid, distance, mid));
169
+ return;
170
+ }
171
+ const pending = pendingRef.current;
172
+ if (pending && pending.pointerId === event.pointerId) {
173
+ const dx = event.clientX - pending.startX;
174
+ const dy = event.clientY - pending.startY;
175
+ if (Math.hypot(dx, dy) < PAN_SLOP_PX) return;
176
+ pendingRef.current = null;
177
+ if (!isFullscreen && Math.abs(dy) > Math.abs(dx)) return;
178
+ startPan(event, event.pointerId, { x: pending.startX, y: pending.startY }, pending.fromStop);
179
+ }
180
+ const drag = dragRef.current;
181
+ if (!drag || drag.pointerId !== event.pointerId) return;
182
+ setView((current) => ({
183
+ ...current,
184
+ x: drag.originX + event.clientX - drag.startX,
185
+ y: drag.originY + event.clientY - drag.startY
186
+ }));
187
+ };
188
+ const handlePointerUp = (event) => {
189
+ if (!pointersRef.current.has(event.pointerId)) return;
190
+ pointersRef.current.delete(event.pointerId);
191
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
192
+ event.currentTarget.releasePointerCapture(event.pointerId);
193
+ }
194
+ if (pendingRef.current?.pointerId === event.pointerId) pendingRef.current = null;
195
+ if (pinchRef.current && pointersRef.current.size < 2) {
196
+ pinchRef.current = null;
197
+ gestureEndedAtRef.current = Date.now();
198
+ const rest = [...pointersRef.current.entries()][0];
199
+ if (rest) restartPan(rest[0], rest[1], event);
200
+ }
201
+ if (dragRef.current?.pointerId === event.pointerId) {
202
+ if (dragFromStopRef.current) gestureEndedAtRef.current = Date.now();
203
+ dragRef.current = null;
204
+ dragFromStopRef.current = false;
205
+ }
206
+ if (pointersRef.current.size === 0) {
207
+ dragRef.current = null;
208
+ dragFromStopRef.current = false;
209
+ setDragging(false);
210
+ }
211
+ };
212
+ const toggleFullscreen = async () => {
213
+ const viewport = viewportRef.current;
214
+ if (!viewport) return;
215
+ if (pseudoFullscreen) {
216
+ setPseudoFullscreen(false);
217
+ return;
218
+ }
219
+ if (document.fullscreenElement === viewport) {
220
+ try {
221
+ await document.exitFullscreen();
222
+ } catch {
223
+ }
224
+ return;
225
+ }
226
+ try {
227
+ if (typeof viewport.requestFullscreen !== "function") throw new Error("unsupported");
228
+ await viewport.requestFullscreen();
229
+ } catch {
230
+ setPseudoFullscreen(true);
231
+ }
232
+ };
233
+ return {
234
+ viewportRef,
235
+ view,
236
+ setView,
237
+ dragging,
238
+ isFullscreen,
239
+ /** 브라우저 전체화면 대신 화면을 덮는 고정 배치로 들어가 있는가(위젯이 배치 클래스를 붙인다). */
240
+ pseudoFullscreen,
241
+ interactedRef,
242
+ viewportCenter,
243
+ zoomAt,
244
+ toggleFullscreen,
245
+ /** 뷰포트 div에 그대로 spread — 패닝 4종 + 핀치 직후 click 차단. */
246
+ pointerHandlers: {
247
+ onPointerDown: handlePointerDown,
248
+ onPointerMove: handlePointerMove,
249
+ onPointerUp: handlePointerUp,
250
+ onPointerCancel: handlePointerUp,
251
+ onClickCapture: handleClickCapture
252
+ }
253
+ };
254
+ }
255
+
256
+ export { MAX_ZOOM, MIN_ZOOM, usePanZoomCanvas };