@operato/popup 10.29.23 → 10.29.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/coverage/lcov-report/index.html +25 -25
- package/coverage/lcov.info +5697 -5515
- package/dist/src/open-popup.d.ts +2 -2
- package/dist/src/open-popup.js.map +1 -1
- package/dist/src/ox-floating-overlay.d.ts +2 -2
- package/dist/src/ox-floating-overlay.js +12 -0
- package/dist/src/ox-floating-overlay.js.map +1 -1
- package/dist/test/overlay-fit-size.test.d.ts +1 -0
- package/dist/test/overlay-fit-size.test.js +34 -0
- package/dist/test/overlay-fit-size.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/test/overlay-fit-size.test.ts +42 -0
package/dist/src/open-popup.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { TemplateResult } from 'lit';
|
|
|
6
6
|
* @typedef {Object} PopupOptions
|
|
7
7
|
* @property {String} [title] - popup title
|
|
8
8
|
* @property {'center' | 'next' | 'edge'} [hovering] - hovering position (default: 'center'). 'edge' : edge of the HEADERBAR, 'next' : next of the clicked position.
|
|
9
|
-
* @property {'large' | 'medium' | small'} [size] - popup size
|
|
9
|
+
* @property {'large' | 'medium' | 'small' | 'full' | 'fit'} [size] - popup size; 'fit' stands as tall as its content
|
|
10
10
|
* @property {Boolean} [closable] - set whether the close 'X' button is shown on top-right most position (default true)
|
|
11
11
|
* @property {Boolean} [escapable] - ESC closes the popup right away (default false — ESC still works,
|
|
12
12
|
* but asks first)
|
|
@@ -17,7 +17,7 @@ import { TemplateResult } from 'lit';
|
|
|
17
17
|
export type PopupOptions = {
|
|
18
18
|
title?: string;
|
|
19
19
|
hovering?: 'center' | 'next' | 'edge';
|
|
20
|
-
size?: 'large' | 'medium' | 'small' | 'full';
|
|
20
|
+
size?: 'large' | 'medium' | 'small' | 'full' | 'fit';
|
|
21
21
|
closable?: boolean;
|
|
22
22
|
escapable?: boolean;
|
|
23
23
|
backdrop?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-popup.js","sourceRoot":"","sources":["../../src/open-popup.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAA;AAEjC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAkB,MAAM,KAAK,CAAA;AAGlD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AA2E3G;;;;;;;;GAQG;AACH,IAAI,aAAa,GAAG,CAAC,CAAA;AAErB;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,QAAwB,EAAE,UAAwB,EAAE;IAC5E,MAAM,EACJ,KAAK,EACL,IAAI,GAAG,OAAO,EACd,QAAQ,GAAG,KAAK,EAChB,SAAS,GAAG,KAAK,EACjB,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,GAAG,KAAK,EACf,MAAM,EACN,MAAM,EACP,GAAG,OAAO,CAAA;IACX,MAAM,IAAI,GAAG,UAAU,aAAa,EAAE,EAAE,CAAA;IAExC;;;;;;OAMG;IACH,MAAM,QAAQ,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAA;IAElD,MAAM,CACJ,IAAI,CAAA;;aAEK,IAAI;eACF,IAAI;oBACC,QAAQ;;oBAER,QAAQ;iBACX,KAAK,IAAI,EAAE;gBACZ,IAAI;gBACJ,IAAI;oBACA,QAAQ;qBACP,SAAS;sBACR,KAAK;mBACR,OAAO;kBACR,MAAM;kBACN,MAAM;WACb,QAAQ;;KAEd,EACD,QAAQ,CACT,CAAA;IAED,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;IAEnC,qBAAqB,CAAC,GAAG,EAAE;QACzB,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,MAAM,WAAW,GAA8B;QAC7C,IAAI;QACJ,KAAK,EAAE,GAAG,EAAE;YACV;;;eAGG;YACH,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAA6B,CAAA;YACvE,IAAI,CAAC,KAAK;gBAAE,OAAO,KAAK,CAAA;YAExB,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,OAAO,IAAI,CAAA;QACb,CAAC;QACD,MAAM,EAAE,KAAK;KACd,CAAA;IAED;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,SAAS,QAAQ,CAAC,CAAC;QAC7D,IAAI,IAAI,IAAK,CAAiB,CAAC,MAAM,EAAE,CAAC;YACtC,QAAQ,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAA;YACxD,WAAW,CAAC,MAAM,GAAG,IAAI,CAAA;YACzB,WAAW,CAAC,QAAQ,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAA;QAChD,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,IAAI,aAAa,GAAmF,gBAAgB,CAAA;AAEpH;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,cAA8F;IAE9F,aAAa,GAAG,cAAc,CAAA;AAChC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAc,QAAwB,EAAE,UAAwB,EAAE,EAAkB,EAAE;IAC7G,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,OAAO,CAA8B,CAAA;IAC5E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IACxB,MAAM,mBAAmB,GAAG,MAAM,CAAC,KAAiC,CAAA;IAEpE,gBAAgB,CAAC,IAAI,CAAC,CAAA;IAEtB;;;;OAIG;IACH,IAAI,MAAuC,CAAA;IAC3C,MAAM,CAAC,MAAM,GAAG,IAAI,OAAO,CAAgB,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAA;IAEzE,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAA;IAEpC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE;QACxC,YAAY,EAAE,IAAI;QAClB,UAAU,EAAE,IAAI;QAChB,sGAAsG;QACtG,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE;YACd,IAAI,OAAO;gBAAE,OAAM;YACnB,OAAO,GAAG,IAAI,CAAA;YACd,MAAM,CAAC,eAAe,CAAC,IAAI,CAAkB,CAAC,CAAA;YAC9C,cAAc,IAAI,cAAc,EAAE,CAAA;QACpC,CAAC;QACD,GAAG,EAAE,CAAC,EAA4B,EAAE,EAAE;YACpC,cAAc,GAAG,EAAE,CAAA;QACrB,CAAC;KACF,CAAC,CAAA;IAEF,MAAM,CAAC,KAAK,GAAG,CAAC,KAAS,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAE/C,oGAAoG;QACpG,IAAI,CAAC,mBAAmB,EAAE,IAAI,QAAQ,EAAE,CAAC;YACvC,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACzB,CAAC;IACH,CAAC,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAoB,EAAE,GAAG,MAAkB,EAAQ,EAAE;IAC9E,OAAO,CAAC,aAAa,CACnB,IAAI,WAAW,CAAC,eAAe,EAAE;QAC/B,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,0FAA0F;QAC1F,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;KAC9D,CAAC,CACH,CAAA;AACH,CAAC,CAAA","sourcesContent":["import './ox-floating-overlay.js'\n\nimport { html, render, TemplateResult } from 'lit'\n\nimport { OxFloatingOverlay } from './ox-floating-overlay.js'\nimport { beginPopupResult, forgetPopupResult, recordPopupResult, takePopupResult } from './popup-result.js'\n\n/**\n * Options for popup\n *\n * @typedef {Object} PopupOptions\n * @property {String} [title] - popup title\n * @property {'center' | 'next' | 'edge'} [hovering] - hovering position (default: 'center'). 'edge' : edge of the HEADERBAR, 'next' : next of the clicked position.\n * @property {'large' | 'medium' | small'} [size] - popup size\n * @property {Boolean} [closable] - set whether the close 'X' button is shown on top-right most position (default true)\n * @property {Boolean} [escapable] - ESC closes the popup right away (default false — ESC still works,\n * but asks first)\n * @property {Boolean} [backdrop] - set whether to do background masking around the pop-up. If true, it becomes modal (default true)\n * @property {Boolean} [movable] - set whether to be able to movable by the gesture dragging on header once the hovering option is 'center'\n * @property {String} [help] - inline help link\n */\nexport type PopupOptions = {\n title?: string\n hovering?: 'center' | 'next' | 'edge'\n size?: 'large' | 'medium' | 'small' | 'full'\n closable?: boolean\n escapable?: boolean\n backdrop?: boolean\n movable?: boolean\n help?: string\n search?: {\n value?: string\n handler?: (closure: any, value: string) => void\n placeholder?: string\n autofocus?: boolean\n }\n filter?: {\n handler?: (closure: any) => void\n }\n}\n\n/**\n * What an openPopup implementation returns. An implementation makes two promises, and the tests count\n * both for every implementation:\n *\n * 1. `onclosed` is called exactly once when the popup is gone, whichever way it went (its own close,\n * ESC, backdrop, X, history back). `openPopup` settles the result there, so an implementation that\n * forgets it leaves every awaiting opener hanging.\n * 2. `close()` answers whether it closed anything. There is deliberately no default: treating \"no\n * answer\" as closed would keep the value of a request that closed nothing, to surface later as the\n * result of a dismissal; treating it as not closed would drop a real result. Both are wrong, so the\n * type requires the answer.\n */\nexport type PopupImplementationHandle = {\n name: string\n /** True when this call closed the popup (or started closing it); false when it closed nothing. */\n close: () => boolean\n closed: boolean\n onclosed?: () => void\n}\n\n/**\n * Popup handle object returned by openPopup\n *\n * @typedef {Object} PopupHandle\n * @property {String} [name] - popup instance name\n * @property {Function} [close] - closes the popup. A value passed here becomes the result.\n * @property {Boolean} [closed] - state telling whether the popup is closed or not.\n * @property {Function} [onclosed] - callback called once when the popup is gone.\n * @property {Promise} [result] - settles once when the popup is gone: the first value given to\n * `close(value)` or `closePopup(element, value)`, or undefined when it was only dismissed.\n */\nexport type PopupHandle<R = unknown> = {\n name: string\n close: (result?: R) => void\n closed: boolean\n onclosed?: () => void\n result: Promise<R | undefined>\n}\n\n/*\n * popup handling\n *\n * popup은 overlay의 특별한 형태이다.\n * popup은 open될 때, viewpart를 append 하며, close 될 때 viewpart를 remove 한다.\n * - name: '$popup-${popupSequence}'\n * - position: VIEWPART_POSITION_HEADERBAR\n * - hovering: 'center' | 'next' | 'edge'\n */\nvar popupSequence = 0\n\n/**\n * default openPopup implementation for operato application environment\n *\n * @param {*} template html template to be rendered inside the popup\n * @param {PopupOptions} options\n * @returns popup handle object. This object is used to close the popup.\n */\nfunction defaultOpenPopup(template: TemplateResult, options: PopupOptions = {}): PopupImplementationHandle {\n const {\n title,\n size = 'large',\n closable = false,\n escapable = false,\n help,\n hovering,\n backdrop,\n movable = false,\n search,\n filter\n } = options\n const name = `$popup-${popupSequence++}`\n\n /*\n * Render each popup into its own fragment and move it into the body.\n *\n * Rendering straight into document.body made every popup share one lit part: the second\n * openPopup reused the first popup's template instance and updated an overlay that had already\n * removed itself from the document, so after one popup closed no other popup ever appeared.\n */\n const fragment = document.createDocumentFragment()\n\n render(\n html`\n <ox-floating-overlay\n id=${name}\n name=${name}\n .backdrop=${backdrop}\n direction=\"down\"\n .hovering=${hovering}\n .title=${title || ''}\n .help=${help}\n .size=${size}\n .closable=${closable}\n .escapable=${escapable}\n .historical=${false}\n .movable=${movable}\n .search=${search}\n .filter=${filter}\n >${template}</ox-floating-overlay\n >\n `,\n fragment\n )\n\n document.body.appendChild(fragment)\n\n requestAnimationFrame(() => {\n dispatchEvent(new Event('resize'))\n })\n\n const popupHandle: PopupImplementationHandle = {\n name,\n close: () => {\n /*\n * getElementById, not querySelector(`#${name}`): names start with `$`, which is not a valid CSS\n * id selector, so querySelector threw and handle.close() never closed anything here.\n */\n const popup = document.getElementById(name) as OxFloatingOverlay | null\n if (!popup) return false\n\n popup.close()\n return true\n },\n closed: false\n }\n\n /*\n * Report \"closed\" from the one place every path passes: the overlay leaving the document. It\n * announces that itself (`overlay-closed`). Reporting from close() only - as before - missed ESC,\n * the backdrop and X, so `closed` stayed false and `onclosed` never ran for those.\n */\n document.addEventListener('overlay-closed', function listener(e) {\n if (name == (e as CustomEvent).detail) {\n document.removeEventListener('overlay-closed', listener)\n popupHandle.closed = true\n popupHandle.onclosed && popupHandle.onclosed()\n }\n })\n\n return popupHandle\n}\n\nvar openPopupImpl: (template: TemplateResult, options: PopupOptions) => PopupImplementationHandle = defaultOpenPopup\n\n/**\n * replace default openPopup implementation\n *\n * @param {(template: TemplateResult, options: PopupOptions) => PopupImplementationHandle} implementation\n */\nexport function setOpenPopupImplementation(\n implementation: (template: TemplateResult, options: PopupOptions) => PopupImplementationHandle\n) {\n openPopupImpl = implementation\n}\n\n/**\n * open popup out of operato application environment\n *\n * @param {*} template html template to be rendered inside the popup\n * @param {PopupOptions} options\n * @returns popup handle object. This object is used to close the popup.\n */\nexport const openPopup = <R = unknown>(template: TemplateResult, options: PopupOptions = {}): PopupHandle<R> => {\n const handle = openPopupImpl(template, options) as unknown as PopupHandle<R>\n const name = handle.name\n const implementationClose = handle.close as unknown as () => boolean\n\n beginPopupResult(name)\n\n /*\n * The result settles in one place: when the implementation reports the popup gone. Both entrances\n * below only record. Whatever the path - close(value), closePopup(element, value), ESC, backdrop,\n * X, history back - it settles exactly once.\n */\n let settle!: (value: R | undefined) => void\n handle.result = new Promise<R | undefined>(resolve => (settle = resolve))\n\n let settled = false\n let callerOnclosed = handle.onclosed\n\n Object.defineProperty(handle, 'onclosed', {\n configurable: true,\n enumerable: true,\n /* Callers still assign `handle.onclosed = fn`; the implementation still calls `handle.onclosed()`. */\n get: () => () => {\n if (settled) return\n settled = true\n settle(takePopupResult(name) as R | undefined)\n callerOnclosed && callerOnclosed()\n },\n set: (fn: (() => void) | undefined) => {\n callerOnclosed = fn\n }\n })\n\n handle.close = (value?: R) => {\n const recorded = recordPopupResult(name, value)\n\n /* A request that closed nothing must not leave its value behind to surface on a later dismissal. */\n if (!implementationClose() && recorded) {\n forgetPopupResult(name)\n }\n }\n\n return handle\n}\n\n/**\n * close the popup that contains the element, from inside the popup's content\n *\n * The content usually does not hold the handle - openPopup returns it after the template exists - so\n * this is the content's way to give the opener a result without knowing who opened it.\n *\n * @param {HTMLElement} element an element inside the popup content\n * @param {*} [result] becomes the handle's result, unless another close request came first\n */\nexport const closePopup = (element: HTMLElement, ...result: [unknown?]): void => {\n element.dispatchEvent(\n new CustomEvent('close-overlay', {\n bubbles: true,\n composed: true,\n /* Only carries a result when one was given - `closePopup(el)` stays a plain dismissal. */\n detail: result.length > 0 ? { result: result[0] } : undefined\n })\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"open-popup.js","sourceRoot":"","sources":["../../src/open-popup.ts"],"names":[],"mappings":"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","sourcesContent":["import './ox-floating-overlay.js'\n\nimport { html, render, TemplateResult } from 'lit'\n\nimport { OxFloatingOverlay } from './ox-floating-overlay.js'\nimport { beginPopupResult, forgetPopupResult, recordPopupResult, takePopupResult } from './popup-result.js'\n\n/**\n * Options for popup\n *\n * @typedef {Object} PopupOptions\n * @property {String} [title] - popup title\n * @property {'center' | 'next' | 'edge'} [hovering] - hovering position (default: 'center'). 'edge' : edge of the HEADERBAR, 'next' : next of the clicked position.\n * @property {'large' | 'medium' | 'small' | 'full' | 'fit'} [size] - popup size; 'fit' stands as tall as its content\n * @property {Boolean} [closable] - set whether the close 'X' button is shown on top-right most position (default true)\n * @property {Boolean} [escapable] - ESC closes the popup right away (default false — ESC still works,\n * but asks first)\n * @property {Boolean} [backdrop] - set whether to do background masking around the pop-up. If true, it becomes modal (default true)\n * @property {Boolean} [movable] - set whether to be able to movable by the gesture dragging on header once the hovering option is 'center'\n * @property {String} [help] - inline help link\n */\nexport type PopupOptions = {\n title?: string\n hovering?: 'center' | 'next' | 'edge'\n size?: 'large' | 'medium' | 'small' | 'full' | 'fit'\n closable?: boolean\n escapable?: boolean\n backdrop?: boolean\n movable?: boolean\n help?: string\n search?: {\n value?: string\n handler?: (closure: any, value: string) => void\n placeholder?: string\n autofocus?: boolean\n }\n filter?: {\n handler?: (closure: any) => void\n }\n}\n\n/**\n * What an openPopup implementation returns. An implementation makes two promises, and the tests count\n * both for every implementation:\n *\n * 1. `onclosed` is called exactly once when the popup is gone, whichever way it went (its own close,\n * ESC, backdrop, X, history back). `openPopup` settles the result there, so an implementation that\n * forgets it leaves every awaiting opener hanging.\n * 2. `close()` answers whether it closed anything. There is deliberately no default: treating \"no\n * answer\" as closed would keep the value of a request that closed nothing, to surface later as the\n * result of a dismissal; treating it as not closed would drop a real result. Both are wrong, so the\n * type requires the answer.\n */\nexport type PopupImplementationHandle = {\n name: string\n /** True when this call closed the popup (or started closing it); false when it closed nothing. */\n close: () => boolean\n closed: boolean\n onclosed?: () => void\n}\n\n/**\n * Popup handle object returned by openPopup\n *\n * @typedef {Object} PopupHandle\n * @property {String} [name] - popup instance name\n * @property {Function} [close] - closes the popup. A value passed here becomes the result.\n * @property {Boolean} [closed] - state telling whether the popup is closed or not.\n * @property {Function} [onclosed] - callback called once when the popup is gone.\n * @property {Promise} [result] - settles once when the popup is gone: the first value given to\n * `close(value)` or `closePopup(element, value)`, or undefined when it was only dismissed.\n */\nexport type PopupHandle<R = unknown> = {\n name: string\n close: (result?: R) => void\n closed: boolean\n onclosed?: () => void\n result: Promise<R | undefined>\n}\n\n/*\n * popup handling\n *\n * popup은 overlay의 특별한 형태이다.\n * popup은 open될 때, viewpart를 append 하며, close 될 때 viewpart를 remove 한다.\n * - name: '$popup-${popupSequence}'\n * - position: VIEWPART_POSITION_HEADERBAR\n * - hovering: 'center' | 'next' | 'edge'\n */\nvar popupSequence = 0\n\n/**\n * default openPopup implementation for operato application environment\n *\n * @param {*} template html template to be rendered inside the popup\n * @param {PopupOptions} options\n * @returns popup handle object. This object is used to close the popup.\n */\nfunction defaultOpenPopup(template: TemplateResult, options: PopupOptions = {}): PopupImplementationHandle {\n const {\n title,\n size = 'large',\n closable = false,\n escapable = false,\n help,\n hovering,\n backdrop,\n movable = false,\n search,\n filter\n } = options\n const name = `$popup-${popupSequence++}`\n\n /*\n * Render each popup into its own fragment and move it into the body.\n *\n * Rendering straight into document.body made every popup share one lit part: the second\n * openPopup reused the first popup's template instance and updated an overlay that had already\n * removed itself from the document, so after one popup closed no other popup ever appeared.\n */\n const fragment = document.createDocumentFragment()\n\n render(\n html`\n <ox-floating-overlay\n id=${name}\n name=${name}\n .backdrop=${backdrop}\n direction=\"down\"\n .hovering=${hovering}\n .title=${title || ''}\n .help=${help}\n .size=${size}\n .closable=${closable}\n .escapable=${escapable}\n .historical=${false}\n .movable=${movable}\n .search=${search}\n .filter=${filter}\n >${template}</ox-floating-overlay\n >\n `,\n fragment\n )\n\n document.body.appendChild(fragment)\n\n requestAnimationFrame(() => {\n dispatchEvent(new Event('resize'))\n })\n\n const popupHandle: PopupImplementationHandle = {\n name,\n close: () => {\n /*\n * getElementById, not querySelector(`#${name}`): names start with `$`, which is not a valid CSS\n * id selector, so querySelector threw and handle.close() never closed anything here.\n */\n const popup = document.getElementById(name) as OxFloatingOverlay | null\n if (!popup) return false\n\n popup.close()\n return true\n },\n closed: false\n }\n\n /*\n * Report \"closed\" from the one place every path passes: the overlay leaving the document. It\n * announces that itself (`overlay-closed`). Reporting from close() only - as before - missed ESC,\n * the backdrop and X, so `closed` stayed false and `onclosed` never ran for those.\n */\n document.addEventListener('overlay-closed', function listener(e) {\n if (name == (e as CustomEvent).detail) {\n document.removeEventListener('overlay-closed', listener)\n popupHandle.closed = true\n popupHandle.onclosed && popupHandle.onclosed()\n }\n })\n\n return popupHandle\n}\n\nvar openPopupImpl: (template: TemplateResult, options: PopupOptions) => PopupImplementationHandle = defaultOpenPopup\n\n/**\n * replace default openPopup implementation\n *\n * @param {(template: TemplateResult, options: PopupOptions) => PopupImplementationHandle} implementation\n */\nexport function setOpenPopupImplementation(\n implementation: (template: TemplateResult, options: PopupOptions) => PopupImplementationHandle\n) {\n openPopupImpl = implementation\n}\n\n/**\n * open popup out of operato application environment\n *\n * @param {*} template html template to be rendered inside the popup\n * @param {PopupOptions} options\n * @returns popup handle object. This object is used to close the popup.\n */\nexport const openPopup = <R = unknown>(template: TemplateResult, options: PopupOptions = {}): PopupHandle<R> => {\n const handle = openPopupImpl(template, options) as unknown as PopupHandle<R>\n const name = handle.name\n const implementationClose = handle.close as unknown as () => boolean\n\n beginPopupResult(name)\n\n /*\n * The result settles in one place: when the implementation reports the popup gone. Both entrances\n * below only record. Whatever the path - close(value), closePopup(element, value), ESC, backdrop,\n * X, history back - it settles exactly once.\n */\n let settle!: (value: R | undefined) => void\n handle.result = new Promise<R | undefined>(resolve => (settle = resolve))\n\n let settled = false\n let callerOnclosed = handle.onclosed\n\n Object.defineProperty(handle, 'onclosed', {\n configurable: true,\n enumerable: true,\n /* Callers still assign `handle.onclosed = fn`; the implementation still calls `handle.onclosed()`. */\n get: () => () => {\n if (settled) return\n settled = true\n settle(takePopupResult(name) as R | undefined)\n callerOnclosed && callerOnclosed()\n },\n set: (fn: (() => void) | undefined) => {\n callerOnclosed = fn\n }\n })\n\n handle.close = (value?: R) => {\n const recorded = recordPopupResult(name, value)\n\n /* A request that closed nothing must not leave its value behind to surface on a later dismissal. */\n if (!implementationClose() && recorded) {\n forgetPopupResult(name)\n }\n }\n\n return handle\n}\n\n/**\n * close the popup that contains the element, from inside the popup's content\n *\n * The content usually does not hold the handle - openPopup returns it after the template exists - so\n * this is the content's way to give the opener a result without knowing who opened it.\n *\n * @param {HTMLElement} element an element inside the popup content\n * @param {*} [result] becomes the handle's result, unless another close request came first\n */\nexport const closePopup = (element: HTMLElement, ...result: [unknown?]): void => {\n element.dispatchEvent(\n new CustomEvent('close-overlay', {\n bubbles: true,\n composed: true,\n /* Only carries a result when one was given - `closePopup(el)` stays a plain dismissal. */\n detail: result.length > 0 ? { result: result[0] } : undefined\n })\n )\n}\n"]}
|
|
@@ -24,9 +24,9 @@ export declare class OxFloatingOverlay extends LitElement {
|
|
|
24
24
|
hovering?: 'center' | 'edge' | 'next';
|
|
25
25
|
/**
|
|
26
26
|
* A string property that specifies the size of the overlay.
|
|
27
|
-
* Possible values are: 'small', 'medium', or '
|
|
27
|
+
* Possible values are: 'small', 'medium', 'large', 'full', or 'fit' (as tall as its content).
|
|
28
28
|
*/
|
|
29
|
-
size?: 'small' | 'medium' | 'large' | 'full';
|
|
29
|
+
size?: 'small' | 'medium' | 'large' | 'full' | 'fit';
|
|
30
30
|
/**
|
|
31
31
|
* A string property that represents the name of the overlay.
|
|
32
32
|
* This can be used for identification or other purposes.
|
|
@@ -230,6 +230,18 @@ let OxFloatingOverlay = class OxFloatingOverlay extends LitElement {
|
|
|
230
230
|
height: var(--overlay-center-full-height, 100%);
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/*
|
|
234
|
+
* A form of a few fields stands at its own height. The other sizes are fractions of the screen, so
|
|
235
|
+
* five fields in a medium popup left half the card empty under them. Bounded by the screen; past
|
|
236
|
+
* that the content scrolls in its own body.
|
|
237
|
+
*/
|
|
238
|
+
[hovering='center'][size='fit'] {
|
|
239
|
+
width: min(var(--overlay-center-fit-width, 480px), calc(100vw - 32px));
|
|
240
|
+
height: auto;
|
|
241
|
+
max-height: calc(100vh - 32px);
|
|
242
|
+
max-height: calc(100dvh - 32px);
|
|
243
|
+
}
|
|
244
|
+
|
|
233
245
|
[header] {
|
|
234
246
|
--help-icon-color: var(--md-sys-color-on-primary-container);
|
|
235
247
|
--help-icon-hover-color: var(--md-sys-color-on-primary-container);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ox-floating-overlay.js","sourceRoot":"","sources":["../../src/ox-floating-overlay.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n// 순환 참조가 되어서 일단 코멘트 처리함.\n// import '@operato/input/ox-input-search.js'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { i18next } from '@operato/i18n'\n\nimport { OxPrompt } from './ox-prompt.js'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { isHandheldDevice } from '@operato/utils'\n\nimport { claimHistoryBack, recordPopupResult } from './popup-result.js'\n\nfunction getPoint(e: Event): { x: number; y: number } | undefined {\n if ((e as MouseEvent).button == 0) {\n return {\n x: (e as MouseEvent).clientX,\n y: (e as MouseEvent).clientY\n }\n } else if ((e as TouchEvent).touches?.length == 1) {\n const touch = (e as TouchEvent).touches[0]\n return {\n x: touch.clientX,\n y: touch.clientY\n }\n } else {\n return\n }\n}\n\n/**\n * Custom element for creating floating overlays.\n * These overlays can have various properties like direction, size, title, and more.\n * They are often used for modal dialogs, pop-ups, and similar UI elements.\n */\n@customElement('ox-floating-overlay')\nexport class OxFloatingOverlay extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n /* for layout style */\n :host {\n position: relative;\n z-index: var(--z-index, 10);\n /*\n * ── 그림자는 층으로 쌓는다 ──────────────────────────────────────────\n * 전에는 2px 3px 10px 5px 였다 — 오른쪽 아래로 치우친 데다 5px 퍼짐이 있어서 상자 네 변에\n * 회색 테를 두른 것처럼 보였다. 떠 있는 느낌이 아니라 덧그린 느낌이다.\n *\n * 가까운 층 하나로 경계를 세우고, 먼 층 하나로 높이를 만든다. 먼 층은 위로 퍼지지 않게\n * 음수 spread 를 준다 — 빛이 위에서 온다는 그 규칙만 지켜도 상자가 뜬다.\n */\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.06),\n 0 16px 40px -12px rgba(0, 0, 0, 0.28);\n }\n\n :host([hovering='edge']) {\n /* edge hovering 인 경우에는 상위 relative position 크기와 위치를 반영한다. */\n position: initial;\n }\n\n #backdrop {\n position: fixed;\n left: 0;\n top: 0;\n\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n\n background-color: var(--md-sys-color-shadow, #000);\n opacity: 0.4;\n }\n\n [overlayed] {\n position: absolute;\n\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n [overlayed][hovering='center'] {\n position: fixed;\n\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n\n opacity: 0;\n /*\n * ── 테두리는 실선 한 올, 모서리는 둥글게 ────────────────────────────\n * 2px outline 이었다. 화면에서 가장 굵고 가장 진한 선이 상자의 테두리여서, 안에 든 내용보다\n * 상자가 먼저 보였다. 경계는 한 올로 충분하다 — 나머지는 그림자가 맡는다.\n *\n * 모서리도 각이었다. 이 제품의 카드·표는 모두 둥글다(10~14px). 팝업만 각이면 그 하나가\n * 딴 세대의 것으로 보인다.\n *\n * ── --popup-radius 는 **카드의 모서리**다. 여기가 그 임자다 ─────────────\n * 이 값이 팝업 안 컨트롤의 모서리를 함께 정한다 — 모서리는 담는 면을 따른다(동심 모서리).\n * 그 짝은 --popup-control-radius 이고 CommonPopupStyles 가 선언한다. 카드를 각지게\n * 하려면 두 값을 **함께** 내려라. 한쪽만 바꾸면 둥근 틀에 각진 판이 박힌다.\n */\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--popup-radius, 16px);\n }\n\n [overlayed][hovering='center'][opened] {\n opacity: 1;\n transition: opacity 0.3s ease-in;\n background-color: var(--md-sys-color-surface-container-lowest);\n }\n\n [hovering='center'] {\n width: var(--overlay-center-normal-width, 60%);\n height: var(--overlay-center-normal-height, 60%);\n }\n\n [hovering='center'][size='small'] {\n width: var(--overlay-center-small-width, 40%);\n height: var(--overlay-center-small-height, 40%);\n }\n\n [hovering='center'][size='large'] {\n width: var(--overlay-center-large-width, 100%);\n height: var(--overlay-center-large-height, 100%);\n }\n\n [hovering='center'][size='full'] {\n width: var(--overlay-center-full-width, 100%);\n height: var(--overlay-center-full-height, 100%);\n }\n\n [header] {\n --help-icon-color: var(--md-sys-color-on-primary-container);\n --help-icon-hover-color: var(--md-sys-color-on-primary-container);\n\n pointer-events: initial;\n }\n\n [content] {\n flex: 1;\n overflow: hidden;\n }\n\n ::slotted(*) {\n box-sizing: border-box;\n pointer-events: initial;\n }\n\n [hovering='center'] [content] ::slotted(*) {\n width: 100%;\n height: 100%;\n }\n [direction='up'],\n [direction='down'] {\n width: 100%;\n\n max-height: 0;\n transition: max-height 0.7s ease-in;\n }\n [direction='up'] {\n bottom: 0;\n }\n [direction='down'] {\n top: 0;\n }\n\n [direction='up'][opened],\n [direction='down'][opened] {\n max-height: 100vh;\n max-height: 100dvh;\n }\n\n [settled][direction='down'] [content],\n [settled][direction='up'] [content] {\n overflow-y: auto;\n }\n\n [direction='left'],\n [direction='right'] {\n height: 100%;\n\n max-width: 0;\n transition: max-width 0.5s ease-in;\n }\n [direction='left'] {\n right: 0;\n }\n [direction='right'] {\n left: 0;\n }\n\n [direction='left'][opened],\n [direction='right'][opened] {\n max-width: 100vw;\n }\n\n [settled][direction='left'] [content],\n [settled][direction='right'] [content] {\n overflow-x: auto;\n }\n\n @media screen and (max-width: 460px) {\n [direction='up'],\n [direction='down'] {\n max-height: 100vh;\n max-height: 100dvh;\n }\n\n [direction='left'],\n [direction='right'] {\n max-width: 100vw;\n }\n }\n `,\n css`\n /*\n * for header style\n *\n * primary 는 어두운 표면 위에 놓는 강조색이라 큰 면을 채우면 다크에서 밝은 띠가 된다\n * (실제로 팝업 제목줄이 탄색 블록으로 보였다). 제목줄은 표면이므로 container 역할을 쓴다.\n * 앱이 조정하려면 --popup-header-background / --popup-header-color 를 지정한다.\n */\n [header] {\n display: flex;\n flex-direction: row;\n align-items: center;\n /*\n * 머리는 슬래브가 아니다. 채움과 아래 실선을 둘 다 쓰고 있었고, 채움이 한 단 진해서 그 띠가\n * 안에 든 내용보다 무거웠다. 한 단 낮춘다 — 선은 남긴다(목록이 올라올 때 그 선이 머리를 말한다).\n */\n background-color: var(--popup-header-background, var(--md-sys-color-surface-container-low));\n font-weight: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500));\n color: var(--popup-header-color, var(--md-sys-color-on-surface));\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n slot[name='header'] {\n flex: 1;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n text-transform: capitalize;\n }\n\n [name='header']::slotted(*) {\n margin: 0 auto;\n }\n\n [name='header'] > h1 {\n font-size: var(--md-sys-typescale-title-medium-size, 1rem);\n margin-block: 0.4rem;\n }\n\n [historyback] {\n margin-left: var(--spacing-medium);\n margin-right: auto;\n }\n\n [close] {\n margin-left: auto;\n margin-right: var(--spacing-medium);\n }\n\n [historyback],\n [close] {\n display: none;\n }\n\n [closable][close] {\n display: block;\n cursor: pointer;\n }\n\n /*\n * ── 머리의 아이콘은 **꾸밈이 아니라 곁것**이다 ────────────────────────\n *\n * 닫기와 손잡이가 제목과 같은 잉크에 24px 였다. 제목이 16px 이니 **곁것이 내용보다 굵고\n * 컸다** — 팝업을 열면 눈이 먼저 ✕ 로 갔다.\n *\n * 크기는 이 제품의 아이콘 눈금(18~19px)에 맞추고, 색은 한 단 흐리게 두었다가 마우스를\n * 올릴 때만 짙어진다. 누를 자리는 여백으로 넓혀 둔다 — 아이콘이 작아도 28px 안에서 눌린다.\n *\n * 손잡이(drag_indicator)는 그중 **가장 흐리다.** 그것은 동작이 아니라 「여기를 잡으면\n * 움직인다」는 표시이고, 잡으려는 사람은 이미 그 자리를 안다.\n */\n /*\n * 앱이 --popup-header-background 를 primary 같은 짙은 색으로 바꾸면 아이콘도 함께 밝아져야 한다.\n * --popup-header-icon-color 하나로 닫기/뒤로/손잡이 색을 맞추고, 호버 면은 --popup-header-icon-hover-background.\n */\n [header] md-icon {\n --md-icon-size: 18px;\n\n padding: 5px;\n border-radius: 999em;\n color: var(--popup-header-icon-color, var(--md-sys-color-outline));\n transition:\n color 0.12s ease-out,\n background-color 0.12s ease-out;\n }\n\n [header] md-icon[historyback]:hover,\n [header] md-icon[close]:hover {\n color: var(--popup-header-icon-hover-color, var(--md-sys-color-on-surface));\n background-color: var(--popup-header-icon-hover-background, var(--md-sys-color-surface-container-high));\n }\n\n /* 손잡이는 눌리는 것이 아니라 잡히는 것이다. 면을 주지 않고 색만 한 단 올린다. */\n [header] md-icon:not([close]):not([historyback]) {\n color: var(--popup-header-icon-color, var(--md-sys-color-outline-variant));\n opacity: var(--popup-header-handle-opacity, 1);\n cursor: grab;\n }\n\n [header] md-icon:not([close]):not([historyback]):hover {\n color: var(--popup-header-icon-color, var(--md-sys-color-outline));\n opacity: 1;\n }\n\n [search] ox-help-icon {\n color: var(--md-sys-color-on-secondary-container);\n }\n\n [search] {\n --help-icon-color: var(--md-sys-color-primary);\n --help-icon-hover-color: var(--md-sys-color-primary);\n --help-icon-opacity: 0.2;\n --help-icon-size: 20px;\n\n --md-icon-size: 20px;\n\n --input-search-padding: var(--spacing-medium);\n --input-search-focus-border-bottom: none;\n --input-search-font: normal 16px var(--theme-font);\n\n display: flex;\n justify-content: space-between;\n align-items: center;\n\n align-self: center;\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-on-primary);\n border-radius: 999em;\n padding: 0 var(--spacing-medium);\n }\n\n [search] > * {\n align-self: center;\n }\n\n ox-input-search {\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-on-primary);\n border-radius: var(--md-sys-shape-corner-full);\n }\n\n @media screen and (max-width: 460px) {\n [closable][historyback] {\n display: block;\n }\n\n [closable][close] {\n display: none;\n }\n }\n `\n ]\n\n /**\n * A boolean property that determines whether a backdrop should be displayed behind the overlay.\n * Backdrop provides a semi-transparent background that covers the entire screen when the overlay is open.\n */\n @property({ type: Boolean }) backdrop?: boolean = false\n\n /**\n * A string property that specifies the direction in which the overlay should appear.\n * Possible values are: 'up', 'down', 'left', or 'right'.\n */\n @property({ type: String }) direction?: 'up' | 'down' | 'left' | 'right'\n\n /**\n * A string property that reflects the hovering state of the overlay.\n * Possible values are: 'center', 'edge', or 'next'.\n */\n @property({ type: String, reflect: true }) hovering?: 'center' | 'edge' | 'next'\n\n /**\n * A string property that specifies the size of the overlay.\n * Possible values are: 'small', 'medium', or 'large'.\n */\n @property({ type: String }) size?: 'small' | 'medium' | 'large' | 'full'\n\n /**\n * A string property that represents the name of the overlay.\n * This can be used for identification or other purposes.\n */\n @property({ type: String }) name?: string\n\n /**\n * A string property that sets the title of the overlay.\n * The title is typically displayed in the header of the overlay.\n */\n @property({ type: String }) title: string = ''\n\n /**\n * A boolean property that determines whether the overlay can be closed by the user.\n * If set to true, a close button will be displayed in the header.\n */\n @property({ type: Boolean }) closable?: boolean = false\n\n /**\n * An object property that can hold custom properties for the template of the overlay.\n * These properties can be used to customize the template's behavior.\n */\n @property({ type: Object }) templateProperties: any\n\n /**\n * An object property that can hold information related to help or assistance for the overlay.\n * This information may be used to provide additional guidance to users.\n */\n @property({ type: Object }) help: any\n\n /**\n * A boolean property that determines whether the overlay is considered historical.\n * Historical overlays may have specific behavior or interactions, such as navigating back in history.\n */\n /**\n * ESC 로 바로 닫아도 되나.\n *\n * 이 속성이 **없었다.** `openPopup({ escapable: true })` 로 줘도 부품까지 오지 않았고, 값은\n * 브라우저 이력 상태에만 담겨 바탕 클릭 판정에만 쓰였다. 그래서 이 값을 참으로 준 팝업도 ESC\n * 로는 닫히지 않았다.\n *\n * 기본값은 거짓이다 — 잃을 것이 있는 팝업이 실수로 닫히지 않게. 거짓이어도 ESC 는 듣는다.\n * 닫을지 물어본다(`onEscape`).\n */\n @property({ type: Boolean }) escapable?: boolean = false\n\n @property({ type: Boolean }) historical?: boolean = false\n\n /**\n * A boolean property that determines whether the overlay can be moved by dragging.\n * If set to true, the overlay can be repositioned by dragging its header.\n */\n @property({ type: Boolean }) movable?: boolean = false\n\n /**\n * An object property that can hold information related to a search feature within the overlay.\n * It can include properties like 'value', 'handler', and 'placeholder'.\n */\n @property({ type: Object }) search?: {\n value?: string\n handler?: (instance: any, value: string) => void\n placeholder?: string\n }\n\n /**\n * An object property that can hold information related to a filter feature within the overlay.\n * It can include a 'handler' function for filtering content.\n */\n @property({ type: Object }) filter?: { handler?: (instance: any) => void }\n\n /**\n * A numeric property that specifies the z-index of the overlay.\n * The z-index determines the stacking order of the overlay in relation to other elements on the page.\n */\n @property({ type: Number, attribute: 'z-index' }) zIndex?: number\n\n private dragStart?: { x: number; y: number }\n private dragEndHandler = this.onDragEnd.bind(this) as EventListener\n private dragMoveHandler = this.onDragMove.bind(this) as EventListener\n\n @query('[overlayed]') overlayed!: HTMLDivElement\n @query('[content]') content!: HTMLDivElement\n\n render() {\n const direction = this.hovering == 'center' ? undefined : this.direction\n\n const { value = '', handler: searchHandler, placeholder = '', autofocus = true } = this.search || ({} as any)\n const { handler: filterHandler } = this.filter || ({} as any)\n\n const searchable = typeof searchHandler == 'function'\n const filterable = typeof filterHandler == 'function'\n\n return html`\n ${Boolean(this.backdrop)\n ? html`\n <div\n id=\"backdrop\"\n ?hidden=${!this.backdrop}\n @click=${(e: Event) => this.onClose(e, true /* escape */)}\n ></div>\n `\n : html``}\n\n <div\n overlayed\n hovering=${this.hovering || 'center'}\n direction=${ifDefined(direction)}\n size=${this.size || 'medium'}\n @close-overlay=${(e: Event) => {\n e.stopPropagation()\n this.onClose(e, false, (e as CustomEvent).detail)\n }}\n @transitionstart=${(e: Event) => {\n /* to hide scrollbar during transition */\n ;(e.target as HTMLElement).removeAttribute('settled')\n }}\n @transitionend=${(e: Event) => {\n ;(e.target as HTMLElement).setAttribute('settled', '')\n }}\n @click=${(e: MouseEvent) => {\n if (this.backdrop && e.target === this.content) {\n this.onClose(e, true /* escape */)\n }\n }}\n >\n <div\n header\n @mousedown=${this.onDragStart.bind(this)}\n @touchstart=${this.onDragStart.bind(this)}\n draggable=\"false\"\n >\n <md-icon\n role=\"button\"\n tabindex=${this.closable ? 0 : -1}\n @click=${(e: Event) => this.onClose(e)}\n @keydown=${(e: KeyboardEvent) => this.onActivateKey(e, () => this.onClose(e))}\n ?closable=${this.closable}\n historyback\n >arrow_back</md-icon\n >\n ${this.movable ? html`<md-icon>drag_indicator</md-icon>` : html``}\n <slot name=\"header\">\n ${this.title || this.closable\n ? html`\n <h1>\n ${this.title || ''} ${this.help\n ? html`<ox-help-icon .topic=${this.help}></ox-help-icon>`\n : html``}\n </h1>\n `\n : html``}\n ${searchable || filterable\n ? html`\n <div search>\n ${searchable\n ? html` <ox-input-search\n .placeholder=${placeholder}\n .value=${value || ''}\n ?autofocus=${autofocus}\n @change=${(e: Event) => {\n searchHandler(this.firstElementChild, (e.target as any).value)\n }}\n ></ox-input-search>`\n : html``}\n ${this.help && searchable ? html`<ox-help-icon .topic=${this.help}></ox-help-icon>` : html``}\n ${filterable\n ? html`<md-icon\n role=\"button\"\n tabindex=\"0\"\n @click=${(e: MouseEvent) => filterHandler(this.firstElementChild)}\n @keydown=${(e: KeyboardEvent) =>\n this.onActivateKey(e, () => filterHandler(this.firstElementChild))}\n >tune</md-icon\n >`\n : html``}\n </div>\n `\n : html``}\n ${this.help && !searchable && !this.title /* help only */\n ? html`<ox-help-icon .topic=${this.help}></ox-help-icon>`\n : html``}\n </slot>\n <md-icon\n role=\"button\"\n tabindex=${this.closable ? 0 : -1}\n title=${i18next.t('button.close', { defaultValue: 'close' })}\n @click=${(e: Event) => this.onClose(e)}\n @keydown=${(e: KeyboardEvent) => this.onActivateKey(e, () => this.onClose(e))}\n ?closable=${this.closable}\n close\n >close</md-icon\n >\n </div>\n\n <div content>\n <slot> </slot>\n </div>\n </div>\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('templateProperties') && this.templateProperties) {\n var template = this.firstElementChild\n if (template) {\n for (let prop in this.templateProperties) {\n //@ts-ignore\n template[prop] = this.templateProperties[prop]\n }\n }\n }\n }\n\n firstUpdated() {\n if (this.zIndex) {\n this.style.setProperty('--z-index', String(this.zIndex))\n }\n\n requestAnimationFrame(() => {\n /* transition(animation) 효과를 위해 'opened' 속성을 변화시킨다. */\n this.overlayed?.setAttribute('opened', 'true')\n })\n }\n\n /**\n * 팝업을 연 자리. **닫히면 여기로 돌려준다.**\n *\n * 안 돌려주면 포커스가 body 로 떨어진다. 키보드로 일하는 사람은 자기 자리를 잃고,\n * 그리드에서는 팝업을 닫자마자 화살표가 안 먹는다. 대화상자의 표준 동작이다\n * (WAI-ARIA 의 dialog 패턴).\n */\n /**\n * Enter · Space 로도 눌린다.\n *\n * 머리의 표식들은 `md-icon` 이라 **키보드 초점을 받지 못한다.** 마우스로만 닫히는 팝업이 되는데,\n * 이 앱의 `openPopup` 은 기본값이 `escapable: false` 라서 ESC 로도 닫히지 않는다 — 키보드만\n * 쓰는 사람에게는 나갈 방법이 없어진다.\n *\n * 그래서 role · tabindex 를 주고 이 처리기를 단다. Space 는 기본 동작(스크롤)을 막아야 한다.\n */\n /**\n * ── ESC ─────────────────────────────────────────────────────────────────\n *\n * 이 부품은 **ESC 를 아예 듣지 않았다.** `escapable` 은 바탕을 눌렀을 때만 보던 값이라,\n * `escapable: true` 로 연 팝업도 ESC 로는 닫히지 않았다. 문서에는 기본값이 참이라고 적혀\n * 있는데 코드의 기본값은 거짓이다(`open-popup.ts`) — 그 어긋남도 여기서 드러났다.\n *\n * 기본값은 바꾸지 않는다. 팝업마다 무엇을 잃을지 다르고, 그 판단은 여는 쪽이 한다.\n * 대신 **두 갈래로 답한다.**\n *\n * escapable: true 바로 닫는다 — 여는 쪽이 그래도 된다고 말한 것이다\n * escapable: false 닫을지 묻는다 — 실수로 닫히지 않으면서, 나갈 길은 있다\n *\n * 묻는 쪽을 고른 이유: 닫는 길을 막는 것은 잃을 것을 지키는 방법이 아니라 **나갈 길을 없애는**\n * 방법이다. 키보드만 쓰는 사람에게는 그것이 유일한 길일 수 있다.\n *\n * 겹쳐 있으면 **맨 위 것만** 답한다. 둘이 함께 닫히면 뒤엣것까지 사라진다.\n */\n private onEscape = async (event: KeyboardEvent) => {\n if (event.key !== 'Escape' && event.key !== 'Esc') {\n return\n }\n\n if (!this.isTopOverlay()) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n if (this.escapable) {\n this.close()\n return\n }\n\n const leave = await OxPrompt.open({\n type: 'question',\n title: i18next.t('text.close-this-popup', { defaultValue: 'close this popup?' }),\n text: i18next.t('text.unsaved-may-be-lost', { defaultValue: 'anything not saved is lost.' }),\n confirmButton: { text: i18next.t('button.close', { defaultValue: 'close' }) },\n cancelButton: { text: i18next.t('button.cancel', { defaultValue: 'cancel' }) }\n })\n\n if (leave) {\n this.close()\n }\n }\n\n /** 겹친 팝업 중 맨 위인가 — 나중에 붙은 것이 위다. */\n private isTopOverlay(): boolean {\n const root = this.getRootNode() as Document | ShadowRoot\n const all = Array.from(root.querySelectorAll('ox-floating-overlay'))\n\n return all.length === 0 || all[all.length - 1] === this\n }\n\n private onActivateKey(event: KeyboardEvent, run: () => void) {\n if (event.key !== 'Enter' && event.key !== ' ') {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n run()\n }\n\n private opener?: HTMLElement\n\n connectedCallback(): void {\n super.connectedCallback()\n\n /*\n * ESC 는 **문서에서** 듣는다. 초점이 팝업 안에 없을 수도 있는데(연 직후, 또는 바탕을 눌러\n * 초점이 빠졌을 때) 그때도 나갈 수 있어야 한다.\n */\n document.addEventListener('keydown', this.onEscape)\n\n /*\n * 그림자 안에 있는 요소도 찾아 들어간다 — document.activeElement 는 그 요소를 품은\n * 호스트까지만 알려 준다. 그리드의 칸이 그림자 두 겹 안에 있다.\n */\n let active = document.activeElement as HTMLElement | null\n\n while (active?.shadowRoot?.activeElement) {\n active = active.shadowRoot.activeElement as HTMLElement\n }\n\n /* 자기 자신이나 자기 안의 것은 기억하지 않는다 — 돌아갈 자리가 아니다. */\n this.opener = active && !this.contains(active) ? active : undefined\n\n this.movable = this.movable && !isHandheldDevice()\n\n if (this.movable) {\n document.addEventListener('mouseup', this.dragEndHandler)\n document.addEventListener('touchend', this.dragEndHandler)\n document.addEventListener('touchcancel', this.dragEndHandler)\n document.addEventListener('mousemove', this.dragMoveHandler)\n document.addEventListener('touchmove', this.dragMoveHandler)\n }\n }\n\n disconnectedCallback() {\n document.removeEventListener('keydown', this.onEscape)\n\n document.dispatchEvent(\n new CustomEvent('overlay-closed', {\n detail: this.name\n })\n )\n\n /*\n * 열어 준 자리로 돌려준다.\n *\n * **사라졌으면 조용히 넘어간다** — 줄이 다시 그려졌거나 목록이 바뀌었으면 그 요소는 이미\n * 문서에 없다. 없는 곳에 포커스를 주려다 오류를 내면 팝업 닫기가 통째로 멈춘다.\n *\n * 다음 프레임에 준다. 지금 주면 아직 이 오버레이가 떼어지는 중이라 브라우저가 다시\n * 가져간다.\n */\n const opener = this.opener\n\n this.opener = undefined\n\n if (opener?.isConnected) {\n requestAnimationFrame(() => {\n try {\n opener.focus({ preventScroll: true })\n } catch (e) {\n /* 포커스를 못 받는 요소였다. 팝업 닫기를 막을 일은 아니다. */\n }\n })\n }\n\n if (this.movable) {\n document.removeEventListener('mouseup', this.dragEndHandler!)\n document.removeEventListener('touchend', this.dragEndHandler!)\n document.removeEventListener('touchcancel', this.dragEndHandler!)\n document.removeEventListener('mousemove', this.dragMoveHandler!)\n document.removeEventListener('touchmove', this.dragMoveHandler!)\n }\n\n super.disconnectedCallback()\n }\n\n onDragStart(e: Event) {\n if (!this.movable) {\n return\n }\n\n const point = getPoint(e)\n\n if (point) {\n this.dragStart = point\n e.stopPropagation()\n return false\n }\n }\n\n onDragMove(e: Event) {\n if (!this.movable || !this.dragStart) {\n return false\n }\n\n const point = getPoint(e)\n\n if (!point) {\n return false\n }\n\n e.stopPropagation()\n e.preventDefault()\n\n const dragStart = point\n var { x, y } = point\n\n x -= this.dragStart.x\n y -= this.dragStart.y\n\n this.dragStart = dragStart\n\n const overlayed = this.overlayed\n\n var boundingRect = overlayed.getBoundingClientRect()\n\n overlayed.style.left =\n Math.min(document.body.offsetWidth - 40, Math.max(40 - overlayed.offsetWidth, boundingRect.left + x)) + 'px'\n overlayed.style.top = Math.min(document.body.offsetHeight - 40, Math.max(0, boundingRect.top + y)) + 'px'\n\n overlayed.style.transform = 'initial'\n\n return false\n }\n\n onDragEnd(e: Event) {\n if (this.movable && this.dragStart) {\n e.stopPropagation()\n e.preventDefault()\n\n delete this.dragStart\n }\n }\n\n /**\n * A method that closes the overlay by removing it from its parent node in the DOM.\n * When called, this method removes the overlay element, effectively hiding it from the user interface.\n */\n close() {\n this.parentNode?.removeChild(this)\n }\n\n onClose(e: Event, escape?: boolean, request?: { result: unknown }) {\n e.stopPropagation()\n /* 현재 overlay state를 확인해서, 자신이 포함하고 있는 템플릿인 경우에 history.back() 한다. */\n\n if (this.historical) {\n var state = history.state\n var overlay = (state || {}).overlay\n\n if (!overlay || overlay.name !== this.name) {\n return\n }\n\n /* Backdrop click 경우는 escape 시도라고 정의한다. overlay 속성이 escapable이 아닌 경우에는 동작하지 않는다. */\n if (escape && !overlay.escapable) {\n return true\n }\n\n /* A second close in the same tick would see the same state and go back one page too far. */\n if (!claimHistoryBack(overlay.name)) {\n return\n }\n\n this.recordResult(request)\n history.back()\n } else {\n this.recordResult(request)\n this.close()\n }\n }\n\n /*\n * A value from the content (`closePopup(element, value)`) is recorded only once the overlay is really\n * going to close, and nothing settles here - the result settles when the overlay leaves the document,\n * where every way of closing ends. If another request recorded first, this value is dropped.\n */\n private recordResult(request?: { result: unknown }) {\n if (request && 'result' in request) {\n recordPopupResult(this.name, request.result)\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ox-floating-overlay.js","sourceRoot":"","sources":["../../src/ox-floating-overlay.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n// 순환 참조가 되어서 일단 코멘트 처리함.\n// import '@operato/input/ox-input-search.js'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { i18next } from '@operato/i18n'\n\nimport { OxPrompt } from './ox-prompt.js'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { isHandheldDevice } from '@operato/utils'\n\nimport { claimHistoryBack, recordPopupResult } from './popup-result.js'\n\nfunction getPoint(e: Event): { x: number; y: number } | undefined {\n if ((e as MouseEvent).button == 0) {\n return {\n x: (e as MouseEvent).clientX,\n y: (e as MouseEvent).clientY\n }\n } else if ((e as TouchEvent).touches?.length == 1) {\n const touch = (e as TouchEvent).touches[0]\n return {\n x: touch.clientX,\n y: touch.clientY\n }\n } else {\n return\n }\n}\n\n/**\n * Custom element for creating floating overlays.\n * These overlays can have various properties like direction, size, title, and more.\n * They are often used for modal dialogs, pop-ups, and similar UI elements.\n */\n@customElement('ox-floating-overlay')\nexport class OxFloatingOverlay extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n /* for layout style */\n :host {\n position: relative;\n z-index: var(--z-index, 10);\n /*\n * ── 그림자는 층으로 쌓는다 ──────────────────────────────────────────\n * 전에는 2px 3px 10px 5px 였다 — 오른쪽 아래로 치우친 데다 5px 퍼짐이 있어서 상자 네 변에\n * 회색 테를 두른 것처럼 보였다. 떠 있는 느낌이 아니라 덧그린 느낌이다.\n *\n * 가까운 층 하나로 경계를 세우고, 먼 층 하나로 높이를 만든다. 먼 층은 위로 퍼지지 않게\n * 음수 spread 를 준다 — 빛이 위에서 온다는 그 규칙만 지켜도 상자가 뜬다.\n */\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.06),\n 0 16px 40px -12px rgba(0, 0, 0, 0.28);\n }\n\n :host([hovering='edge']) {\n /* edge hovering 인 경우에는 상위 relative position 크기와 위치를 반영한다. */\n position: initial;\n }\n\n #backdrop {\n position: fixed;\n left: 0;\n top: 0;\n\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n\n background-color: var(--md-sys-color-shadow, #000);\n opacity: 0.4;\n }\n\n [overlayed] {\n position: absolute;\n\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n [overlayed][hovering='center'] {\n position: fixed;\n\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n\n opacity: 0;\n /*\n * ── 테두리는 실선 한 올, 모서리는 둥글게 ────────────────────────────\n * 2px outline 이었다. 화면에서 가장 굵고 가장 진한 선이 상자의 테두리여서, 안에 든 내용보다\n * 상자가 먼저 보였다. 경계는 한 올로 충분하다 — 나머지는 그림자가 맡는다.\n *\n * 모서리도 각이었다. 이 제품의 카드·표는 모두 둥글다(10~14px). 팝업만 각이면 그 하나가\n * 딴 세대의 것으로 보인다.\n *\n * ── --popup-radius 는 **카드의 모서리**다. 여기가 그 임자다 ─────────────\n * 이 값이 팝업 안 컨트롤의 모서리를 함께 정한다 — 모서리는 담는 면을 따른다(동심 모서리).\n * 그 짝은 --popup-control-radius 이고 CommonPopupStyles 가 선언한다. 카드를 각지게\n * 하려면 두 값을 **함께** 내려라. 한쪽만 바꾸면 둥근 틀에 각진 판이 박힌다.\n */\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--popup-radius, 16px);\n }\n\n [overlayed][hovering='center'][opened] {\n opacity: 1;\n transition: opacity 0.3s ease-in;\n background-color: var(--md-sys-color-surface-container-lowest);\n }\n\n [hovering='center'] {\n width: var(--overlay-center-normal-width, 60%);\n height: var(--overlay-center-normal-height, 60%);\n }\n\n [hovering='center'][size='small'] {\n width: var(--overlay-center-small-width, 40%);\n height: var(--overlay-center-small-height, 40%);\n }\n\n [hovering='center'][size='large'] {\n width: var(--overlay-center-large-width, 100%);\n height: var(--overlay-center-large-height, 100%);\n }\n\n [hovering='center'][size='full'] {\n width: var(--overlay-center-full-width, 100%);\n height: var(--overlay-center-full-height, 100%);\n }\n\n /*\n * A form of a few fields stands at its own height. The other sizes are fractions of the screen, so\n * five fields in a medium popup left half the card empty under them. Bounded by the screen; past\n * that the content scrolls in its own body.\n */\n [hovering='center'][size='fit'] {\n width: min(var(--overlay-center-fit-width, 480px), calc(100vw - 32px));\n height: auto;\n max-height: calc(100vh - 32px);\n max-height: calc(100dvh - 32px);\n }\n\n [header] {\n --help-icon-color: var(--md-sys-color-on-primary-container);\n --help-icon-hover-color: var(--md-sys-color-on-primary-container);\n\n pointer-events: initial;\n }\n\n [content] {\n flex: 1;\n overflow: hidden;\n }\n\n ::slotted(*) {\n box-sizing: border-box;\n pointer-events: initial;\n }\n\n [hovering='center'] [content] ::slotted(*) {\n width: 100%;\n height: 100%;\n }\n [direction='up'],\n [direction='down'] {\n width: 100%;\n\n max-height: 0;\n transition: max-height 0.7s ease-in;\n }\n [direction='up'] {\n bottom: 0;\n }\n [direction='down'] {\n top: 0;\n }\n\n [direction='up'][opened],\n [direction='down'][opened] {\n max-height: 100vh;\n max-height: 100dvh;\n }\n\n [settled][direction='down'] [content],\n [settled][direction='up'] [content] {\n overflow-y: auto;\n }\n\n [direction='left'],\n [direction='right'] {\n height: 100%;\n\n max-width: 0;\n transition: max-width 0.5s ease-in;\n }\n [direction='left'] {\n right: 0;\n }\n [direction='right'] {\n left: 0;\n }\n\n [direction='left'][opened],\n [direction='right'][opened] {\n max-width: 100vw;\n }\n\n [settled][direction='left'] [content],\n [settled][direction='right'] [content] {\n overflow-x: auto;\n }\n\n @media screen and (max-width: 460px) {\n [direction='up'],\n [direction='down'] {\n max-height: 100vh;\n max-height: 100dvh;\n }\n\n [direction='left'],\n [direction='right'] {\n max-width: 100vw;\n }\n }\n `,\n css`\n /*\n * for header style\n *\n * primary 는 어두운 표면 위에 놓는 강조색이라 큰 면을 채우면 다크에서 밝은 띠가 된다\n * (실제로 팝업 제목줄이 탄색 블록으로 보였다). 제목줄은 표면이므로 container 역할을 쓴다.\n * 앱이 조정하려면 --popup-header-background / --popup-header-color 를 지정한다.\n */\n [header] {\n display: flex;\n flex-direction: row;\n align-items: center;\n /*\n * 머리는 슬래브가 아니다. 채움과 아래 실선을 둘 다 쓰고 있었고, 채움이 한 단 진해서 그 띠가\n * 안에 든 내용보다 무거웠다. 한 단 낮춘다 — 선은 남긴다(목록이 올라올 때 그 선이 머리를 말한다).\n */\n background-color: var(--popup-header-background, var(--md-sys-color-surface-container-low));\n font-weight: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500));\n color: var(--popup-header-color, var(--md-sys-color-on-surface));\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n slot[name='header'] {\n flex: 1;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n text-transform: capitalize;\n }\n\n [name='header']::slotted(*) {\n margin: 0 auto;\n }\n\n [name='header'] > h1 {\n font-size: var(--md-sys-typescale-title-medium-size, 1rem);\n margin-block: 0.4rem;\n }\n\n [historyback] {\n margin-left: var(--spacing-medium);\n margin-right: auto;\n }\n\n [close] {\n margin-left: auto;\n margin-right: var(--spacing-medium);\n }\n\n [historyback],\n [close] {\n display: none;\n }\n\n [closable][close] {\n display: block;\n cursor: pointer;\n }\n\n /*\n * ── 머리의 아이콘은 **꾸밈이 아니라 곁것**이다 ────────────────────────\n *\n * 닫기와 손잡이가 제목과 같은 잉크에 24px 였다. 제목이 16px 이니 **곁것이 내용보다 굵고\n * 컸다** — 팝업을 열면 눈이 먼저 ✕ 로 갔다.\n *\n * 크기는 이 제품의 아이콘 눈금(18~19px)에 맞추고, 색은 한 단 흐리게 두었다가 마우스를\n * 올릴 때만 짙어진다. 누를 자리는 여백으로 넓혀 둔다 — 아이콘이 작아도 28px 안에서 눌린다.\n *\n * 손잡이(drag_indicator)는 그중 **가장 흐리다.** 그것은 동작이 아니라 「여기를 잡으면\n * 움직인다」는 표시이고, 잡으려는 사람은 이미 그 자리를 안다.\n */\n /*\n * 앱이 --popup-header-background 를 primary 같은 짙은 색으로 바꾸면 아이콘도 함께 밝아져야 한다.\n * --popup-header-icon-color 하나로 닫기/뒤로/손잡이 색을 맞추고, 호버 면은 --popup-header-icon-hover-background.\n */\n [header] md-icon {\n --md-icon-size: 18px;\n\n padding: 5px;\n border-radius: 999em;\n color: var(--popup-header-icon-color, var(--md-sys-color-outline));\n transition:\n color 0.12s ease-out,\n background-color 0.12s ease-out;\n }\n\n [header] md-icon[historyback]:hover,\n [header] md-icon[close]:hover {\n color: var(--popup-header-icon-hover-color, var(--md-sys-color-on-surface));\n background-color: var(--popup-header-icon-hover-background, var(--md-sys-color-surface-container-high));\n }\n\n /* 손잡이는 눌리는 것이 아니라 잡히는 것이다. 면을 주지 않고 색만 한 단 올린다. */\n [header] md-icon:not([close]):not([historyback]) {\n color: var(--popup-header-icon-color, var(--md-sys-color-outline-variant));\n opacity: var(--popup-header-handle-opacity, 1);\n cursor: grab;\n }\n\n [header] md-icon:not([close]):not([historyback]):hover {\n color: var(--popup-header-icon-color, var(--md-sys-color-outline));\n opacity: 1;\n }\n\n [search] ox-help-icon {\n color: var(--md-sys-color-on-secondary-container);\n }\n\n [search] {\n --help-icon-color: var(--md-sys-color-primary);\n --help-icon-hover-color: var(--md-sys-color-primary);\n --help-icon-opacity: 0.2;\n --help-icon-size: 20px;\n\n --md-icon-size: 20px;\n\n --input-search-padding: var(--spacing-medium);\n --input-search-focus-border-bottom: none;\n --input-search-font: normal 16px var(--theme-font);\n\n display: flex;\n justify-content: space-between;\n align-items: center;\n\n align-self: center;\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-on-primary);\n border-radius: 999em;\n padding: 0 var(--spacing-medium);\n }\n\n [search] > * {\n align-self: center;\n }\n\n ox-input-search {\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-on-primary);\n border-radius: var(--md-sys-shape-corner-full);\n }\n\n @media screen and (max-width: 460px) {\n [closable][historyback] {\n display: block;\n }\n\n [closable][close] {\n display: none;\n }\n }\n `\n ]\n\n /**\n * A boolean property that determines whether a backdrop should be displayed behind the overlay.\n * Backdrop provides a semi-transparent background that covers the entire screen when the overlay is open.\n */\n @property({ type: Boolean }) backdrop?: boolean = false\n\n /**\n * A string property that specifies the direction in which the overlay should appear.\n * Possible values are: 'up', 'down', 'left', or 'right'.\n */\n @property({ type: String }) direction?: 'up' | 'down' | 'left' | 'right'\n\n /**\n * A string property that reflects the hovering state of the overlay.\n * Possible values are: 'center', 'edge', or 'next'.\n */\n @property({ type: String, reflect: true }) hovering?: 'center' | 'edge' | 'next'\n\n /**\n * A string property that specifies the size of the overlay.\n * Possible values are: 'small', 'medium', 'large', 'full', or 'fit' (as tall as its content).\n */\n @property({ type: String }) size?: 'small' | 'medium' | 'large' | 'full' | 'fit'\n\n /**\n * A string property that represents the name of the overlay.\n * This can be used for identification or other purposes.\n */\n @property({ type: String }) name?: string\n\n /**\n * A string property that sets the title of the overlay.\n * The title is typically displayed in the header of the overlay.\n */\n @property({ type: String }) title: string = ''\n\n /**\n * A boolean property that determines whether the overlay can be closed by the user.\n * If set to true, a close button will be displayed in the header.\n */\n @property({ type: Boolean }) closable?: boolean = false\n\n /**\n * An object property that can hold custom properties for the template of the overlay.\n * These properties can be used to customize the template's behavior.\n */\n @property({ type: Object }) templateProperties: any\n\n /**\n * An object property that can hold information related to help or assistance for the overlay.\n * This information may be used to provide additional guidance to users.\n */\n @property({ type: Object }) help: any\n\n /**\n * A boolean property that determines whether the overlay is considered historical.\n * Historical overlays may have specific behavior or interactions, such as navigating back in history.\n */\n /**\n * ESC 로 바로 닫아도 되나.\n *\n * 이 속성이 **없었다.** `openPopup({ escapable: true })` 로 줘도 부품까지 오지 않았고, 값은\n * 브라우저 이력 상태에만 담겨 바탕 클릭 판정에만 쓰였다. 그래서 이 값을 참으로 준 팝업도 ESC\n * 로는 닫히지 않았다.\n *\n * 기본값은 거짓이다 — 잃을 것이 있는 팝업이 실수로 닫히지 않게. 거짓이어도 ESC 는 듣는다.\n * 닫을지 물어본다(`onEscape`).\n */\n @property({ type: Boolean }) escapable?: boolean = false\n\n @property({ type: Boolean }) historical?: boolean = false\n\n /**\n * A boolean property that determines whether the overlay can be moved by dragging.\n * If set to true, the overlay can be repositioned by dragging its header.\n */\n @property({ type: Boolean }) movable?: boolean = false\n\n /**\n * An object property that can hold information related to a search feature within the overlay.\n * It can include properties like 'value', 'handler', and 'placeholder'.\n */\n @property({ type: Object }) search?: {\n value?: string\n handler?: (instance: any, value: string) => void\n placeholder?: string\n }\n\n /**\n * An object property that can hold information related to a filter feature within the overlay.\n * It can include a 'handler' function for filtering content.\n */\n @property({ type: Object }) filter?: { handler?: (instance: any) => void }\n\n /**\n * A numeric property that specifies the z-index of the overlay.\n * The z-index determines the stacking order of the overlay in relation to other elements on the page.\n */\n @property({ type: Number, attribute: 'z-index' }) zIndex?: number\n\n private dragStart?: { x: number; y: number }\n private dragEndHandler = this.onDragEnd.bind(this) as EventListener\n private dragMoveHandler = this.onDragMove.bind(this) as EventListener\n\n @query('[overlayed]') overlayed!: HTMLDivElement\n @query('[content]') content!: HTMLDivElement\n\n render() {\n const direction = this.hovering == 'center' ? undefined : this.direction\n\n const { value = '', handler: searchHandler, placeholder = '', autofocus = true } = this.search || ({} as any)\n const { handler: filterHandler } = this.filter || ({} as any)\n\n const searchable = typeof searchHandler == 'function'\n const filterable = typeof filterHandler == 'function'\n\n return html`\n ${Boolean(this.backdrop)\n ? html`\n <div\n id=\"backdrop\"\n ?hidden=${!this.backdrop}\n @click=${(e: Event) => this.onClose(e, true /* escape */)}\n ></div>\n `\n : html``}\n\n <div\n overlayed\n hovering=${this.hovering || 'center'}\n direction=${ifDefined(direction)}\n size=${this.size || 'medium'}\n @close-overlay=${(e: Event) => {\n e.stopPropagation()\n this.onClose(e, false, (e as CustomEvent).detail)\n }}\n @transitionstart=${(e: Event) => {\n /* to hide scrollbar during transition */\n ;(e.target as HTMLElement).removeAttribute('settled')\n }}\n @transitionend=${(e: Event) => {\n ;(e.target as HTMLElement).setAttribute('settled', '')\n }}\n @click=${(e: MouseEvent) => {\n if (this.backdrop && e.target === this.content) {\n this.onClose(e, true /* escape */)\n }\n }}\n >\n <div\n header\n @mousedown=${this.onDragStart.bind(this)}\n @touchstart=${this.onDragStart.bind(this)}\n draggable=\"false\"\n >\n <md-icon\n role=\"button\"\n tabindex=${this.closable ? 0 : -1}\n @click=${(e: Event) => this.onClose(e)}\n @keydown=${(e: KeyboardEvent) => this.onActivateKey(e, () => this.onClose(e))}\n ?closable=${this.closable}\n historyback\n >arrow_back</md-icon\n >\n ${this.movable ? html`<md-icon>drag_indicator</md-icon>` : html``}\n <slot name=\"header\">\n ${this.title || this.closable\n ? html`\n <h1>\n ${this.title || ''} ${this.help\n ? html`<ox-help-icon .topic=${this.help}></ox-help-icon>`\n : html``}\n </h1>\n `\n : html``}\n ${searchable || filterable\n ? html`\n <div search>\n ${searchable\n ? html` <ox-input-search\n .placeholder=${placeholder}\n .value=${value || ''}\n ?autofocus=${autofocus}\n @change=${(e: Event) => {\n searchHandler(this.firstElementChild, (e.target as any).value)\n }}\n ></ox-input-search>`\n : html``}\n ${this.help && searchable ? html`<ox-help-icon .topic=${this.help}></ox-help-icon>` : html``}\n ${filterable\n ? html`<md-icon\n role=\"button\"\n tabindex=\"0\"\n @click=${(e: MouseEvent) => filterHandler(this.firstElementChild)}\n @keydown=${(e: KeyboardEvent) =>\n this.onActivateKey(e, () => filterHandler(this.firstElementChild))}\n >tune</md-icon\n >`\n : html``}\n </div>\n `\n : html``}\n ${this.help && !searchable && !this.title /* help only */\n ? html`<ox-help-icon .topic=${this.help}></ox-help-icon>`\n : html``}\n </slot>\n <md-icon\n role=\"button\"\n tabindex=${this.closable ? 0 : -1}\n title=${i18next.t('button.close', { defaultValue: 'close' })}\n @click=${(e: Event) => this.onClose(e)}\n @keydown=${(e: KeyboardEvent) => this.onActivateKey(e, () => this.onClose(e))}\n ?closable=${this.closable}\n close\n >close</md-icon\n >\n </div>\n\n <div content>\n <slot> </slot>\n </div>\n </div>\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('templateProperties') && this.templateProperties) {\n var template = this.firstElementChild\n if (template) {\n for (let prop in this.templateProperties) {\n //@ts-ignore\n template[prop] = this.templateProperties[prop]\n }\n }\n }\n }\n\n firstUpdated() {\n if (this.zIndex) {\n this.style.setProperty('--z-index', String(this.zIndex))\n }\n\n requestAnimationFrame(() => {\n /* transition(animation) 효과를 위해 'opened' 속성을 변화시킨다. */\n this.overlayed?.setAttribute('opened', 'true')\n })\n }\n\n /**\n * 팝업을 연 자리. **닫히면 여기로 돌려준다.**\n *\n * 안 돌려주면 포커스가 body 로 떨어진다. 키보드로 일하는 사람은 자기 자리를 잃고,\n * 그리드에서는 팝업을 닫자마자 화살표가 안 먹는다. 대화상자의 표준 동작이다\n * (WAI-ARIA 의 dialog 패턴).\n */\n /**\n * Enter · Space 로도 눌린다.\n *\n * 머리의 표식들은 `md-icon` 이라 **키보드 초점을 받지 못한다.** 마우스로만 닫히는 팝업이 되는데,\n * 이 앱의 `openPopup` 은 기본값이 `escapable: false` 라서 ESC 로도 닫히지 않는다 — 키보드만\n * 쓰는 사람에게는 나갈 방법이 없어진다.\n *\n * 그래서 role · tabindex 를 주고 이 처리기를 단다. Space 는 기본 동작(스크롤)을 막아야 한다.\n */\n /**\n * ── ESC ─────────────────────────────────────────────────────────────────\n *\n * 이 부품은 **ESC 를 아예 듣지 않았다.** `escapable` 은 바탕을 눌렀을 때만 보던 값이라,\n * `escapable: true` 로 연 팝업도 ESC 로는 닫히지 않았다. 문서에는 기본값이 참이라고 적혀\n * 있는데 코드의 기본값은 거짓이다(`open-popup.ts`) — 그 어긋남도 여기서 드러났다.\n *\n * 기본값은 바꾸지 않는다. 팝업마다 무엇을 잃을지 다르고, 그 판단은 여는 쪽이 한다.\n * 대신 **두 갈래로 답한다.**\n *\n * escapable: true 바로 닫는다 — 여는 쪽이 그래도 된다고 말한 것이다\n * escapable: false 닫을지 묻는다 — 실수로 닫히지 않으면서, 나갈 길은 있다\n *\n * 묻는 쪽을 고른 이유: 닫는 길을 막는 것은 잃을 것을 지키는 방법이 아니라 **나갈 길을 없애는**\n * 방법이다. 키보드만 쓰는 사람에게는 그것이 유일한 길일 수 있다.\n *\n * 겹쳐 있으면 **맨 위 것만** 답한다. 둘이 함께 닫히면 뒤엣것까지 사라진다.\n */\n private onEscape = async (event: KeyboardEvent) => {\n if (event.key !== 'Escape' && event.key !== 'Esc') {\n return\n }\n\n if (!this.isTopOverlay()) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n if (this.escapable) {\n this.close()\n return\n }\n\n const leave = await OxPrompt.open({\n type: 'question',\n title: i18next.t('text.close-this-popup', { defaultValue: 'close this popup?' }),\n text: i18next.t('text.unsaved-may-be-lost', { defaultValue: 'anything not saved is lost.' }),\n confirmButton: { text: i18next.t('button.close', { defaultValue: 'close' }) },\n cancelButton: { text: i18next.t('button.cancel', { defaultValue: 'cancel' }) }\n })\n\n if (leave) {\n this.close()\n }\n }\n\n /** 겹친 팝업 중 맨 위인가 — 나중에 붙은 것이 위다. */\n private isTopOverlay(): boolean {\n const root = this.getRootNode() as Document | ShadowRoot\n const all = Array.from(root.querySelectorAll('ox-floating-overlay'))\n\n return all.length === 0 || all[all.length - 1] === this\n }\n\n private onActivateKey(event: KeyboardEvent, run: () => void) {\n if (event.key !== 'Enter' && event.key !== ' ') {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n run()\n }\n\n private opener?: HTMLElement\n\n connectedCallback(): void {\n super.connectedCallback()\n\n /*\n * ESC 는 **문서에서** 듣는다. 초점이 팝업 안에 없을 수도 있는데(연 직후, 또는 바탕을 눌러\n * 초점이 빠졌을 때) 그때도 나갈 수 있어야 한다.\n */\n document.addEventListener('keydown', this.onEscape)\n\n /*\n * 그림자 안에 있는 요소도 찾아 들어간다 — document.activeElement 는 그 요소를 품은\n * 호스트까지만 알려 준다. 그리드의 칸이 그림자 두 겹 안에 있다.\n */\n let active = document.activeElement as HTMLElement | null\n\n while (active?.shadowRoot?.activeElement) {\n active = active.shadowRoot.activeElement as HTMLElement\n }\n\n /* 자기 자신이나 자기 안의 것은 기억하지 않는다 — 돌아갈 자리가 아니다. */\n this.opener = active && !this.contains(active) ? active : undefined\n\n this.movable = this.movable && !isHandheldDevice()\n\n if (this.movable) {\n document.addEventListener('mouseup', this.dragEndHandler)\n document.addEventListener('touchend', this.dragEndHandler)\n document.addEventListener('touchcancel', this.dragEndHandler)\n document.addEventListener('mousemove', this.dragMoveHandler)\n document.addEventListener('touchmove', this.dragMoveHandler)\n }\n }\n\n disconnectedCallback() {\n document.removeEventListener('keydown', this.onEscape)\n\n document.dispatchEvent(\n new CustomEvent('overlay-closed', {\n detail: this.name\n })\n )\n\n /*\n * 열어 준 자리로 돌려준다.\n *\n * **사라졌으면 조용히 넘어간다** — 줄이 다시 그려졌거나 목록이 바뀌었으면 그 요소는 이미\n * 문서에 없다. 없는 곳에 포커스를 주려다 오류를 내면 팝업 닫기가 통째로 멈춘다.\n *\n * 다음 프레임에 준다. 지금 주면 아직 이 오버레이가 떼어지는 중이라 브라우저가 다시\n * 가져간다.\n */\n const opener = this.opener\n\n this.opener = undefined\n\n if (opener?.isConnected) {\n requestAnimationFrame(() => {\n try {\n opener.focus({ preventScroll: true })\n } catch (e) {\n /* 포커스를 못 받는 요소였다. 팝업 닫기를 막을 일은 아니다. */\n }\n })\n }\n\n if (this.movable) {\n document.removeEventListener('mouseup', this.dragEndHandler!)\n document.removeEventListener('touchend', this.dragEndHandler!)\n document.removeEventListener('touchcancel', this.dragEndHandler!)\n document.removeEventListener('mousemove', this.dragMoveHandler!)\n document.removeEventListener('touchmove', this.dragMoveHandler!)\n }\n\n super.disconnectedCallback()\n }\n\n onDragStart(e: Event) {\n if (!this.movable) {\n return\n }\n\n const point = getPoint(e)\n\n if (point) {\n this.dragStart = point\n e.stopPropagation()\n return false\n }\n }\n\n onDragMove(e: Event) {\n if (!this.movable || !this.dragStart) {\n return false\n }\n\n const point = getPoint(e)\n\n if (!point) {\n return false\n }\n\n e.stopPropagation()\n e.preventDefault()\n\n const dragStart = point\n var { x, y } = point\n\n x -= this.dragStart.x\n y -= this.dragStart.y\n\n this.dragStart = dragStart\n\n const overlayed = this.overlayed\n\n var boundingRect = overlayed.getBoundingClientRect()\n\n overlayed.style.left =\n Math.min(document.body.offsetWidth - 40, Math.max(40 - overlayed.offsetWidth, boundingRect.left + x)) + 'px'\n overlayed.style.top = Math.min(document.body.offsetHeight - 40, Math.max(0, boundingRect.top + y)) + 'px'\n\n overlayed.style.transform = 'initial'\n\n return false\n }\n\n onDragEnd(e: Event) {\n if (this.movable && this.dragStart) {\n e.stopPropagation()\n e.preventDefault()\n\n delete this.dragStart\n }\n }\n\n /**\n * A method that closes the overlay by removing it from its parent node in the DOM.\n * When called, this method removes the overlay element, effectively hiding it from the user interface.\n */\n close() {\n this.parentNode?.removeChild(this)\n }\n\n onClose(e: Event, escape?: boolean, request?: { result: unknown }) {\n e.stopPropagation()\n /* 현재 overlay state를 확인해서, 자신이 포함하고 있는 템플릿인 경우에 history.back() 한다. */\n\n if (this.historical) {\n var state = history.state\n var overlay = (state || {}).overlay\n\n if (!overlay || overlay.name !== this.name) {\n return\n }\n\n /* Backdrop click 경우는 escape 시도라고 정의한다. overlay 속성이 escapable이 아닌 경우에는 동작하지 않는다. */\n if (escape && !overlay.escapable) {\n return true\n }\n\n /* A second close in the same tick would see the same state and go back one page too far. */\n if (!claimHistoryBack(overlay.name)) {\n return\n }\n\n this.recordResult(request)\n history.back()\n } else {\n this.recordResult(request)\n this.close()\n }\n }\n\n /*\n * A value from the content (`closePopup(element, value)`) is recorded only once the overlay is really\n * going to close, and nothing settles here - the result settles when the overlay leaves the document,\n * where every way of closing ends. If another request recorded first, this value is dropped.\n */\n private recordResult(request?: { result: unknown }) {\n if (request && 'result' in request) {\n recordPopupResult(this.name, request.result)\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
import { openPopup } from '../src/open-popup.js';
|
|
4
|
+
/*
|
|
5
|
+
* A popup of size 'fit' stands as tall as its content, and no taller than the screen.
|
|
6
|
+
* The other sizes are fractions of the screen; a form of five fields in a medium popup left half the card empty.
|
|
7
|
+
*/
|
|
8
|
+
async function openWith(height) {
|
|
9
|
+
const handle = openPopup(html `<div class="content" style="height: ${height}px">content</div>`, { size: 'fit', title: 'form' });
|
|
10
|
+
const overlay = document.getElementById(handle.name);
|
|
11
|
+
await overlay.updateComplete;
|
|
12
|
+
const card = overlay.renderRoot.querySelector('[overlayed]');
|
|
13
|
+
const header = overlay.renderRoot.querySelector('[header]');
|
|
14
|
+
return { handle, card, header };
|
|
15
|
+
}
|
|
16
|
+
describe("openPopup size 'fit'", () => {
|
|
17
|
+
it('stands at its content height', async () => {
|
|
18
|
+
const { handle, card, header } = await openWith(120);
|
|
19
|
+
const expected = header.getBoundingClientRect().height + 120;
|
|
20
|
+
expect(card.getBoundingClientRect().height).to.be.closeTo(expected, 2);
|
|
21
|
+
handle.close();
|
|
22
|
+
});
|
|
23
|
+
it('stays inside the screen when the content is taller', async () => {
|
|
24
|
+
const { handle, card } = await openWith(5000);
|
|
25
|
+
expect(card.getBoundingClientRect().height).to.be.at.most(window.innerHeight - 32 + 0.5);
|
|
26
|
+
handle.close();
|
|
27
|
+
});
|
|
28
|
+
it('is no wider than the form width', async () => {
|
|
29
|
+
const { handle, card } = await openWith(120);
|
|
30
|
+
expect(card.getBoundingClientRect().width).to.be.at.most(Math.min(480, window.innerWidth - 32) + 0.5);
|
|
31
|
+
handle.close();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=overlay-fit-size.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay-fit-size.test.js","sourceRoot":"","sources":["../../test/overlay-fit-size.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGhD;;;GAGG;AACH,KAAK,UAAU,QAAQ,CAAC,MAAc;IACpC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAA,uCAAuC,MAAM,mBAAmB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IAC9H,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAsB,CAAA;IACzE,MAAM,OAAO,CAAC,cAAc,CAAA;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAgB,CAAA;IAC3E,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAgB,CAAA;IAC1E,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACjC,CAAC;AAED,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAA;QACpD,MAAM,QAAQ,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC,MAAM,GAAG,GAAG,CAAA;QAE5D,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QACtE,MAAM,CAAC,KAAK,EAAE,CAAA;IAChB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAA;QAE7C,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,GAAG,EAAE,GAAG,GAAG,CAAC,CAAA;QACxF,MAAM,CAAC,KAAK,EAAE,CAAA;IAChB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAA;QAE5C,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,CAAA;QACrG,MAAM,CAAC,KAAK,EAAE,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport { openPopup } from '../src/open-popup.js'\nimport { OxFloatingOverlay } from '../src/ox-floating-overlay.js'\n\n/*\n * A popup of size 'fit' stands as tall as its content, and no taller than the screen.\n * The other sizes are fractions of the screen; a form of five fields in a medium popup left half the card empty.\n */\nasync function openWith(height: number) {\n const handle = openPopup(html`<div class=\"content\" style=\"height: ${height}px\">content</div>`, { size: 'fit', title: 'form' })\n const overlay = document.getElementById(handle.name) as OxFloatingOverlay\n await overlay.updateComplete\n const card = overlay.renderRoot.querySelector('[overlayed]') as HTMLElement\n const header = overlay.renderRoot.querySelector('[header]') as HTMLElement\n return { handle, card, header }\n}\n\ndescribe(\"openPopup size 'fit'\", () => {\n it('stands at its content height', async () => {\n const { handle, card, header } = await openWith(120)\n const expected = header.getBoundingClientRect().height + 120\n\n expect(card.getBoundingClientRect().height).to.be.closeTo(expected, 2)\n handle.close()\n })\n\n it('stays inside the screen when the content is taller', async () => {\n const { handle, card } = await openWith(5000)\n\n expect(card.getBoundingClientRect().height).to.be.at.most(window.innerHeight - 32 + 0.5)\n handle.close()\n })\n\n it('is no wider than the form width', async () => {\n const { handle, card } = await openWith(120)\n\n expect(card.getBoundingClientRect().width).to.be.at.most(Math.min(480, window.innerWidth - 32) + 0.5)\n handle.close()\n })\n})\n"]}
|