@operato/popup 10.11.0 → 10.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/coverage/lcov-report/base.css +224 -0
  3. package/coverage/lcov-report/block-navigation.js +87 -0
  4. package/coverage/lcov-report/favicon.png +0 -0
  5. package/coverage/lcov-report/index.html +206 -0
  6. package/coverage/lcov-report/prettify.css +1 -0
  7. package/coverage/lcov-report/prettify.js +2 -0
  8. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  9. package/coverage/lcov-report/sorter.js +210 -0
  10. package/coverage/lcov.info +7985 -0
  11. package/dist/src/implementation.d.ts +13 -0
  12. package/dist/src/implementation.js +13 -0
  13. package/dist/src/implementation.js.map +1 -0
  14. package/dist/src/index.d.ts +1 -0
  15. package/dist/src/index.js +1 -0
  16. package/dist/src/index.js.map +1 -1
  17. package/dist/src/open-popup.d.ts +37 -13
  18. package/dist/src/open-popup.js +79 -12
  19. package/dist/src/open-popup.js.map +1 -1
  20. package/dist/src/ox-floating-overlay.d.ts +4 -1
  21. package/dist/src/ox-floating-overlay.js +19 -2
  22. package/dist/src/ox-floating-overlay.js.map +1 -1
  23. package/dist/src/ox-popup-actions.d.ts +36 -0
  24. package/dist/src/ox-popup-actions.js +129 -0
  25. package/dist/src/ox-popup-actions.js.map +1 -0
  26. package/dist/src/ox-prompt.d.ts +25 -3
  27. package/dist/src/ox-prompt.js +74 -42
  28. package/dist/src/ox-prompt.js.map +1 -1
  29. package/dist/src/popup-result.d.ts +19 -0
  30. package/dist/src/popup-result.js +53 -0
  31. package/dist/src/popup-result.js.map +1 -0
  32. package/dist/test/office-control-height.test.d.ts +2 -0
  33. package/dist/test/office-control-height.test.js +102 -0
  34. package/dist/test/office-control-height.test.js.map +1 -0
  35. package/dist/test/ox-popup-actions.test.d.ts +3 -0
  36. package/dist/test/ox-popup-actions.test.js +104 -0
  37. package/dist/test/ox-popup-actions.test.js.map +1 -0
  38. package/dist/test/ox-prompt-actions.test.d.ts +1 -0
  39. package/dist/test/ox-prompt-actions.test.js +108 -0
  40. package/dist/test/ox-prompt-actions.test.js.map +1 -0
  41. package/dist/test/popup-result.test.d.ts +1 -0
  42. package/dist/test/popup-result.test.js +114 -0
  43. package/dist/test/popup-result.test.js.map +1 -0
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +14 -5
  46. package/test/office-control-height.test.ts +125 -0
  47. package/test/ox-popup-actions.test.ts +130 -0
  48. package/test/ox-prompt-actions.test.ts +136 -0
  49. package/test/popup-result.test.ts +150 -0
  50. package/translations/en.json +6 -1
  51. package/translations/ja.json +6 -0
  52. package/translations/ko.json +6 -1
  53. package/translations/ms.json +6 -0
  54. package/translations/zh.json +6 -0
