pith-ui 0.1.1 → 0.2.0-app.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.
- package/AI.md +33 -8
- package/API.md +424 -268
- package/APP-API.md +2019 -0
- package/APP.md +137 -0
- package/README.md +37 -4
- package/dist/app/files.d.ts +68 -0
- package/dist/app/files.d.ts.map +1 -0
- package/dist/app/files.js +177 -0
- package/dist/app/files.js.map +1 -0
- package/dist/app/index.d.ts +57 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +300 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/internal.d.ts +31 -0
- package/dist/app/internal.d.ts.map +1 -0
- package/dist/app/internal.js +2 -0
- package/dist/app/internal.js.map +1 -0
- package/dist/app/resources.d.ts +89 -0
- package/dist/app/resources.d.ts.map +1 -0
- package/dist/app/resources.js +190 -0
- package/dist/app/resources.js.map +1 -0
- package/dist/app/session.d.ts +14 -0
- package/dist/app/session.d.ts.map +1 -0
- package/dist/app/session.js +12 -0
- package/dist/app/session.js.map +1 -0
- package/dist/app/settings.d.ts +109 -0
- package/dist/app/settings.d.ts.map +1 -0
- package/dist/app/settings.js +279 -0
- package/dist/app/settings.js.map +1 -0
- package/dist/app/workspace.d.ts +228 -0
- package/dist/app/workspace.d.ts.map +1 -0
- package/dist/app/workspace.js +402 -0
- package/dist/app/workspace.js.map +1 -0
- package/dist/composer.d.ts.map +1 -1
- package/dist/composer.js +37 -27
- package/dist/composer.js.map +1 -1
- package/dist/content/conversation-reader.d.ts.map +1 -1
- package/dist/content/conversation-reader.js +8 -1
- package/dist/content/conversation-reader.js.map +1 -1
- package/dist/content/conversation-view.d.ts.map +1 -1
- package/dist/content/conversation-view.js +34 -8
- package/dist/content/conversation-view.js.map +1 -1
- package/dist/content/image-viewer.d.ts.map +1 -1
- package/dist/content/image-viewer.js +11 -3
- package/dist/content/image-viewer.js.map +1 -1
- package/dist/content/paged-preview.d.ts +1 -1
- package/dist/content/paged-preview.d.ts.map +1 -1
- package/dist/content/paged-preview.js +4 -2
- package/dist/content/paged-preview.js.map +1 -1
- package/dist/content/views.d.ts +3 -0
- package/dist/content/views.d.ts.map +1 -1
- package/dist/content/views.js +110 -41
- package/dist/content/views.js.map +1 -1
- package/dist/content/welcome.d.ts.map +1 -1
- package/dist/content/welcome.js +5 -2
- package/dist/content/welcome.js.map +1 -1
- package/dist/dom.js +1 -1
- package/dist/dom.js.map +1 -1
- package/dist/files/panels.d.ts +2 -0
- package/dist/files/panels.d.ts.map +1 -1
- package/dist/files/panels.js +202 -128
- package/dist/files/panels.js.map +1 -1
- package/dist/files/systems.d.ts.map +1 -1
- package/dist/files/systems.js +37 -64
- package/dist/files/systems.js.map +1 -1
- package/dist/forms/actions.d.ts +24 -2
- package/dist/forms/actions.d.ts.map +1 -1
- package/dist/forms/actions.js +54 -25
- package/dist/forms/actions.js.map +1 -1
- package/dist/forms/custom-connection.d.ts.map +1 -1
- package/dist/forms/custom-connection.js +3 -2
- package/dist/forms/custom-connection.js.map +1 -1
- package/dist/forms/history.d.ts +1 -1
- package/dist/forms/history.d.ts.map +1 -1
- package/dist/forms/history.js +78 -15
- package/dist/forms/history.js.map +1 -1
- package/dist/forms/identity.d.ts.map +1 -1
- package/dist/forms/identity.js +9 -25
- package/dist/forms/identity.js.map +1 -1
- package/dist/forms/model-editor.js +3 -3
- package/dist/forms/model-editor.js.map +1 -1
- package/dist/forms/panels.d.ts +9 -2
- package/dist/forms/panels.d.ts.map +1 -1
- package/dist/forms/panels.js +79 -88
- package/dist/forms/panels.js.map +1 -1
- package/dist/forms/provider-login.d.ts.map +1 -1
- package/dist/forms/provider-login.js +20 -36
- package/dist/forms/provider-login.js.map +1 -1
- package/dist/forms/resource-editor.js +5 -4
- package/dist/forms/resource-editor.js.map +1 -1
- package/dist/foundations.d.ts +1 -1
- package/dist/foundations.d.ts.map +1 -1
- package/dist/foundations.js +22 -38
- package/dist/foundations.js.map +1 -1
- package/dist/navigation/context-menu.d.ts +7 -1
- package/dist/navigation/context-menu.d.ts.map +1 -1
- package/dist/navigation/context-menu.js +60 -57
- package/dist/navigation/context-menu.js.map +1 -1
- package/dist/navigation/navigation.d.ts +13 -0
- package/dist/navigation/navigation.d.ts.map +1 -1
- package/dist/navigation/navigation.js +96 -130
- package/dist/navigation/navigation.js.map +1 -1
- package/dist/operation.d.ts +12 -0
- package/dist/operation.d.ts.map +1 -0
- package/dist/operation.js +49 -0
- package/dist/operation.js.map +1 -0
- package/dist/primitives.d.ts +8 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +114 -143
- package/dist/primitives.js.map +1 -1
- package/dist/reconcile.d.ts +11 -0
- package/dist/reconcile.d.ts.map +1 -0
- package/dist/reconcile.js +36 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/select.d.ts +14 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +304 -0
- package/dist/select.js.map +1 -0
- package/dist/styles.css +439 -370
- package/dist/surface.d.ts +31 -0
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js +193 -3
- package/dist/surface.js.map +1 -1
- package/dist/tasks/approval.d.ts.map +1 -1
- package/dist/tasks/approval.js +83 -45
- package/dist/tasks/approval.js.map +1 -1
- package/dist/tasks/permission-element.d.ts +3 -0
- package/dist/tasks/permission-element.d.ts.map +1 -0
- package/dist/tasks/permission-element.js +10 -0
- package/dist/tasks/permission-element.js.map +1 -0
- package/dist/tasks/permission.d.ts.map +1 -1
- package/dist/tasks/permission.js +37 -18
- package/dist/tasks/permission.js.map +1 -1
- package/dist/tasks/runtime.d.ts.map +1 -1
- package/dist/tasks/runtime.js +32 -15
- package/dist/tasks/runtime.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +93 -40
- package/dist/workspace.js.map +1 -1
- package/package.json +42 -8
package/dist/surface.d.ts
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
interface AnchoredSurfaceOptions {
|
|
2
|
+
trigger: HTMLElement;
|
|
3
|
+
panel: HTMLElement;
|
|
4
|
+
closeOnFocusOut?: boolean;
|
|
5
|
+
exclusions?: readonly Node[];
|
|
6
|
+
onToggle?: (open: boolean, restoreFocus?: boolean) => void;
|
|
7
|
+
position?: boolean;
|
|
8
|
+
canOpen?: () => boolean;
|
|
9
|
+
canEscape?: () => boolean;
|
|
10
|
+
getAnchor?: () => Pick<DOMRect, 'left' | 'right' | 'top' | 'bottom' | 'width' | 'height'>;
|
|
11
|
+
anchorElement?: HTMLElement;
|
|
12
|
+
dismissOnMove?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface AnchoredSurface {
|
|
15
|
+
open(): void;
|
|
16
|
+
close(restoreFocus?: boolean): void;
|
|
17
|
+
isOpen(): boolean;
|
|
18
|
+
destroy(): void;
|
|
19
|
+
}
|
|
20
|
+
/** Shared nonmodal surface ownership. Retained panels can keep their own layout;
|
|
21
|
+
* anchored panels use the native top layer to escape scroll/overflow containers.
|
|
22
|
+
*/
|
|
23
|
+
export declare function installAnchoredSurface(options: AnchoredSurfaceOptions): AnchoredSurface;
|
|
24
|
+
/** A content block can request closure without guessing its eventual frame ID. */
|
|
25
|
+
export declare function bindContentClose(owner: HTMLElement, options?: {
|
|
26
|
+
dialogId?: string;
|
|
27
|
+
onClose?: () => void;
|
|
28
|
+
}): {
|
|
29
|
+
destroy(): void;
|
|
30
|
+
};
|
|
1
31
|
export interface DialogLifecycleOptions {
|
|
2
32
|
closeOnBackdrop?: boolean;
|
|
3
33
|
canClose?: () => boolean;
|
|
@@ -26,4 +56,5 @@ export declare function installMenuNavigation(menu: HTMLElement, options: MenuNa
|
|
|
26
56
|
focus(edge?: 'first' | 'last'): void;
|
|
27
57
|
destroy(): void;
|
|
28
58
|
};
|
|
59
|
+
export {};
|
|
29
60
|
//# sourceMappingURL=surface.d.ts.map
|
package/dist/surface.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACvC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AACD,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,OAAO,CAAC;IAClB,OAAO,IAAI,IAAI,CAAC;CACjB;AA2BD,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE,sBAA2B,GAAG,eAAe,CA0EvH;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,KAAK,OAAO,CAAC;CACtC;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,qBAAqB,GAAG;IAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,IAAI,IAAI,CAAA;CAAE,CAsBlJ"}
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"AAEA,UAAU,sBAAsB;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;IAC1F,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AACD,UAAU,eAAe;IACvB,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,MAAM,IAAI,OAAO,CAAC;IAClB,OAAO,IAAI,IAAI,CAAC;CACjB;AAGD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CA2GvF;AASD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,GAAG;IAAE,OAAO,IAAI,IAAI,CAAA;CAAE,CAcnI;AAED,MAAM,WAAW,sBAAsB;IACrC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACvC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AACD,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,OAAO,CAAC;IAClB,OAAO,IAAI,IAAI,CAAC;CACjB;AA2BD,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE,sBAA2B,GAAG,eAAe,CA0EvH;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,KAAK,OAAO,CAAC;CACtC;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,qBAAqB,GAAG;IAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,IAAI,IAAI,CAAA;CAAE,CAsBlJ"}
|
package/dist/surface.js
CHANGED
|
@@ -1,4 +1,194 @@
|
|
|
1
1
|
import { Lifetime } from './core.js';
|
|
2
|
+
const floatingStacks = new WeakMap();
|
|
3
|
+
/** Shared nonmodal surface ownership. Retained panels can keep their own layout;
|
|
4
|
+
* anchored panels use the native top layer to escape scroll/overflow containers.
|
|
5
|
+
*/
|
|
6
|
+
export function installAnchoredSurface(options) {
|
|
7
|
+
const { trigger, panel } = options;
|
|
8
|
+
const doc = trigger.ownerDocument, view = doc.defaultView;
|
|
9
|
+
const position = options.position !== false;
|
|
10
|
+
const originalPopover = panel.getAttribute('popover');
|
|
11
|
+
const originalStyle = panel.getAttribute('style');
|
|
12
|
+
const topLayer = position && typeof panel.showPopover === 'function';
|
|
13
|
+
if (topLayer)
|
|
14
|
+
panel.setAttribute('popover', 'manual');
|
|
15
|
+
if (position)
|
|
16
|
+
panel.dataset.puiFloating = '';
|
|
17
|
+
let opened = false, disposed = false, events;
|
|
18
|
+
const stack = floatingStacks.get(doc) ?? [];
|
|
19
|
+
floatingStacks.set(doc, stack);
|
|
20
|
+
panel.hidden = true;
|
|
21
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
22
|
+
const contains = (target) => target instanceof Node &&
|
|
23
|
+
(trigger.contains(target) || panel.contains(target) || options.exclusions?.some(node => node.contains(target)));
|
|
24
|
+
const style = (name, value) => { if (panel.style.getPropertyValue(name) !== value)
|
|
25
|
+
panel.style.setProperty(name, value); };
|
|
26
|
+
const place = () => {
|
|
27
|
+
if (!opened || !position)
|
|
28
|
+
return;
|
|
29
|
+
if (!trigger.isConnected || !trigger.getClientRects().length) {
|
|
30
|
+
close();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const anchor = options.getAnchor?.() ?? options.anchorElement?.getBoundingClientRect() ?? trigger.getBoundingClientRect();
|
|
34
|
+
const viewport = view.visualViewport;
|
|
35
|
+
const left = viewport?.offsetLeft ?? 0, top = viewport?.offsetTop ?? 0;
|
|
36
|
+
const width = viewport?.width ?? doc.documentElement.clientWidth;
|
|
37
|
+
const height = viewport?.height ?? doc.documentElement.clientHeight;
|
|
38
|
+
const gap = parseFloat(view.getComputedStyle(panel).getPropertyValue('--pui-space-sm')) || 8;
|
|
39
|
+
const margin = gap;
|
|
40
|
+
style('max-width', `${Math.max(0, width - margin * 2)}px`);
|
|
41
|
+
style('min-width', `${Math.min(anchor.width, Math.max(0, width - margin * 2))}px`);
|
|
42
|
+
// scrollHeight measures the content without expanding the viewport first.
|
|
43
|
+
// Expanding a scrolled list would clamp scrollTop and hide its active item.
|
|
44
|
+
const scrollTop = panel.scrollTop, scrollLeft = panel.scrollLeft;
|
|
45
|
+
const desired = Math.min(panel.scrollHeight + 2, 320);
|
|
46
|
+
const below = top + height - anchor.bottom - margin - gap;
|
|
47
|
+
const above = anchor.top - top - margin - gap;
|
|
48
|
+
const upwards = below < desired && above > below;
|
|
49
|
+
const available = Math.max(0, upwards ? above : below);
|
|
50
|
+
style('max-height', `${Math.min(320, available)}px`);
|
|
51
|
+
const bounds = panel.getBoundingClientRect();
|
|
52
|
+
const horizontal = anchor.left + bounds.width > left + width - margin ? anchor.right - bounds.width : anchor.left;
|
|
53
|
+
style('left', `${Math.max(left + margin, Math.min(horizontal, left + width - margin - bounds.width))}px`);
|
|
54
|
+
style('top', `${upwards ? Math.max(top + margin, anchor.top - gap - bounds.height) : anchor.bottom + gap}px`);
|
|
55
|
+
panel.scrollTop = scrollTop;
|
|
56
|
+
panel.scrollLeft = scrollLeft;
|
|
57
|
+
};
|
|
58
|
+
function close(restoreFocus = false) {
|
|
59
|
+
if (!opened)
|
|
60
|
+
return;
|
|
61
|
+
opened = false;
|
|
62
|
+
events?.destroy();
|
|
63
|
+
events = undefined;
|
|
64
|
+
const index = stack.indexOf(handle);
|
|
65
|
+
if (index >= 0)
|
|
66
|
+
stack.splice(index, 1);
|
|
67
|
+
if (topLayer && panel.matches(':popover-open'))
|
|
68
|
+
panel.hidePopover();
|
|
69
|
+
panel.hidden = true;
|
|
70
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
71
|
+
options.onToggle?.(false, restoreFocus);
|
|
72
|
+
if (restoreFocus && trigger.isConnected && !trigger.matches(':disabled'))
|
|
73
|
+
trigger.focus({ preventScroll: true });
|
|
74
|
+
}
|
|
75
|
+
const handle = {
|
|
76
|
+
open() {
|
|
77
|
+
if (disposed || opened || options.canOpen?.() === false || !trigger.isConnected || !trigger.getClientRects().length)
|
|
78
|
+
return;
|
|
79
|
+
opened = true;
|
|
80
|
+
panel.hidden = false;
|
|
81
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
82
|
+
stack.push(handle);
|
|
83
|
+
if (topLayer)
|
|
84
|
+
panel.showPopover();
|
|
85
|
+
place();
|
|
86
|
+
if (!opened)
|
|
87
|
+
return;
|
|
88
|
+
events = new Lifetime();
|
|
89
|
+
const outside = (event) => { if (!contains(event.target))
|
|
90
|
+
close(); };
|
|
91
|
+
events.listen(doc, 'pointerdown', outside, { capture: true });
|
|
92
|
+
events.listen(doc, 'click', outside, { capture: true });
|
|
93
|
+
if (options.closeOnFocusOut !== false) {
|
|
94
|
+
events.listen(doc, 'focusin', outside, { capture: true });
|
|
95
|
+
const blur = (event) => {
|
|
96
|
+
// Native pointer focus can briefly expose body between focusout and
|
|
97
|
+
// focusin. Its related target already identifies an internal move.
|
|
98
|
+
if (contains(event.relatedTarget))
|
|
99
|
+
return;
|
|
100
|
+
queueMicrotask(() => { if (opened && !contains(doc.activeElement))
|
|
101
|
+
close(); });
|
|
102
|
+
};
|
|
103
|
+
events.listen(trigger, 'focusout', blur);
|
|
104
|
+
events.listen(panel, 'focusout', blur);
|
|
105
|
+
}
|
|
106
|
+
events.listen(doc, 'keydown', (event => {
|
|
107
|
+
const key = event;
|
|
108
|
+
if (key.key !== 'Escape' || stack.at(-1) !== handle || options.canEscape?.() === false)
|
|
109
|
+
return;
|
|
110
|
+
const modal = [...doc.querySelectorAll('dialog[open]')].at(-1);
|
|
111
|
+
if (modal && !modal.contains(trigger))
|
|
112
|
+
return;
|
|
113
|
+
key.preventDefault();
|
|
114
|
+
key.stopPropagation();
|
|
115
|
+
close(true);
|
|
116
|
+
}), { capture: true });
|
|
117
|
+
if (position) {
|
|
118
|
+
const move = () => { if (options.dismissOnMove)
|
|
119
|
+
close();
|
|
120
|
+
else
|
|
121
|
+
place(); };
|
|
122
|
+
events.listen(view, 'resize', move);
|
|
123
|
+
events.listen(doc, 'scroll', event => { if (!(event.target instanceof Node) || !panel.contains(event.target))
|
|
124
|
+
move(); }, { capture: true });
|
|
125
|
+
if (view.visualViewport) {
|
|
126
|
+
events.listen(view.visualViewport, 'resize', move);
|
|
127
|
+
events.listen(view.visualViewport, 'scroll', move);
|
|
128
|
+
}
|
|
129
|
+
const observer = new ResizeObserver(place);
|
|
130
|
+
observer.observe(trigger);
|
|
131
|
+
observer.observe(panel);
|
|
132
|
+
if (options.anchorElement && options.anchorElement !== trigger)
|
|
133
|
+
observer.observe(options.anchorElement);
|
|
134
|
+
events.add(() => observer.disconnect());
|
|
135
|
+
}
|
|
136
|
+
options.onToggle?.(true);
|
|
137
|
+
},
|
|
138
|
+
close,
|
|
139
|
+
isOpen: () => opened,
|
|
140
|
+
destroy() {
|
|
141
|
+
if (disposed)
|
|
142
|
+
return;
|
|
143
|
+
close();
|
|
144
|
+
disposed = true;
|
|
145
|
+
if (position) {
|
|
146
|
+
delete panel.dataset.puiFloating;
|
|
147
|
+
if (originalStyle === null)
|
|
148
|
+
panel.removeAttribute('style');
|
|
149
|
+
else
|
|
150
|
+
panel.setAttribute('style', originalStyle);
|
|
151
|
+
}
|
|
152
|
+
if (topLayer) {
|
|
153
|
+
if (originalPopover === null)
|
|
154
|
+
panel.removeAttribute('popover');
|
|
155
|
+
else
|
|
156
|
+
panel.setAttribute('popover', originalPopover);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
return handle;
|
|
161
|
+
}
|
|
162
|
+
function belongsToCloseScope(owner, close, dialogId) {
|
|
163
|
+
if (!owner.contains(close) || close.matches(':disabled') || close.getAttribute('aria-disabled') === 'true')
|
|
164
|
+
return false;
|
|
165
|
+
const dialog = owner.closest('dialog');
|
|
166
|
+
if (close.closest('dialog') !== dialog)
|
|
167
|
+
return false;
|
|
168
|
+
return close.hasAttribute('data-pui-close') || !close.dataset.close || close.dataset.close === (dialogId ?? dialog?.id ?? owner.id);
|
|
169
|
+
}
|
|
170
|
+
/** A content block can request closure without guessing its eventual frame ID. */
|
|
171
|
+
export function bindContentClose(owner, options = {}) {
|
|
172
|
+
const life = new Lifetime();
|
|
173
|
+
life.listen(owner, 'click', (event => {
|
|
174
|
+
if (event.defaultPrevented || !(event.target instanceof Element))
|
|
175
|
+
return;
|
|
176
|
+
const close = event.target.closest('[data-pui-close], [data-close]');
|
|
177
|
+
if (!close || !belongsToCloseScope(owner, close, options.dialogId))
|
|
178
|
+
return;
|
|
179
|
+
const dialog = owner.closest('dialog');
|
|
180
|
+
if (dialog && ![...(dialogSessions.get(dialog)?.subscribers ?? [])].every(subscriber => subscriber.canClose?.() !== false))
|
|
181
|
+
return;
|
|
182
|
+
event.preventDefault();
|
|
183
|
+
if (options.onClose)
|
|
184
|
+
options.onClose();
|
|
185
|
+
else if (dialog?.open)
|
|
186
|
+
dialog.close();
|
|
187
|
+
else
|
|
188
|
+
owner.hidden = true;
|
|
189
|
+
}));
|
|
190
|
+
return { destroy: () => life.destroy() };
|
|
191
|
+
}
|
|
2
192
|
const dialogSessions = new WeakMap();
|
|
3
193
|
const activations = new WeakMap();
|
|
4
194
|
function retainActivation(document) {
|
|
@@ -40,13 +230,13 @@ export function installDialogLifecycle(dialog, options = {}) {
|
|
|
40
230
|
current.listeners.listen(dialog, 'focusin', (() => { if (dialog.open)
|
|
41
231
|
current.active = true; }));
|
|
42
232
|
current.listeners.listen(dialog, 'click', (event => {
|
|
43
|
-
if (!dialog.open || !canClose())
|
|
233
|
+
if (!dialog.open || !canClose() || event.defaultPrevented)
|
|
44
234
|
return;
|
|
45
235
|
const target = event.target;
|
|
46
236
|
if (target instanceof Element) {
|
|
47
237
|
for (const subscriber of current.subscribers) {
|
|
48
|
-
const close = target.closest(subscriber.closeButtonSelector ?? '[data-close]');
|
|
49
|
-
if (close && dialog
|
|
238
|
+
const close = target.closest(subscriber.closeButtonSelector ?? '[data-pui-close], [data-close]');
|
|
239
|
+
if (close && belongsToCloseScope(dialog, close, dialog.id)) {
|
|
50
240
|
dialog.close();
|
|
51
241
|
return;
|
|
52
242
|
}
|
package/dist/surface.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"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","sourcesContent":["import { Lifetime } from './core.js';\n\nexport interface DialogLifecycleOptions {\n closeOnBackdrop?: boolean;\n canClose?: () => boolean;\n onOpen?: () => void;\n onClose?: () => void;\n returnFocus?: () => HTMLElement | null;\n closeButtonSelector?: string;\n}\nexport interface DialogLifecycle {\n open(): void;\n close(): void;\n isOpen(): boolean;\n destroy(): void;\n}\ntype DialogSession = {\n listeners: Lifetime;\n subscribers: Set<DialogLifecycleOptions>;\n active: boolean;\n previousFocus: HTMLElement | null;\n};\nconst dialogSessions = new WeakMap<HTMLDialogElement, DialogSession>();\ntype Activation = {owners: number; target: HTMLElement | null; listener: EventListener; timer?: ReturnType<typeof setTimeout>};\nconst activations = new WeakMap<Document, Activation>();\nfunction retainActivation(document: Document): {destroy(): void} {\n let activation = activations.get(document);\n if (!activation) {\n const current: Activation = {owners: 0, target: null, listener: () => {}};\n current.listener = event => {\n current.target = event.target instanceof Element ? event.target.closest<HTMLElement>('button, a[href], input, textarea, select, summary, [tabindex]') : null;\n if (current.timer !== undefined) clearTimeout(current.timer);\n current.timer = setTimeout(() => {current.target = null; current.timer = undefined;}, 0);\n };\n document.addEventListener('click', current.listener, true);\n activations.set(document, current); activation = current;\n }\n activation.owners++;\n const current = activation;\n return {destroy() {if (--current.owners === 0) {document.removeEventListener('click', current.listener, true); if (current.timer !== undefined) clearTimeout(current.timer); activations.delete(document);}}};\n}\n\n/** One native lifecycle per dialog, including dialogs supplied by a host shell. */\nexport function installDialogLifecycle(dialog: HTMLDialogElement, options: DialogLifecycleOptions = {}): DialogLifecycle {\n const subscription = {...options};\n let session = dialogSessions.get(dialog);\n if (!session) {\n session = { listeners: new Lifetime(), subscribers: new Set(), active: dialog.open, previousFocus: null };\n dialogSessions.set(dialog, session);\n const current = session;\n const activation = retainActivation(dialog.ownerDocument);\n current.listeners.add(activation.destroy);\n const canClose = () => [...current.subscribers].every(subscriber => subscriber.canClose?.() !== false);\n current.listeners.listen(dialog, 'cancel', (event => { if (!canClose()) event.preventDefault(); }) as EventListener);\n current.listeners.listen(dialog, 'focusin', (() => { if (dialog.open) current.active = true; }) as EventListener);\n current.listeners.listen(dialog, 'click', (event => {\n if (!dialog.open || !canClose()) return;\n const target = event.target;\n if (target instanceof Element) {\n for (const subscriber of current.subscribers) {\n const close = target.closest<HTMLElement>(subscriber.closeButtonSelector ?? '[data-close]');\n if (close && dialog.contains(close) && (!close.dataset.close || close.dataset.close === dialog.id)) {\n dialog.close();\n return;\n }\n }\n }\n if (target !== dialog || ![...current.subscribers].every(subscriber => subscriber.closeOnBackdrop !== false)) return;\n const pointer = event as MouseEvent;\n const rect = dialog.getBoundingClientRect();\n if (pointer.clientX < rect.left || pointer.clientX > rect.right || pointer.clientY < rect.top || pointer.clientY > rect.bottom) dialog.close();\n }) as EventListener);\n current.listeners.listen(dialog, 'close', (() => {\n // A native close event may arrive after the same element has reopened.\n if (dialog.open || !current.active) return;\n current.active = false;\n const returnFocus = [...current.subscribers].reverse().find(subscriber => subscriber.returnFocus)?.returnFocus;\n const previous = returnFocus ? returnFocus() : current.previousFocus;\n current.previousFocus = null;\n const beforeCallbacks = dialog.ownerDocument.activeElement;\n for (const subscriber of [...current.subscribers]) subscriber.onClose?.();\n const afterCallbacks = dialog.ownerDocument.activeElement;\n const deliberatelyFocused = afterCallbacks !== beforeCallbacks && afterCallbacks instanceof HTMLElement && afterCallbacks !== dialog.ownerDocument.body && !dialog.contains(afterCallbacks);\n if (!dialog.open && !deliberatelyFocused && previous?.isConnected) previous.focus({ preventScroll: true });\n }) as EventListener);\n }\n const current = session;\n current.subscribers.add(subscription);\n let destroyed = false;\n return {\n open() {\n if (destroyed || dialog.open) return;\n // Safari does not focus pointer-clicked buttons. Remember this event's\n // actual opener instead of relying solely on activeElement.\n const active = activations.get(dialog.ownerDocument)?.target ?? dialog.ownerDocument.activeElement;\n current.previousFocus = active instanceof HTMLElement && !dialog.contains(active) ? active : null;\n current.active = true;\n if (!dialog.isConnected) document.body.append(dialog);\n dialog.showModal();\n for (const subscriber of [...current.subscribers]) subscriber.onOpen?.();\n },\n close() { if (!destroyed && dialog.open) dialog.close(); },\n isOpen: () => !destroyed && dialog.open,\n destroy() {\n if (destroyed) return;\n destroyed = true;\n const returnFocus = [...current.subscribers].reverse().find(subscriber => subscriber.returnFocus)?.returnFocus;\n const previous = returnFocus ? returnFocus() : current.previousFocus;\n current.subscribers.delete(subscription);\n if (!current.subscribers.size) {\n current.listeners.destroy();\n if (!dialog.open && previous?.isConnected) previous.focus({ preventScroll: true });\n current.previousFocus = null;\n dialogSessions.delete(dialog);\n }\n },\n };\n}\n\nexport interface MenuNavigationOptions {\n trigger?: HTMLElement;\n onDismiss: (restoreFocus: boolean) => void;\n isOpen?: () => boolean;\n closeOnOutside?: boolean;\n contains?: (target: Node) => boolean;\n}\n\n/** Shared keyboard behavior; each menu retains its own presentation and actions. */\nexport function installMenuNavigation(menu: HTMLElement, options: MenuNavigationOptions): { focus(edge?: 'first' | 'last'): void; destroy(): void } {\n const life = new Lifetime();\n const open = () => options.isOpen?.() ?? !menu.hidden;\n const targets = () => [...menu.querySelectorAll<HTMLElement>('[role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"], button')]\n .filter(target => !(target instanceof HTMLButtonElement && target.disabled) && target.getAttribute('aria-disabled') !== 'true' && !target.closest('[hidden]'));\n life.listen(menu, 'keydown', (event => {\n if (!open()) return;\n const keyboard = event as KeyboardEvent;\n if (keyboard.key === 'Escape') { keyboard.preventDefault(); keyboard.stopPropagation(); options.onDismiss(true); return; }\n if (keyboard.key === 'Tab') { options.onDismiss(false); return; }\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(keyboard.key)) return;\n keyboard.preventDefault(); keyboard.stopPropagation();\n const items = targets();\n const index = items.indexOf(document.activeElement as HTMLElement);\n const next = keyboard.key === 'Home' ? 0 : keyboard.key === 'End' ? items.length - 1 : index < 0 ? (keyboard.key === 'ArrowUp' ? items.length - 1 : 0) : (index + (keyboard.key === 'ArrowUp' ? -1 : 1) + items.length) % items.length;\n items[next]?.focus();\n }) as EventListener);\n if (options.closeOnOutside) life.listen(document, 'pointerdown', (event => {\n const target = event.target;\n if (open() && target instanceof Node && !menu.contains(target) && !options.trigger?.contains(target) && !options.contains?.(target)) options.onDismiss(false);\n }) as EventListener);\n return { focus(edge = 'first') { const items = targets(); (edge === 'last' ? items.at(-1) : items[0])?.focus(); }, destroy() { life.destroy(); } };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAqBrC,MAAM,cAAc,GAAG,IAAI,OAAO,EAA+B,CAAC;AAElE;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA+B;IACpE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IACnC,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,EAAE,IAAI,GAAG,GAAG,CAAC,WAAY,CAAC;IAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,KAAK,KAAK,CAAC;IAC5C,MAAM,eAAe,GAAG,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,aAAa,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,QAAQ,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC;IACrE,IAAI,QAAQ;QAAE,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACtD,IAAI,QAAQ;QAAE,KAAK,CAAC,OAAO,CAAC,WAAW,GAAG,EAAE,CAAC;IAC7C,IAAI,MAAM,GAAG,KAAK,EAAE,QAAQ,GAAG,KAAK,EAAE,MAA4B,CAAC;IACnE,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC5C,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/B,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,CAAC,MAA0B,EAAE,EAAE,CAAC,MAAM,YAAY,IAAI;QACrE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClH,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,EAAE,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,KAAK;QAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3I,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ;YAAE,OAAO;QACjC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,CAAC;YAAC,KAAK,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAClF,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,EAAE,IAAI,OAAO,CAAC,aAAa,EAAE,qBAAqB,EAAE,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;QAC1H,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;QACrC,MAAM,IAAI,GAAG,QAAQ,EAAE,UAAU,IAAI,CAAC,EAAE,GAAG,GAAG,QAAQ,EAAE,SAAS,IAAI,CAAC,CAAC;QACvE,MAAM,KAAK,GAAG,QAAQ,EAAE,KAAK,IAAI,GAAG,CAAC,eAAe,CAAC,WAAW,CAAC;QACjE,MAAM,MAAM,GAAG,QAAQ,EAAE,MAAM,IAAI,GAAG,CAAC,eAAe,CAAC,YAAY,CAAC;QACpE,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7F,MAAM,MAAM,GAAG,GAAG,CAAC;QACnB,KAAK,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3D,KAAK,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnF,0EAA0E;QAC1E,4EAA4E;QAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,EAAE,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QACjE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;QAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,MAAM,GAAG,GAAG,CAAC;QAC9C,MAAM,OAAO,GAAG,KAAK,GAAG,OAAO,IAAI,KAAK,GAAG,KAAK,CAAC;QACjD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACvD,KAAK,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAC;QAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;QAClH,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1G,KAAK,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC;QAC9G,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;QAAC,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC;IAC7D,CAAC,CAAC;IACF,SAAS,KAAK,CAAC,YAAY,GAAG,KAAK;QACjC,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,GAAG,KAAK,CAAC;QACf,MAAM,EAAE,OAAO,EAAE,CAAC;QAAC,MAAM,GAAG,SAAS,CAAC;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAAC,IAAI,KAAK,IAAI,CAAC;YAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC5E,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC;YAAE,KAAK,CAAC,WAAW,EAAE,CAAC;QACpE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACpE,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACxC,IAAI,YAAY,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC;YAAE,OAAO,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACnH,CAAC;IACD,MAAM,MAAM,GAAoB;QAC9B,IAAI;YACF,IAAI,QAAQ,IAAI,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,KAAK,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,MAAM;gBAAE,OAAO;YAC5H,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YAAC,OAAO,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YACnF,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnB,IAAI,QAAQ;gBAAE,KAAK,CAAC,WAAW,EAAE,CAAC;YAClC,KAAK,EAAE,CAAC;YACR,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,CAAC,KAAY,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;gBAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5E,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,IAAI,OAAO,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;gBACtC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1D,MAAM,IAAI,GAAG,CAAC,KAAY,EAAE,EAAE;oBAC5B,oEAAoE;oBACpE,mEAAmE;oBACnE,IAAI,QAAQ,CAAE,KAAoB,CAAC,aAAa,CAAC;wBAAE,OAAO;oBAC1D,cAAc,CAAC,GAAG,EAAE,GAAG,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC;wBAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBACjF,CAAC,CAAC;gBACF,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;gBAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;YACnF,CAAC;YACD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE;gBACrC,MAAM,GAAG,GAAG,KAAsB,CAAC;gBACnC,IAAI,GAAG,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,KAAK;oBAAE,OAAO;gBAC/F,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,gBAAgB,CAAoB,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClF,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAAE,OAAO;gBAC9C,GAAG,CAAC,cAAc,EAAE,CAAC;gBAAC,GAAG,CAAC,eAAe,EAAE,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3D,CAAC,CAAkB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,aAAa;oBAAE,KAAK,EAAE,CAAC;;oBAAM,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;gBACzE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACpC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;oBAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5I,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;oBAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;oBAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAAC,CAAC;gBACpI,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;gBAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC/F,IAAI,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,KAAK,OAAO;oBAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;gBACxG,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YAC1C,CAAC;YACD,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK;QACL,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM;QACpB,OAAO;YACL,IAAI,QAAQ;gBAAE,OAAO;YACrB,KAAK,EAAE,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC;YACzB,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;gBACjC,IAAI,aAAa,KAAK,IAAI;oBAAE,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;;oBAAM,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YAC9G,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBAAC,IAAI,eAAe,KAAK,IAAI;oBAAE,KAAK,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;;oBAAM,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;YAAC,CAAC;QACxI,CAAC;KACF,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAkB,EAAE,KAAkB,EAAE,QAAiB;IACpF,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACzH,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACrD,OAAO,KAAK,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;AACtI,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,gBAAgB,CAAC,KAAkB,EAAE,UAAuD,EAAE;IAC5G,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE;QACnC,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY,OAAO,CAAC;YAAE,OAAO;QACzE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAc,gCAAgC,CAAC,CAAC;QAClF,IAAI,CAAC,KAAK,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,KAAK,KAAK,CAAC;YAAE,OAAO;QACnI,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,IAAI,OAAO,CAAC,OAAO;YAAE,OAAO,CAAC,OAAO,EAAE,CAAC;aAClC,IAAI,MAAM,EAAE,IAAI;YAAE,MAAM,CAAC,KAAK,EAAE,CAAC;;YACjC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAC3B,CAAC,CAAkB,CAAC,CAAC;IACrB,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;AAC3C,CAAC;AAsBD,MAAM,cAAc,GAAG,IAAI,OAAO,EAAoC,CAAC;AAEvE,MAAM,WAAW,GAAG,IAAI,OAAO,EAAwB,CAAC;AACxD,SAAS,gBAAgB,CAAC,QAAkB;IAC1C,IAAI,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,OAAO,GAAe,EAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC,EAAC,CAAC;QAC1E,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,EAAE;YACzB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAc,+DAA+D,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7J,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;gBAAE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC7D,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,GAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAA,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3F,CAAC,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3D,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAAC,UAAU,GAAG,OAAO,CAAC;IAC3D,CAAC;IACD,UAAU,CAAC,MAAM,EAAE,CAAC;IACpB,MAAM,OAAO,GAAG,UAAU,CAAC;IAC3B,OAAO,EAAC,OAAO,KAAI,IAAI,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAAA,QAAQ,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAAC,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;gBAAE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAAA,CAAC,CAAA,CAAC,EAAC,CAAC;AAChN,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,sBAAsB,CAAC,MAAyB,EAAE,UAAkC,EAAE;IACpG,MAAM,YAAY,GAAG,EAAC,GAAG,OAAO,EAAC,CAAC;IAClC,IAAI,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,EAAE,SAAS,EAAE,IAAI,QAAQ,EAAE,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;QAC1G,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,OAAO,CAAC;QACxB,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1D,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,KAAK,KAAK,CAAC,CAAC;QACvG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE;YAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAkB,CAAC,CAAC;QACrH,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAkB,CAAC,CAAC;QAClH,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE;YACjD,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,KAAK,CAAC,gBAAgB;gBAAE,OAAO;YAClE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YAC5B,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;gBAC9B,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;oBAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAc,UAAU,CAAC,mBAAmB,IAAI,gCAAgC,CAAC,CAAC;oBAC9G,IAAI,KAAK,IAAI,mBAAmB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;wBAC3D,MAAM,CAAC,KAAK,EAAE,CAAC;wBACf,OAAO;oBACT,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,KAAK,KAAK,CAAC;gBAAE,OAAO;YACrH,MAAM,OAAO,GAAG,KAAmB,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC;YAC5C,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QACjJ,CAAC,CAAkB,CAAC,CAAC;QACrB,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE;YAC9C,uEAAuE;YACvE,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM;gBAAE,OAAO;YAC3C,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;YACvB,MAAM,WAAW,GAAG,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;YAC/G,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;YACrE,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;YAC7B,MAAM,eAAe,GAAG,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC;YAC3D,KAAK,MAAM,UAAU,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;gBAAE,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1E,MAAM,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC;YAC1D,MAAM,mBAAmB,GAAG,cAAc,KAAK,eAAe,IAAI,cAAc,YAAY,WAAW,IAAI,cAAc,KAAK,MAAM,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YAC5L,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,mBAAmB,IAAI,QAAQ,EAAE,WAAW;gBAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7G,CAAC,CAAkB,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC;IACxB,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACtC,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,OAAO;QACL,IAAI;YACF,IAAI,SAAS,IAAI,MAAM,CAAC,IAAI;gBAAE,OAAO;YACrC,uEAAuE;YACvE,4DAA4D;YAC5D,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC;YACnG,OAAO,CAAC,aAAa,GAAG,MAAM,YAAY,WAAW,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAClG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,WAAW;gBAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtD,MAAM,CAAC,SAAS,EAAE,CAAC;YACnB,KAAK,MAAM,UAAU,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;gBAAE,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3E,CAAC;QACD,KAAK,KAAK,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI;YAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC1D,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI;QACvC,OAAO;YACL,IAAI,SAAS;gBAAE,OAAO;YACtB,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM,WAAW,GAAG,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;YAC/G,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;YACrE,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACzC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;gBAC9B,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,QAAQ,EAAE,WAAW;oBAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;gBACnF,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;gBAC7B,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAUD,oFAAoF;AACpF,MAAM,UAAU,qBAAqB,CAAC,IAAiB,EAAE,OAA8B;IACrF,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IACtD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAc,8EAA8E,CAAC,CAAC;SAC1I,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,YAAY,iBAAiB,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACjK,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE;QACpC,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;QACpB,MAAM,QAAQ,GAAG,KAAsB,CAAC;QACxC,IAAI,QAAQ,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;YAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;YAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC1H,IAAI,QAAQ,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;YAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QACjE,IAAI,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO;QAC5E,QAAQ,CAAC,cAAc,EAAE,CAAC;QAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,aAA4B,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,QAAQ,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACvO,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC,CAAkB,CAAC,CAAC;IACrB,IAAI,OAAO,CAAC,cAAc;QAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,CAAC,KAAK,CAAC,EAAE;YACxE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YAC5B,IAAI,IAAI,EAAE,IAAI,MAAM,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC;gBAAE,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAChK,CAAC,CAAkB,CAAC,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC,IAAI,GAAG,OAAO,IAAI,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACrJ,CAAC","sourcesContent":["import { Lifetime } from './core.js';\n\ninterface AnchoredSurfaceOptions {\n trigger: HTMLElement;\n panel: HTMLElement;\n closeOnFocusOut?: boolean;\n exclusions?: readonly Node[];\n onToggle?: (open: boolean, restoreFocus?: boolean) => void;\n position?: boolean;\n canOpen?: () => boolean;\n canEscape?: () => boolean;\n getAnchor?: () => Pick<DOMRect, 'left' | 'right' | 'top' | 'bottom' | 'width' | 'height'>;\n anchorElement?: HTMLElement;\n dismissOnMove?: boolean;\n}\ninterface AnchoredSurface {\n open(): void;\n close(restoreFocus?: boolean): void;\n isOpen(): boolean;\n destroy(): void;\n}\nconst floatingStacks = new WeakMap<Document, AnchoredSurface[]>();\n\n/** Shared nonmodal surface ownership. Retained panels can keep their own layout;\n * anchored panels use the native top layer to escape scroll/overflow containers.\n */\nexport function installAnchoredSurface(options: AnchoredSurfaceOptions): AnchoredSurface {\n const { trigger, panel } = options;\n const doc = trigger.ownerDocument, view = doc.defaultView!;\n const position = options.position !== false;\n const originalPopover = panel.getAttribute('popover');\n const originalStyle = panel.getAttribute('style');\n const topLayer = position && typeof panel.showPopover === 'function';\n if (topLayer) panel.setAttribute('popover', 'manual');\n if (position) panel.dataset.puiFloating = '';\n let opened = false, disposed = false, events: Lifetime | undefined;\n const stack = floatingStacks.get(doc) ?? [];\n floatingStacks.set(doc, stack);\n panel.hidden = true;\n trigger.setAttribute('aria-expanded', 'false');\n const contains = (target: EventTarget | null) => target instanceof Node &&\n (trigger.contains(target) || panel.contains(target) || options.exclusions?.some(node => node.contains(target)));\n const style = (name: string, value: string) => { if (panel.style.getPropertyValue(name) !== value) panel.style.setProperty(name, value); };\n const place = () => {\n if (!opened || !position) return;\n if (!trigger.isConnected || !trigger.getClientRects().length) { close(); return; }\n const anchor = options.getAnchor?.() ?? options.anchorElement?.getBoundingClientRect() ?? trigger.getBoundingClientRect();\n const viewport = view.visualViewport;\n const left = viewport?.offsetLeft ?? 0, top = viewport?.offsetTop ?? 0;\n const width = viewport?.width ?? doc.documentElement.clientWidth;\n const height = viewport?.height ?? doc.documentElement.clientHeight;\n const gap = parseFloat(view.getComputedStyle(panel).getPropertyValue('--pui-space-sm')) || 8;\n const margin = gap;\n style('max-width', `${Math.max(0, width - margin * 2)}px`);\n style('min-width', `${Math.min(anchor.width, Math.max(0, width - margin * 2))}px`);\n // scrollHeight measures the content without expanding the viewport first.\n // Expanding a scrolled list would clamp scrollTop and hide its active item.\n const scrollTop = panel.scrollTop, scrollLeft = panel.scrollLeft;\n const desired = Math.min(panel.scrollHeight + 2, 320);\n const below = top + height - anchor.bottom - margin - gap;\n const above = anchor.top - top - margin - gap;\n const upwards = below < desired && above > below;\n const available = Math.max(0, upwards ? above : below);\n style('max-height', `${Math.min(320, available)}px`);\n const bounds = panel.getBoundingClientRect();\n const horizontal = anchor.left + bounds.width > left + width - margin ? anchor.right - bounds.width : anchor.left;\n style('left', `${Math.max(left + margin, Math.min(horizontal, left + width - margin - bounds.width))}px`);\n style('top', `${upwards ? Math.max(top + margin, anchor.top - gap - bounds.height) : anchor.bottom + gap}px`);\n panel.scrollTop = scrollTop; panel.scrollLeft = scrollLeft;\n };\n function close(restoreFocus = false): void {\n if (!opened) return;\n opened = false;\n events?.destroy(); events = undefined;\n const index = stack.indexOf(handle); if (index >= 0) stack.splice(index, 1);\n if (topLayer && panel.matches(':popover-open')) panel.hidePopover();\n panel.hidden = true; trigger.setAttribute('aria-expanded', 'false');\n options.onToggle?.(false, restoreFocus);\n if (restoreFocus && trigger.isConnected && !trigger.matches(':disabled')) trigger.focus({ preventScroll: true });\n }\n const handle: AnchoredSurface = {\n open() {\n if (disposed || opened || options.canOpen?.() === false || !trigger.isConnected || !trigger.getClientRects().length) return;\n opened = true; panel.hidden = false; trigger.setAttribute('aria-expanded', 'true');\n stack.push(handle);\n if (topLayer) panel.showPopover();\n place();\n if (!opened) return;\n events = new Lifetime();\n const outside = (event: Event) => { if (!contains(event.target)) close(); };\n events.listen(doc, 'pointerdown', outside, { capture: true });\n events.listen(doc, 'click', outside, { capture: true });\n if (options.closeOnFocusOut !== false) {\n events.listen(doc, 'focusin', outside, { capture: true });\n const blur = (event: Event) => {\n // Native pointer focus can briefly expose body between focusout and\n // focusin. Its related target already identifies an internal move.\n if (contains((event as FocusEvent).relatedTarget)) return;\n queueMicrotask(() => { if (opened && !contains(doc.activeElement)) close(); });\n };\n events.listen(trigger, 'focusout', blur); events.listen(panel, 'focusout', blur);\n }\n events.listen(doc, 'keydown', (event => {\n const key = event as KeyboardEvent;\n if (key.key !== 'Escape' || stack.at(-1) !== handle || options.canEscape?.() === false) return;\n const modal = [...doc.querySelectorAll<HTMLDialogElement>('dialog[open]')].at(-1);\n if (modal && !modal.contains(trigger)) return;\n key.preventDefault(); key.stopPropagation(); close(true);\n }) as EventListener, { capture: true });\n if (position) {\n const move = () => { if (options.dismissOnMove) close(); else place(); };\n events.listen(view, 'resize', move);\n events.listen(doc, 'scroll', event => { if (!(event.target instanceof Node) || !panel.contains(event.target)) move(); }, { capture: true });\n if (view.visualViewport) { events.listen(view.visualViewport, 'resize', move); events.listen(view.visualViewport, 'scroll', move); }\n const observer = new ResizeObserver(place); observer.observe(trigger); observer.observe(panel);\n if (options.anchorElement && options.anchorElement !== trigger) observer.observe(options.anchorElement);\n events.add(() => observer.disconnect());\n }\n options.onToggle?.(true);\n },\n close,\n isOpen: () => opened,\n destroy() {\n if (disposed) return;\n close(); disposed = true;\n if (position) {\n delete panel.dataset.puiFloating;\n if (originalStyle === null) panel.removeAttribute('style'); else panel.setAttribute('style', originalStyle);\n }\n if (topLayer) { if (originalPopover === null) panel.removeAttribute('popover'); else panel.setAttribute('popover', originalPopover); }\n },\n };\n return handle;\n}\n\nfunction belongsToCloseScope(owner: HTMLElement, close: HTMLElement, dialogId?: string): boolean {\n if (!owner.contains(close) || close.matches(':disabled') || close.getAttribute('aria-disabled') === 'true') return false;\n const dialog = owner.closest('dialog');\n if (close.closest('dialog') !== dialog) return false;\n return close.hasAttribute('data-pui-close') || !close.dataset.close || close.dataset.close === (dialogId ?? dialog?.id ?? owner.id);\n}\n\n/** A content block can request closure without guessing its eventual frame ID. */\nexport function bindContentClose(owner: HTMLElement, options: { dialogId?: string; onClose?: () => void } = {}): { destroy(): void } {\n const life = new Lifetime();\n life.listen(owner, 'click', (event => {\n if (event.defaultPrevented || !(event.target instanceof Element)) return;\n const close = event.target.closest<HTMLElement>('[data-pui-close], [data-close]');\n if (!close || !belongsToCloseScope(owner, close, options.dialogId)) return;\n const dialog = owner.closest('dialog');\n if (dialog && ![...(dialogSessions.get(dialog)?.subscribers ?? [])].every(subscriber => subscriber.canClose?.() !== false)) return;\n event.preventDefault();\n if (options.onClose) options.onClose();\n else if (dialog?.open) dialog.close();\n else owner.hidden = true;\n }) as EventListener);\n return { destroy: () => life.destroy() };\n}\n\nexport interface DialogLifecycleOptions {\n closeOnBackdrop?: boolean;\n canClose?: () => boolean;\n onOpen?: () => void;\n onClose?: () => void;\n returnFocus?: () => HTMLElement | null;\n closeButtonSelector?: string;\n}\nexport interface DialogLifecycle {\n open(): void;\n close(): void;\n isOpen(): boolean;\n destroy(): void;\n}\ntype DialogSession = {\n listeners: Lifetime;\n subscribers: Set<DialogLifecycleOptions>;\n active: boolean;\n previousFocus: HTMLElement | null;\n};\nconst dialogSessions = new WeakMap<HTMLDialogElement, DialogSession>();\ntype Activation = {owners: number; target: HTMLElement | null; listener: EventListener; timer?: ReturnType<typeof setTimeout>};\nconst activations = new WeakMap<Document, Activation>();\nfunction retainActivation(document: Document): {destroy(): void} {\n let activation = activations.get(document);\n if (!activation) {\n const current: Activation = {owners: 0, target: null, listener: () => {}};\n current.listener = event => {\n current.target = event.target instanceof Element ? event.target.closest<HTMLElement>('button, a[href], input, textarea, select, summary, [tabindex]') : null;\n if (current.timer !== undefined) clearTimeout(current.timer);\n current.timer = setTimeout(() => {current.target = null; current.timer = undefined;}, 0);\n };\n document.addEventListener('click', current.listener, true);\n activations.set(document, current); activation = current;\n }\n activation.owners++;\n const current = activation;\n return {destroy() {if (--current.owners === 0) {document.removeEventListener('click', current.listener, true); if (current.timer !== undefined) clearTimeout(current.timer); activations.delete(document);}}};\n}\n\n/** One native lifecycle per dialog, including dialogs supplied by a host shell. */\nexport function installDialogLifecycle(dialog: HTMLDialogElement, options: DialogLifecycleOptions = {}): DialogLifecycle {\n const subscription = {...options};\n let session = dialogSessions.get(dialog);\n if (!session) {\n session = { listeners: new Lifetime(), subscribers: new Set(), active: dialog.open, previousFocus: null };\n dialogSessions.set(dialog, session);\n const current = session;\n const activation = retainActivation(dialog.ownerDocument);\n current.listeners.add(activation.destroy);\n const canClose = () => [...current.subscribers].every(subscriber => subscriber.canClose?.() !== false);\n current.listeners.listen(dialog, 'cancel', (event => { if (!canClose()) event.preventDefault(); }) as EventListener);\n current.listeners.listen(dialog, 'focusin', (() => { if (dialog.open) current.active = true; }) as EventListener);\n current.listeners.listen(dialog, 'click', (event => {\n if (!dialog.open || !canClose() || event.defaultPrevented) return;\n const target = event.target;\n if (target instanceof Element) {\n for (const subscriber of current.subscribers) {\n const close = target.closest<HTMLElement>(subscriber.closeButtonSelector ?? '[data-pui-close], [data-close]');\n if (close && belongsToCloseScope(dialog, close, dialog.id)) {\n dialog.close();\n return;\n }\n }\n }\n if (target !== dialog || ![...current.subscribers].every(subscriber => subscriber.closeOnBackdrop !== false)) return;\n const pointer = event as MouseEvent;\n const rect = dialog.getBoundingClientRect();\n if (pointer.clientX < rect.left || pointer.clientX > rect.right || pointer.clientY < rect.top || pointer.clientY > rect.bottom) dialog.close();\n }) as EventListener);\n current.listeners.listen(dialog, 'close', (() => {\n // A native close event may arrive after the same element has reopened.\n if (dialog.open || !current.active) return;\n current.active = false;\n const returnFocus = [...current.subscribers].reverse().find(subscriber => subscriber.returnFocus)?.returnFocus;\n const previous = returnFocus ? returnFocus() : current.previousFocus;\n current.previousFocus = null;\n const beforeCallbacks = dialog.ownerDocument.activeElement;\n for (const subscriber of [...current.subscribers]) subscriber.onClose?.();\n const afterCallbacks = dialog.ownerDocument.activeElement;\n const deliberatelyFocused = afterCallbacks !== beforeCallbacks && afterCallbacks instanceof HTMLElement && afterCallbacks !== dialog.ownerDocument.body && !dialog.contains(afterCallbacks);\n if (!dialog.open && !deliberatelyFocused && previous?.isConnected) previous.focus({ preventScroll: true });\n }) as EventListener);\n }\n const current = session;\n current.subscribers.add(subscription);\n let destroyed = false;\n return {\n open() {\n if (destroyed || dialog.open) return;\n // Safari does not focus pointer-clicked buttons. Remember this event's\n // actual opener instead of relying solely on activeElement.\n const active = activations.get(dialog.ownerDocument)?.target ?? dialog.ownerDocument.activeElement;\n current.previousFocus = active instanceof HTMLElement && !dialog.contains(active) ? active : null;\n current.active = true;\n if (!dialog.isConnected) document.body.append(dialog);\n dialog.showModal();\n for (const subscriber of [...current.subscribers]) subscriber.onOpen?.();\n },\n close() { if (!destroyed && dialog.open) dialog.close(); },\n isOpen: () => !destroyed && dialog.open,\n destroy() {\n if (destroyed) return;\n destroyed = true;\n const returnFocus = [...current.subscribers].reverse().find(subscriber => subscriber.returnFocus)?.returnFocus;\n const previous = returnFocus ? returnFocus() : current.previousFocus;\n current.subscribers.delete(subscription);\n if (!current.subscribers.size) {\n current.listeners.destroy();\n if (!dialog.open && previous?.isConnected) previous.focus({ preventScroll: true });\n current.previousFocus = null;\n dialogSessions.delete(dialog);\n }\n },\n };\n}\n\nexport interface MenuNavigationOptions {\n trigger?: HTMLElement;\n onDismiss: (restoreFocus: boolean) => void;\n isOpen?: () => boolean;\n closeOnOutside?: boolean;\n contains?: (target: Node) => boolean;\n}\n\n/** Shared keyboard behavior; each menu retains its own presentation and actions. */\nexport function installMenuNavigation(menu: HTMLElement, options: MenuNavigationOptions): { focus(edge?: 'first' | 'last'): void; destroy(): void } {\n const life = new Lifetime();\n const open = () => options.isOpen?.() ?? !menu.hidden;\n const targets = () => [...menu.querySelectorAll<HTMLElement>('[role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"], button')]\n .filter(target => !(target instanceof HTMLButtonElement && target.disabled) && target.getAttribute('aria-disabled') !== 'true' && !target.closest('[hidden]'));\n life.listen(menu, 'keydown', (event => {\n if (!open()) return;\n const keyboard = event as KeyboardEvent;\n if (keyboard.key === 'Escape') { keyboard.preventDefault(); keyboard.stopPropagation(); options.onDismiss(true); return; }\n if (keyboard.key === 'Tab') { options.onDismiss(false); return; }\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(keyboard.key)) return;\n keyboard.preventDefault(); keyboard.stopPropagation();\n const items = targets();\n const index = items.indexOf(document.activeElement as HTMLElement);\n const next = keyboard.key === 'Home' ? 0 : keyboard.key === 'End' ? items.length - 1 : index < 0 ? (keyboard.key === 'ArrowUp' ? items.length - 1 : 0) : (index + (keyboard.key === 'ArrowUp' ? -1 : 1) + items.length) % items.length;\n items[next]?.focus();\n }) as EventListener);\n if (options.closeOnOutside) life.listen(document, 'pointerdown', (event => {\n const target = event.target;\n if (open() && target instanceof Node && !menu.contains(target) && !options.trigger?.contains(target) && !options.contains?.(target)) options.onDismiss(false);\n }) as EventListener);\n return { focus(edge = 'first') { const items = targets(); (edge === 'last' ? items.at(-1) : items[0])?.focus(); }, destroy() { life.destroy(); } };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../src/tasks/approval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,MAAM,WAAW,YAAY;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAC,CAAA;CAAC;AACrN,MAAM,WAAW,kBAAkB;IAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAC;AACvF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,GAAE;IAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,KAAK,IAAI,CAAA;CAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../src/tasks/approval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,MAAM,WAAW,YAAY;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAC,CAAA;CAAC;AACrN,MAAM,WAAW,kBAAkB;IAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAC;AACvF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,GAAE;IAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,KAAK,IAAI,CAAA;CAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkC5N"}
|
package/dist/tasks/approval.js
CHANGED
|
@@ -1,64 +1,102 @@
|
|
|
1
|
-
import { scopeIds
|
|
2
|
-
import {
|
|
1
|
+
import { scopeIds } from '../forms/identity.js';
|
|
2
|
+
import { icon, uniqueId, setText } from '../dom.js';
|
|
3
3
|
import { createPagedPreview } from '../content/paged-preview.js';
|
|
4
4
|
import { adoptProductParts } from '../foundations.js';
|
|
5
5
|
export function createApprovalPanel(initial, options = {}) {
|
|
6
6
|
const element = options.element || document.createElement('div');
|
|
7
7
|
if (!options.element)
|
|
8
8
|
element.className = 'pui-approval-panel';
|
|
9
|
-
const prefix = options.idPrefix ?? uniqueId('pui-approval') + '-';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
const prefix = options.idPrefix ?? uniqueId('pui-approval') + '-', parts = adoptProductParts(element), abort = new AbortController();
|
|
10
|
+
let destroyed = false, current = null, contentAbort = new AbortController();
|
|
11
|
+
let card, warning, badge, file, fileKind, path, previewError, diff, shortened, details, args, scope, always;
|
|
12
|
+
let diffBlock, argsBlock;
|
|
13
|
+
const clear = () => { contentAbort.abort(); contentAbort = new AbortController(); diffBlock?.destroy(); argsBlock?.destroy(); diffBlock = argsBlock = undefined; card = undefined; element.replaceChildren(); };
|
|
14
|
+
const showArgs = () => { if (destroyed || !current || argsBlock || (current.preview && !details.open))
|
|
15
|
+
return; argsBlock = createPagedPreview({ container: args, text: current.argsText, kind: 'text' }); };
|
|
16
|
+
function create() {
|
|
17
|
+
element.innerHTML = `<section class="pui-approval-card" aria-label="Tool approval required"><div class="pui-approval-heading">${icon('shield')}<div><strong>Pith needs your permission</strong><span>Review this action before it runs.</span></div><span class="pui-approval-badge"></span></div><p class="pui-approval-warning" hidden></p><div class="pui-approval-file" hidden><strong></strong><code></code></div><p class="pui-preview-note" role="status" hidden></p><div id="approval-diff-preview" hidden></div><p class="pui-preview-note" data-shortened hidden>Preview shortened. Expand Tool arguments for the complete change.</p><details class="pui-approval-arguments"><summary>Tool arguments</summary><div id="approval-args-preview"></div></details><p class="pui-approval-scope" hidden>Workspace permission applies to this conversation. Commands and external connection tools still need approval.</p><div class="pui-approval-actions"><button type="button" class="pui-secondary-button" data-approval="deny">Deny</button><button type="button" class="pui-secondary-button pui-always-allow-button" data-approval="always">Always allow workspace changes</button><button type="button" class="pui-primary-button" data-approval="allow">${icon('check')}Allow this action</button></div></section>`;
|
|
18
|
+
card = element.firstElementChild;
|
|
19
|
+
scopeIds(card, prefix);
|
|
20
|
+
warning = card.querySelector('.pui-approval-warning');
|
|
21
|
+
badge = card.querySelector('.pui-approval-badge');
|
|
22
|
+
file = card.querySelector('.pui-approval-file');
|
|
23
|
+
fileKind = file.querySelector('strong');
|
|
24
|
+
path = file.querySelector('code');
|
|
25
|
+
previewError = card.querySelector('[role="status"]');
|
|
26
|
+
diff = card.querySelector('[id$="approval-diff-preview"]');
|
|
27
|
+
shortened = card.querySelector('[data-shortened]');
|
|
28
|
+
details = card.querySelector('details');
|
|
29
|
+
args = details.querySelector('div');
|
|
30
|
+
scope = card.querySelector('.pui-approval-scope');
|
|
31
|
+
always = card.querySelector('[data-approval="always"]');
|
|
32
|
+
details.addEventListener('toggle', showArgs, { signal: contentAbort.signal });
|
|
33
|
+
}
|
|
17
34
|
const update = (state) => {
|
|
18
35
|
if (destroyed)
|
|
19
36
|
return;
|
|
20
|
-
const approval = state.approval;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
37
|
+
const approval = state.approval, changed = approval?.id !== current?.id;
|
|
38
|
+
if (changed || !approval)
|
|
39
|
+
clear();
|
|
40
|
+
current = approval;
|
|
41
|
+
if (!approval) {
|
|
42
|
+
parts.update();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const fresh = !card;
|
|
46
|
+
if (fresh)
|
|
47
|
+
create();
|
|
48
|
+
const preview = approval.preview;
|
|
49
|
+
setText(badge, approval.toolName);
|
|
50
|
+
setText(warning, approval.warning || '');
|
|
51
|
+
warning.hidden = !approval.warning;
|
|
52
|
+
file.hidden = !preview;
|
|
53
|
+
if (preview) {
|
|
54
|
+
setText(fileKind, preview.kind === 'create' ? 'Create file' : 'Modify file');
|
|
55
|
+
setText(path, preview.path);
|
|
56
|
+
}
|
|
57
|
+
previewError.hidden = !preview?.error;
|
|
58
|
+
setText(previewError, preview?.error || '');
|
|
59
|
+
diff.hidden = !preview || !!preview.error;
|
|
60
|
+
shortened.hidden = !preview || !!preview.error || !preview.truncated;
|
|
61
|
+
if (preview && !preview.error) {
|
|
62
|
+
const value = { text: preview.diff || 'No content changes.', kind: 'diff' };
|
|
63
|
+
if (diffBlock)
|
|
64
|
+
diffBlock.update(value);
|
|
65
|
+
else
|
|
66
|
+
diffBlock = createPagedPreview({ container: diff, ...value });
|
|
67
|
+
}
|
|
68
|
+
else if (diffBlock) {
|
|
69
|
+
diffBlock.destroy();
|
|
70
|
+
diffBlock = undefined;
|
|
51
71
|
}
|
|
52
|
-
|
|
72
|
+
if (preview) {
|
|
73
|
+
if (args.parentElement !== details)
|
|
74
|
+
details.append(args);
|
|
75
|
+
if (details.parentElement !== card)
|
|
76
|
+
card.insertBefore(details, scope);
|
|
77
|
+
if (fresh)
|
|
78
|
+
details.open = !!preview.error;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
if (args.parentElement !== card)
|
|
82
|
+
card.insertBefore(args, scope);
|
|
83
|
+
details.remove();
|
|
84
|
+
}
|
|
85
|
+
showArgs();
|
|
86
|
+
argsBlock?.update({ text: approval.argsText, kind: 'text' });
|
|
87
|
+
scope.hidden = !approval.canAlwaysAllow;
|
|
88
|
+
always.hidden = !approval.canAlwaysAllow;
|
|
89
|
+
for (const button of element.querySelectorAll('[data-approval]')) {
|
|
90
|
+
button.dataset.approvalId = approval.id;
|
|
53
91
|
parts.action(button).update({ disabled: !!state.disabled });
|
|
92
|
+
}
|
|
54
93
|
parts.update();
|
|
55
94
|
};
|
|
56
|
-
element.addEventListener('click',
|
|
95
|
+
element.addEventListener('click', event => { const button = event.target.closest('[data-approval]'); if (button && !button.disabled && !button.hidden)
|
|
57
96
|
options.onAction?.(button.dataset.approvalId, button.dataset.approval); }, { signal: abort.signal });
|
|
58
97
|
update(initial);
|
|
59
98
|
return { element, update, destroy() { if (destroyed)
|
|
60
|
-
return; destroyed = true; parts.destroy(); abort.abort(); contentAbort.abort();
|
|
61
|
-
preview.destroy(); if (!options.element)
|
|
99
|
+
return; destroyed = true; clear(); parts.destroy(); abort.abort(); contentAbort.abort(); if (!options.element)
|
|
62
100
|
element.remove(); } };
|
|
63
101
|
}
|
|
64
102
|
//# sourceMappingURL=approval.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/tasks/approval.ts"],"names":[],"mappings":"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","sourcesContent":["import {scopeIds, localField} from '../forms/identity.js';\nimport type { UIBlock } from '../core.js';\nimport {escape, icon, uniqueId} from '../dom.js';\nimport {createPagedPreview, type PagedPreviewState} from '../content/paged-preview.js';\nimport {adoptProductParts} from '../foundations.js';\nexport interface ApprovalView {id: string; toolName: string; warning?: string; canAlwaysAllow: boolean; argsText: string; preview?: {kind: string; path: string; error?: string; diff?: string; truncated?: boolean}}\nexport interface ApprovalPanelState {approval: ApprovalView | null; disabled?: boolean}\nexport function createApprovalPanel(initial: ApprovalPanelState, options: {element?: HTMLElement; idPrefix?: string; onAction?: (id: string, action: 'deny' | 'always' | 'allow') => void} = {}): UIBlock<ApprovalPanelState> {\n const element = options.element || document.createElement('div'); if (!options.element) element.className = 'pui-approval-panel';\n const prefix = options.idPrefix ?? uniqueId('pui-approval') + '-';\n const parts = adoptProductParts(element);\n const $ = <T extends HTMLElement = HTMLElement>(id: string) => localField<T>(element, prefix + id);\n const abort = new AbortController(); let contentAbort = new AbortController(); let signature = ''; let destroyed = false; let previews: UIBlock<PagedPreviewState>[] = [];\n const update = (state: Readonly<ApprovalPanelState>) => {\n if (destroyed) return; const approval = state.approval; const next = JSON.stringify(approval);\n if (next !== signature) {signature = next; contentAbort.abort(); contentAbort = new AbortController(); for (const preview of previews) preview.destroy(); previews = [];\n const warning = approval?.warning || ''; const canAlwaysAllow = !!approval?.canAlwaysAllow; const preview = approval?.preview;\n const previewBody = preview?.error ? `<p class=\"pui-preview-note\" role=\"status\">${escape(preview.error)}</p>` : preview ? `<div id=\"approval-diff-preview\"></div>${preview.truncated ? '<p class=\"pui-preview-note\">Preview shortened. Expand Tool arguments for the complete change.</p>' : ''}` : '';\n const previewMarkup = preview ? `<div class=\"pui-approval-file\"><strong>${preview.kind === 'create' ? 'Create file' : 'Modify file'}</strong><code>${escape(preview.path)}</code></div>${previewBody}` : '';\n const args = `<div id=\"approval-args-preview\"></div>`;\n\n element.innerHTML = approval ? `<section class=\"pui-approval-card\" aria-label=\"Tool approval required\"><div class=\"pui-approval-heading\">${icon('shield')}<div><strong>Pith needs your permission</strong><span>Review this action before it runs.</span></div><span class=\"pui-approval-badge\">${escape(approval.toolName)}</span></div>${warning ? `<p class=\"pui-approval-warning\">${escape(warning)}</p>` : ''}${previewMarkup}${preview ? `<details class=\"pui-approval-arguments\" ${preview.error ? 'open' : ''}><summary>Tool arguments</summary>${args}</details>` : args}${canAlwaysAllow ? '<p class=\"pui-approval-scope\">Workspace permission applies to this conversation. Commands and external connection tools still need approval.</p>' : ''}<div class=\"pui-approval-actions\"><button class=\"pui-secondary-button\" data-approval=\"deny\" ${state.disabled ? 'disabled' : ''}>Deny</button>${canAlwaysAllow ? `<button class=\"pui-secondary-button pui-always-allow-button\" data-approval=\"always\" ${state.disabled ? 'disabled' : ''}>Always allow workspace changes</button>` : ''}<button class=\"pui-primary-button\" data-approval=\"allow\" ${state.disabled ? 'disabled' : ''}>${icon('check')}Allow this action</button></div></section>` : ''; for (const child of element.children) scopeIds(child as HTMLElement, prefix);\n for (const button of element.querySelectorAll<HTMLButtonElement>('[data-approval]')) button.dataset.approvalId = approval?.id || '';\n if (preview && !preview.error) previews.push(createPagedPreview({container: $<HTMLElement>('approval-diff-preview'), text: preview.diff || 'No content changes.', kind: 'diff'}));\n if (approval) {const argsContainer = $<HTMLElement>('approval-args-preview'); const details = argsContainer.closest('details'); let loaded = false; const showArgs = () => {if (destroyed || loaded || (details && !details.open)) return; loaded = true; previews.push(createPagedPreview({container: argsContainer, text: approval.argsText, kind: 'text'}));}; details?.addEventListener('toggle', showArgs, {signal:contentAbort.signal}); showArgs();}\n }\n for (const button of element.querySelectorAll<HTMLButtonElement>('[data-approval]')) parts.action(button).update({disabled: !!state.disabled});\n parts.update();\n };\n element.addEventListener('click', (event) => {const button = (event.target as HTMLElement).closest<HTMLButtonElement>('[data-approval]'); if (button && !button.disabled) options.onAction?.(button.dataset.approvalId!, button.dataset.approval as 'deny' | 'always' | 'allow');}, {signal:abort.signal});\n update(initial); return {element, update, destroy() {if (destroyed) return; destroyed = true; parts.destroy(); abort.abort(); contentAbort.abort(); for (const preview of previews) preview.destroy(); if (!options.element) element.remove();}};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/tasks/approval.ts"],"names":[],"mappings":"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","sourcesContent":["import {scopeIds} from '../forms/identity.js';\nimport type { UIBlock } from '../core.js';\nimport {icon, uniqueId, setText} from '../dom.js';\nimport {createPagedPreview, type PagedPreviewState} from '../content/paged-preview.js';\nimport {adoptProductParts} from '../foundations.js';\nexport interface ApprovalView {id: string; toolName: string; warning?: string; canAlwaysAllow: boolean; argsText: string; preview?: {kind: string; path: string; error?: string; diff?: string; truncated?: boolean}}\nexport interface ApprovalPanelState {approval: ApprovalView | null; disabled?: boolean}\nexport function createApprovalPanel(initial: ApprovalPanelState, options: {element?: HTMLElement; idPrefix?: string; onAction?: (id: string, action: 'deny' | 'always' | 'allow') => void} = {}): UIBlock<ApprovalPanelState> {\n const element = options.element || document.createElement('div'); if (!options.element) element.className = 'pui-approval-panel';\n const prefix = options.idPrefix ?? uniqueId('pui-approval') + '-', parts = adoptProductParts(element), abort = new AbortController();\n let destroyed = false, current: ApprovalView | null = null, contentAbort = new AbortController();\n let card: HTMLElement | undefined, warning: HTMLElement, badge: HTMLElement, file: HTMLElement, fileKind: HTMLElement, path: HTMLElement, previewError: HTMLElement, diff: HTMLElement, shortened: HTMLElement, details: HTMLDetailsElement, args: HTMLElement, scope: HTMLElement, always: HTMLButtonElement;\n let diffBlock: UIBlock<PagedPreviewState> | undefined, argsBlock: UIBlock<PagedPreviewState> | undefined;\n const clear = () => {contentAbort.abort(); contentAbort = new AbortController(); diffBlock?.destroy(); argsBlock?.destroy(); diffBlock = argsBlock = undefined; card = undefined; element.replaceChildren();};\n const showArgs = () => {if (destroyed || !current || argsBlock || (current.preview && !details.open)) return; argsBlock = createPagedPreview({container:args,text:current.argsText,kind:'text'});};\n function create(): void {\n element.innerHTML = `<section class=\"pui-approval-card\" aria-label=\"Tool approval required\"><div class=\"pui-approval-heading\">${icon('shield')}<div><strong>Pith needs your permission</strong><span>Review this action before it runs.</span></div><span class=\"pui-approval-badge\"></span></div><p class=\"pui-approval-warning\" hidden></p><div class=\"pui-approval-file\" hidden><strong></strong><code></code></div><p class=\"pui-preview-note\" role=\"status\" hidden></p><div id=\"approval-diff-preview\" hidden></div><p class=\"pui-preview-note\" data-shortened hidden>Preview shortened. Expand Tool arguments for the complete change.</p><details class=\"pui-approval-arguments\"><summary>Tool arguments</summary><div id=\"approval-args-preview\"></div></details><p class=\"pui-approval-scope\" hidden>Workspace permission applies to this conversation. Commands and external connection tools still need approval.</p><div class=\"pui-approval-actions\"><button type=\"button\" class=\"pui-secondary-button\" data-approval=\"deny\">Deny</button><button type=\"button\" class=\"pui-secondary-button pui-always-allow-button\" data-approval=\"always\">Always allow workspace changes</button><button type=\"button\" class=\"pui-primary-button\" data-approval=\"allow\">${icon('check')}Allow this action</button></div></section>`;\n card = element.firstElementChild as HTMLElement; scopeIds(card,prefix);\n warning = card.querySelector('.pui-approval-warning')!; badge = card.querySelector('.pui-approval-badge')!; file = card.querySelector('.pui-approval-file')!; fileKind = file.querySelector('strong')!; path = file.querySelector('code')!;\n previewError = card.querySelector('[role=\"status\"]')!; diff = card.querySelector('[id$=\"approval-diff-preview\"]')!; shortened = card.querySelector('[data-shortened]')!; details = card.querySelector('details')!; args = details.querySelector('div')!; scope = card.querySelector('.pui-approval-scope')!; always = card.querySelector('[data-approval=\"always\"]')!;\n details.addEventListener('toggle',showArgs,{signal:contentAbort.signal});\n }\n const update = (state: Readonly<ApprovalPanelState>) => {\n if (destroyed) return; const approval = state.approval, changed = approval?.id !== current?.id; if (changed || !approval) clear(); current = approval;\n if (!approval) {parts.update(); return;}\n const fresh = !card; if (fresh) create(); const preview = approval.preview;\n setText(badge,approval.toolName); setText(warning,approval.warning || ''); warning.hidden = !approval.warning;\n file.hidden = !preview; if (preview) {setText(fileKind,preview.kind === 'create' ? 'Create file' : 'Modify file'); setText(path,preview.path);}\n previewError.hidden = !preview?.error; setText(previewError,preview?.error || '');\n diff.hidden = !preview || !!preview.error; shortened.hidden = !preview || !!preview.error || !preview.truncated;\n if (preview && !preview.error) {const value = {text:preview.diff || 'No content changes.',kind:'diff' as const}; if (diffBlock) diffBlock.update(value); else diffBlock = createPagedPreview({container:diff,...value});}\n else if (diffBlock) {diffBlock.destroy(); diffBlock = undefined;}\n if (preview) {if (args.parentElement !== details) details.append(args); if (details.parentElement !== card) card!.insertBefore(details,scope); if (fresh) details.open = !!preview.error;}\n else {if (args.parentElement !== card) card!.insertBefore(args,scope); details.remove();}\n showArgs(); argsBlock?.update({text:approval.argsText,kind:'text'});\n scope.hidden = !approval.canAlwaysAllow; always.hidden = !approval.canAlwaysAllow;\n for (const button of element.querySelectorAll<HTMLButtonElement>('[data-approval]')) {button.dataset.approvalId = approval.id; parts.action(button).update({disabled:!!state.disabled});}\n parts.update();\n };\n element.addEventListener('click', event => {const button = (event.target as HTMLElement).closest<HTMLButtonElement>('[data-approval]'); if (button && !button.disabled && !button.hidden) options.onAction?.(button.dataset.approvalId!,button.dataset.approval as 'deny' | 'always' | 'allow');}, {signal:abort.signal});\n update(initial); return {element,update,destroy() {if (destroyed) return; destroyed = true; clear(); parts.destroy(); abort.abort(); contentAbort.abort(); if (!options.element) element.remove();}};\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-element.d.ts","sourceRoot":"","sources":["../../src/tasks/permission-element.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,wBAAgB,wBAAwB,IAAI,gBAAgB,CAI3D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { icon } from '../dom.js';
|
|
2
|
+
/** Internal retained-node template shared with the composer shell. */
|
|
3
|
+
export function permissionControlElement() {
|
|
4
|
+
const element = document.createElement('label');
|
|
5
|
+
element.className = 'pui-permission-control';
|
|
6
|
+
element.dataset.puiSelectAnchor = '';
|
|
7
|
+
element.innerHTML = `${icon('shield')}<span class="pui-sr-only">Conversation permissions</span><select><option value="ask">Ask before changes</option><option value="workspace-write">Allow workspace changes</option><option value="full-access">Full access</option></select>${icon('down')}`;
|
|
8
|
+
return element;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=permission-element.js.map
|