@@ -0,0 +1,125 @@
1
+ import '@material/web/button/filled-button.js'
2
+
3
+ import { expect, fixture } from '@open-wc/testing'
4
+ import { css, html, LitElement } from 'lit'
5
+
6
+ import {
7
+ ACTION_HEIGHT_TOKENS,
8
+ ButtonContainerStyles,
9
+ CommonHeaderStyles,
10
+ CommonPopupStyles
11
+ } from '@operato/styles'
12
+
13
+ import '../src/ox-popup-actions.js'
14
+ import { OxPopupActions } from '../src/ox-popup-actions.js'
15
+
16
+ /**
17
+ * Button heights (ADR-0060 decisions 6 and 6-1).
18
+ *
19
+ * The **platform** keeps the heights every application had before the operato standardization, so
20
+ * dssp, fmsim and the rest do not change when they upgrade. The **operato products** are compact: the
21
+ * shell theme opens each token as `var(--suite-<token>, <platform>)` and operato-suite fills the slot.
22
+ *
23
+ * These render both worlds with a mouse (the test browser). The finger branches cannot be emulated,
24
+ * so those are read from the stylesheets.
25
+ */
26
+
27
+ const PLATFORM_TOKENS = `
28
+ --context-action-height: var(--suite-context-action-height, 32px);
29
+ --popup-action-height: var(--suite-popup-action-height, 30px);
30
+ --form-action-height: var(--suite-form-action-height, 40px);
31
+ `
32
+ const SUITE_SLOTS = `
33
+ --suite-context-action-height: 32px;
34
+ --suite-popup-action-height: 32px;
35
+ --suite-form-action-height: 32px;
36
+ `
37
+
38
+ class StyledRows extends LitElement {
39
+ static styles = [CommonPopupStyles, CommonHeaderStyles, ButtonContainerStyles, css``]
40
+
41
+ render() {
42
+ return html`
43
+ <div class="buttons"><md-filled-button id="popup-md">save</md-filled-button></div>
44
+ <div class="footer"><button id="footer">save</button></div>
45
+ <div class="button-container">
46
+ <button id="bar">export</button>
47
+ <md-filled-button id="bar-md">publish</md-filled-button>
48
+ </div>
49
+ `
50
+ }
51
+ }
52
+ customElements.define('test-styled-rows', StyledRows)
53
+
54
+ const height = (el: Element | null | undefined) => Math.round(el!.getBoundingClientRect().height)
55
+ const text = (styles: unknown) =>
56
+ (Array.isArray(styles) ? styles : [styles]).map(s => String((s as { cssText?: string }).cssText ?? s)).join('\n')
57
+ const coarse = (cssText: string) => cssText.slice(cssText.indexOf('(pointer: coarse)'))
58
+
59
+ async function rows(style: string) {
60
+ const host = await fixture<HTMLElement>(html`
61
+ <div style="${style}">
62
+ <test-styled-rows></test-styled-rows>
63
+ <ox-popup-actions>
64
+ <md-filled-button slot="confirm" id="prompt-md">ok</md-filled-button>
65
+ </ox-popup-actions>
66
+ </div>
67
+ `)
68
+ const styled = host.querySelector('test-styled-rows') as StyledRows
69
+ await styled.updateComplete
70
+ const actions = host.querySelector('ox-popup-actions') as OxPopupActions
71
+ await actions.updateComplete
72
+ const buttons = [...Array.from(styled.shadowRoot!.querySelectorAll('md-filled-button')), host.querySelector('#prompt-md')]
73
+ await Promise.all(buttons.map(b => (b as LitElement).updateComplete))
74
+ return { root: styled.shadowRoot!, host }
75
+ }
76
+
77
+ describe('office control height', () => {
78
+ it('the platform defaults are the heights before the standardization', () => {
79
+ expect(ACTION_HEIGHT_TOKENS).to.deep.equal({
80
+ '--context-action-height': 32,
81
+ '--popup-action-height': 30,
82
+ '--form-action-height': 40,
83
+ '--cell-action-height': 26
84
+ })
85
+ })
86
+
87
+ it('★ platform: nothing changes for applications outside the operato suite', async () => {
88
+ const { root, host } = await rows(PLATFORM_TOKENS)
89
+
90
+ expect(height(root.querySelector('#popup-md'))).to.equal(40) // CommonPopupStyles .buttons
91
+ expect(height(root.querySelector('#footer'))).to.be.at.least(30) // older footer
92
+ expect(height(root.querySelector('#bar'))).to.equal(32) // page action bar
93
+ expect(height(root.querySelector('#bar-md'))).to.equal(40) // Material keeps its own in the bar
94
+ expect(height(host.querySelector('#prompt-md'))).to.equal(30) // OxPrompt row, as before
95
+ })
96
+
97
+ it('★ suite: every action button in the operato products is 32px', async () => {
98
+ const { root, host } = await rows(SUITE_SLOTS + PLATFORM_TOKENS)
99
+
100
+ expect(height(root.querySelector('#popup-md'))).to.equal(32)
101
+ expect(height(root.querySelector('#bar'))).to.equal(32)
102
+ expect(height(root.querySelector('#bar-md'))).to.equal(32)
103
+ expect(height(host.querySelector('#prompt-md'))).to.equal(32)
104
+ })
105
+
106
+ it('a shop-floor screen still raises the popup row above both', async () => {
107
+ const { root } = await rows(SUITE_SLOTS + PLATFORM_TOKENS + '--popup-action-height: 64px;')
108
+ expect(height(root.querySelector('#popup-md'))).to.equal(64)
109
+ })
110
+
111
+ it('finger: the platform keeps 44px for the page bar and a 48px floor for the popup row', () => {
112
+ const bar = coarse(text(ButtonContainerStyles))
113
+ expect(bar).to.contain('var(--suite-context-action-height, 44px)')
114
+
115
+ const popup = coarse(text(CommonPopupStyles))
116
+ expect(popup).to.contain('var(--suite-popup-action-height, 48px)')
117
+ expect(popup).to.contain('var(--popup-action-height, 30px)')
118
+ })
119
+
120
+ it('ox-popup-actions has no finger height of its own', () => {
121
+ const cssText = text(OxPopupActions.styles)
122
+ expect(cssText).to.contain('--_height: var(--popup-action-height, 30px)')
123
+ expect(coarse(cssText)).to.not.contain('--_height:')
124
+ })
125
+ })
@@ -0,0 +1,130 @@
1
+ import '@material/web/button/filled-button.js'
2
+ import '@material/web/button/text-button.js'
3
+
4
+ import { expect, fixture } from '@open-wc/testing'
5
+ import { html } from 'lit'
6
+
7
+ import '../src/ox-popup-actions.js'
8
+
9
+ /**
10
+ * The action row owns order, height, shape and the destructive colour - so a popup cannot get them
11
+ * wrong by writing its markup differently. These run with a mouse pointer (the test browser); the
12
+ * finger bar is a media query of the same element.
13
+ *
14
+ * The expected numbers are written out (30, 68, 999em) rather than read from the stylesheet, so a
15
+ * change to the stylesheet shows up here as a decision, not as a silent follow.
16
+ */
17
+
18
+ const left = (el: Element) => el.getBoundingClientRect().left
19
+ const height = (el: Element) => Math.round(el.getBoundingClientRect().height)
20
+
21
+ async function row(template: ReturnType<typeof html>) {
22
+ const host = await fixture<HTMLElement>(html`<div style="width: 600px">${template}</div>`)
23
+ const actions = host.querySelector('ox-popup-actions') as HTMLElement & { updateComplete: Promise<unknown> }
24
+ await actions.updateComplete
25
+ await Promise.all(
26
+ Array.from(actions.querySelectorAll('md-filled-button, md-text-button')).map(
27
+ b => (b as HTMLElement & { updateComplete: Promise<unknown> }).updateComplete
28
+ )
29
+ )
30
+ return actions
31
+ }
32
+
33
+ describe('ox-popup-actions', () => {
34
+ it('renders start, cancel, confirm in that order whatever the markup order', async () => {
35
+ const actions = await row(html`
36
+ <ox-popup-actions>
37
+ <md-filled-button slot="confirm" id="confirm">save</md-filled-button>
38
+ <md-text-button slot="cancel" id="cancel">cancel</md-text-button>
39
+ <md-text-button slot="start" id="start">delete</md-text-button>
40
+ </ox-popup-actions>
41
+ `)
42
+
43
+ const start = actions.querySelector('#start')!
44
+ const cancel = actions.querySelector('#cancel')!
45
+ const confirm = actions.querySelector('#confirm')!
46
+
47
+ expect(left(start)).to.be.lessThan(left(cancel))
48
+ expect(left(cancel)).to.be.lessThan(left(confirm))
49
+ })
50
+
51
+ it('keeps the confirm button at the right edge', async () => {
52
+ const actions = await row(html`
53
+ <ox-popup-actions>
54
+ <md-filled-button slot="confirm" id="confirm">save</md-filled-button>
55
+ <md-text-button slot="cancel">cancel</md-text-button>
56
+ </ox-popup-actions>
57
+ `)
58
+
59
+ const confirm = actions.querySelector('#confirm')!
60
+ expect(Math.round(confirm.getBoundingClientRect().right)).to.equal(Math.round(actions.getBoundingClientRect().right))
61
+ })
62
+
63
+ it('gives Material buttons and plain buttons the same height (30px, the platform default)', async () => {
64
+ const actions = await row(html`
65
+ <ox-popup-actions>
66
+ <button slot="cancel" id="plain">cancel</button>
67
+ <md-filled-button slot="confirm" id="md">save</md-filled-button>
68
+ </ox-popup-actions>
69
+ `)
70
+
71
+ expect(height(actions.querySelector('#md')!)).to.equal(30)
72
+ expect(height(actions.querySelector('#plain')!)).to.equal(30)
73
+ })
74
+
75
+ it('uses pill shapes inside the popup card', async () => {
76
+ const actions = await row(html`
77
+ <ox-popup-actions>
78
+ <button slot="cancel" id="plain">cancel</button>
79
+ <md-filled-button slot="confirm" id="md">save</md-filled-button>
80
+ </ox-popup-actions>
81
+ `)
82
+
83
+ const md = actions.querySelector('#md')!
84
+ expect(getComputedStyle(md).getPropertyValue('--md-filled-button-container-shape').trim()).to.equal('999em')
85
+ expect(getComputedStyle(actions.querySelector('#plain')!).borderTopLeftRadius).to.not.equal('0px')
86
+ })
87
+
88
+ it('lets a screen raise the height through --popup-action-height', async () => {
89
+ const actions = await row(html`
90
+ <ox-popup-actions style="--popup-action-height: 68px">
91
+ <button slot="cancel" id="plain">cancel</button>
92
+ <md-filled-button slot="confirm" id="md">save</md-filled-button>
93
+ </ox-popup-actions>
94
+ `)
95
+
96
+ expect(height(actions.querySelector('#md')!)).to.equal(68)
97
+ expect(height(actions.querySelector('#plain')!)).to.equal(68)
98
+ })
99
+
100
+ it('paints a destructive action with the error colour', async () => {
101
+ const actions = await row(html`
102
+ <ox-popup-actions style="--md-sys-color-error: rgb(190, 12, 20)">
103
+ <md-text-button slot="start" destructive id="side">delete</md-text-button>
104
+ <md-filled-button slot="confirm" destructive id="main">delete all</md-filled-button>
105
+ <button slot="cancel" id="plain" destructive>cancel</button>
106
+ </ox-popup-actions>
107
+ `)
108
+
109
+ const side = getComputedStyle(actions.querySelector('#side')!)
110
+ const main = getComputedStyle(actions.querySelector('#main')!)
111
+
112
+ expect(side.getPropertyValue('--md-text-button-label-text-color').trim()).to.equal('rgb(190, 12, 20)')
113
+ expect(main.getPropertyValue('--md-filled-button-container-color').trim()).to.equal('rgb(190, 12, 20)')
114
+ })
115
+
116
+ it('never paints cancel as destructive', async () => {
117
+ const actions = await row(html`
118
+ <ox-popup-actions style="--md-sys-color-error: rgb(190, 12, 20)">
119
+ <md-text-button slot="cancel" destructive id="cancel">cancel</md-text-button>
120
+ <button slot="cancel" destructive id="plain">cancel</button>
121
+ <md-filled-button slot="confirm">save</md-filled-button>
122
+ </ox-popup-actions>
123
+ `)
124
+
125
+ expect(getComputedStyle(actions.querySelector('#cancel')!).getPropertyValue('--md-text-button-label-text-color').trim()).to.not.equal(
126
+ 'rgb(190, 12, 20)'
127
+ )
128
+ expect(getComputedStyle(actions.querySelector('#plain')!).color).to.not.equal('rgb(190, 12, 20)')
129
+ })
130
+ })
@@ -0,0 +1,136 @@
1
+ import { expect } from '@open-wc/testing'
2
+
3
+ import { OxPrompt } from '../src/ox-prompt.js'
4
+
5
+ /**
6
+ * OxPrompt is the first real consumer of the shared action row. Before, its buttons were centred,
7
+ * confirm stood left of cancel, and both had the theme's 5px corner inside a floating card - a row of
8
+ * its own, unlike every popup that opened it.
9
+ *
10
+ * Checked here: the row is the shared one, confirm is on the right, heights match, a destructive
11
+ * confirmation is painted and focuses cancel, and the promise still answers true / false.
12
+ */
13
+
14
+ const settle = () => new Promise(resolve => setTimeout(resolve, 50))
15
+
16
+ const TIMEOUT = 'TIMEOUT'
17
+ function within<T>(promise: Promise<T>, ms = 1500): Promise<T | typeof TIMEOUT> {
18
+ return Promise.race([promise, new Promise<typeof TIMEOUT>(resolve => setTimeout(() => resolve(TIMEOUT), ms))])
19
+ }
20
+
21
+ async function openPrompt(destructive = false) {
22
+ const answer = OxPrompt.open({
23
+ title: 'remove?',
24
+ text: 'this cannot be undone',
25
+ confirmButton: { text: 'remove', destructive },
26
+ cancelButton: { text: 'cancel' },
27
+ preventCloseOnBlur: true
28
+ })
29
+
30
+ await settle()
31
+
32
+ const prompts = document.body.querySelectorAll('ox-prompt')
33
+ const prompt = prompts[prompts.length - 1] as OxPrompt
34
+ await prompt.updateComplete
35
+
36
+ const root = prompt.renderRoot as ShadowRoot
37
+ const actions = root.querySelector('ox-popup-actions') as HTMLElement & { updateComplete: Promise<unknown> }
38
+ await actions?.updateComplete
39
+
40
+ const confirm = root.querySelector('#confirm') as HTMLElement & { updateComplete: Promise<unknown> }
41
+ const cancel = root.querySelector('#cancel') as HTMLElement & { updateComplete: Promise<unknown> }
42
+ await Promise.all([confirm?.updateComplete, cancel?.updateComplete])
43
+
44
+ return { answer, prompt, root, actions, confirm, cancel }
45
+ }
46
+
47
+ describe('OxPrompt uses the shared action row', () => {
48
+ before(() => {
49
+ /* No theme is loaded in the test page; an undefined var() would make every colour read empty. */
50
+ document.body.style.setProperty('--md-sys-color-error', 'rgb(190, 12, 20)')
51
+ })
52
+
53
+ afterEach(() => {
54
+ /* A failed assertion before the click leaves its prompt open; do not let it leak into the next test. */
55
+ document.body.querySelectorAll('ox-prompt').forEach(p => (p as OxPrompt).close())
56
+ })
57
+
58
+ it('renders its buttons in ox-popup-actions, confirm right of cancel, same height', async () => {
59
+ const { answer, actions, confirm, cancel } = await openPrompt()
60
+
61
+ expect(actions, 'ox-popup-actions').to.exist
62
+ expect(confirm.getAttribute('slot')).to.equal('confirm')
63
+ expect(cancel.getAttribute('slot')).to.equal('cancel')
64
+ expect(cancel.getBoundingClientRect().left).to.be.lessThan(confirm.getBoundingClientRect().left)
65
+ expect(Math.round(confirm.getBoundingClientRect().height)).to.equal(30)
66
+ expect(Math.round(cancel.getBoundingClientRect().height)).to.equal(30)
67
+
68
+ cancel.click()
69
+ expect(await within(answer)).to.equal(false)
70
+ })
71
+
72
+ it('answers true on confirm', async () => {
73
+ const { answer, confirm } = await openPrompt()
74
+
75
+ confirm.click()
76
+ expect(await within(answer)).to.equal(true)
77
+ })
78
+
79
+ it('focuses confirm for an ordinary question', async () => {
80
+ const { answer, root, confirm, cancel } = await openPrompt()
81
+
82
+ /* Compare ids, not elements: a failing element comparison makes chai render the DOM and hang. */
83
+ expect((root.activeElement as HTMLElement | null)?.id).to.equal('confirm')
84
+
85
+ cancel.click()
86
+ await within(answer)
87
+ })
88
+
89
+ it('paints a destructive confirmation and focuses cancel', async () => {
90
+ const { answer, root, confirm, cancel } = await openPrompt(true)
91
+
92
+ expect(confirm.hasAttribute('destructive')).to.equal(true)
93
+ expect(getComputedStyle(confirm).getPropertyValue('--md-filled-button-container-color').trim()).to.equal('rgb(190, 12, 20)')
94
+ expect((root.activeElement as HTMLElement | null)?.id).to.equal('cancel')
95
+
96
+ cancel.click()
97
+ expect(await within(answer)).to.equal(false)
98
+ })
99
+ })
100
+
101
+ describe('OxPrompt.confirmDelete', () => {
102
+ afterEach(() => {
103
+ document.body.querySelectorAll('ox-prompt').forEach(p => (p as OxPrompt).close())
104
+ })
105
+
106
+ async function opened(count?: number) {
107
+ const before = document.body.querySelectorAll('ox-prompt').length
108
+ const answer = OxPrompt.confirmDelete({ count })
109
+ for (let i = 0; i < 40 && document.body.querySelectorAll('ox-prompt').length <= before; i++) await settle()
110
+ const prompts = document.body.querySelectorAll('ox-prompt')
111
+ const prompt = prompts[prompts.length - 1] as OxPrompt
112
+ await prompt.updateComplete
113
+ const root = prompt.renderRoot as ShadowRoot
114
+ const confirm = root.querySelector('#confirm') as HTMLElement & { updateComplete: Promise<unknown> }
115
+ await confirm?.updateComplete
116
+ return { answer, prompt, root, confirm }
117
+ }
118
+
119
+ it('asks in the shared popup with a destructive delete, and answers true on delete', async () => {
120
+ const { answer, prompt, confirm } = await opened()
121
+
122
+ expect(prompt.titler).to.equal('delete the selected item?')
123
+ expect(confirm.hasAttribute('destructive')).to.equal(true)
124
+ expect(confirm.textContent?.trim()).to.equal('delete')
125
+
126
+ confirm.click()
127
+ expect(await within(answer)).to.equal(true)
128
+ })
129
+
130
+ it('names how many are selected when more than one', async () => {
131
+ const { prompt, root } = await opened(3)
132
+
133
+ expect(prompt.titler).to.equal('delete the 3 selected items?')
134
+ ;(root.querySelector('#cancel') as HTMLElement).click()
135
+ })
136
+ })
@@ -0,0 +1,150 @@
1
+ import { expect } from '@open-wc/testing'
2
+ import { html } from 'lit'
3
+
4
+ import { closePopup, openPopup } from '../src/open-popup.js'
5
+ import { OxFloatingOverlay } from '../src/ox-floating-overlay.js'
6
+
7
+ /**
8
+ * The popup result settles exactly once, with the right value, whichever way the popup closes -
9
+ * for the default implementation (no @operato/layout loaded).
10
+ *
11
+ * The implementation's one promise is "call onclosed once when the popup is gone". Before this test
12
+ * the default implementation kept it only for handle.close(): ESC, the backdrop and X removed the
13
+ * overlay without telling the handle, so an awaited result would have hung forever.
14
+ *
15
+ * The same table runs for the layout implementation in @operato/layout/test. A new implementation
16
+ * adds its own row there.
17
+ */
18
+
19
+ const TIMEOUT = 'TIMEOUT'
20
+
21
+ /** Never await a result bare - a broken implementation must fail the test, not hang the runner. */
22
+ function within<T>(promise: Promise<T>, ms = 2000): Promise<T | typeof TIMEOUT> {
23
+ return Promise.race([promise, new Promise<typeof TIMEOUT>(resolve => setTimeout(() => resolve(TIMEOUT), ms))])
24
+ }
25
+
26
+ function overlayOf(handle: { name: string }): OxFloatingOverlay {
27
+ return document.getElementById(handle.name) as OxFloatingOverlay
28
+ }
29
+
30
+ async function open(options = {}) {
31
+ const handle = openPopup<string>(html`<div class="content">content</div>`, { backdrop: true, ...options })
32
+ let onclosedCalls = 0
33
+ handle.onclosed = () => onclosedCalls++
34
+
35
+ const overlay = overlayOf(handle)
36
+ await overlay.updateComplete
37
+
38
+ return {
39
+ handle,
40
+ overlay,
41
+ content: overlay.querySelector('.content') as HTMLElement,
42
+ onclosedCalls: () => onclosedCalls
43
+ }
44
+ }
45
+
46
+ /** Lets any late second settle or second onclosed show up before counting. */
47
+ const settleTurn = () => new Promise(resolve => setTimeout(resolve, 50))
48
+
49
+ describe('openPopup result - default implementation', () => {
50
+ it('handle.close(value) settles with that value', async () => {
51
+ const { handle, onclosedCalls } = await open()
52
+
53
+ handle.close('saved')
54
+
55
+ expect(await within(handle.result)).to.equal('saved')
56
+ await settleTurn()
57
+ expect(handle.closed).to.equal(true)
58
+ expect(onclosedCalls()).to.equal(1)
59
+ })
60
+
61
+ it('closePopup(element, value) from the content settles with that value', async () => {
62
+ const { handle, content, onclosedCalls } = await open()
63
+
64
+ closePopup(content, 'picked')
65
+
66
+ expect(await within(handle.result)).to.equal('picked')
67
+ await settleTurn()
68
+ expect(handle.closed).to.equal(true)
69
+ expect(onclosedCalls()).to.equal(1)
70
+ })
71
+
72
+ it('closePopup(element) without a value settles undefined', async () => {
73
+ const { handle, content } = await open()
74
+
75
+ closePopup(content)
76
+
77
+ expect(await within(handle.result)).to.equal(undefined)
78
+ })
79
+
80
+ it('ESC settles undefined and reports closed', async () => {
81
+ const { handle, onclosedCalls } = await open({ escapable: true })
82
+
83
+ document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
84
+
85
+ expect(await within(handle.result)).to.equal(undefined)
86
+ await settleTurn()
87
+ expect(handle.closed).to.equal(true)
88
+ expect(onclosedCalls()).to.equal(1)
89
+ })
90
+
91
+ it('backdrop click settles undefined and reports closed', async () => {
92
+ const { handle, overlay, onclosedCalls } = await open()
93
+
94
+ const backdrop = overlay.renderRoot.querySelector('#backdrop') as HTMLElement
95
+ expect(backdrop, 'backdrop element').to.exist
96
+ backdrop.click()
97
+
98
+ expect(await within(handle.result)).to.equal(undefined)
99
+ await settleTurn()
100
+ expect(handle.closed).to.equal(true)
101
+ expect(onclosedCalls()).to.equal(1)
102
+ })
103
+
104
+ it('the X button settles undefined and reports closed', async () => {
105
+ const { handle, overlay, onclosedCalls } = await open({ closable: true, title: 'x' })
106
+
107
+ const closer = overlay.renderRoot.querySelector('[closable][close]') as HTMLElement
108
+ expect(closer, 'close button').to.exist
109
+ closer.click()
110
+
111
+ expect(await within(handle.result)).to.equal(undefined)
112
+ await settleTurn()
113
+ expect(handle.closed).to.equal(true)
114
+ expect(onclosedCalls()).to.equal(1)
115
+ })
116
+
117
+ it('the first close request wins: closePopup then handle.close', async () => {
118
+ const { handle, content, onclosedCalls } = await open()
119
+
120
+ closePopup(content, 'first')
121
+ handle.close('second')
122
+
123
+ expect(await within(handle.result)).to.equal('first')
124
+ await settleTurn()
125
+ expect(onclosedCalls()).to.equal(1)
126
+ })
127
+
128
+ it('the first close request wins: handle.close twice', async () => {
129
+ const { handle, onclosedCalls } = await open()
130
+
131
+ handle.close('first')
132
+ handle.close('second')
133
+
134
+ expect(await within(handle.result)).to.equal('first')
135
+ await settleTurn()
136
+ expect(onclosedCalls()).to.equal(1)
137
+ })
138
+
139
+ it('an onclosed assigned before the change is still called once', async () => {
140
+ const handle = openPopup(html`<div>legacy</div>`)
141
+ let calls = 0
142
+ handle.onclosed = () => calls++
143
+
144
+ handle.close()
145
+
146
+ await within(handle.result)
147
+ await settleTurn()
148
+ expect(calls).to.equal(1)
149
+ })
150
+ })
@@ -1 +1,6 @@
1
- {}
1
+ {
2
+ "button.popup-cancel": "cancel",
3
+ "button.popup-delete": "delete",
4
+ "text.popup-confirm-delete": "delete the selected item?",
5
+ "text.popup-confirm-delete-count": "delete the {count} selected items?"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "button.popup-cancel": "キャンセル",
3
+ "button.popup-delete": "削除",
4
+ "text.popup-confirm-delete": "選択した項目を削除しますか?",
5
+ "text.popup-confirm-delete-count": "選択した{count}件を削除しますか?"
6
+ }
@@ -1 +1,6 @@
1
- {}
1
+ {
2
+ "button.popup-cancel": "취소",
3
+ "button.popup-delete": "삭제",
4
+ "text.popup-confirm-delete": "선택한 항목을 삭제할까요?",
5
+ "text.popup-confirm-delete-count": "선택한 {count}건을 삭제할까요?"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "button.popup-cancel": "batal",
3
+ "button.popup-delete": "padam",
4
+ "text.popup-confirm-delete": "padam item yang dipilih?",
5
+ "text.popup-confirm-delete-count": "padam {count} item yang dipilih?"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "button.popup-cancel": "取消",
3
+ "button.popup-delete": "删除",
4
+ "text.popup-confirm-delete": "删除所选项目吗?",
5
+ "text.popup-confirm-delete-count": "删除所选的{count}项吗?"
6
+ }