@lion/ui 0.19.1 → 0.20.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 (95) hide show
  1. package/calendar-suites.js +1 -0
  2. package/components/form-core/src/FormatMixin.js +7 -2
  3. package/components/form-core/test/FormatMixin.test.js +4 -1
  4. package/components/form-core/test-suites/FormatMixin.suite.js +242 -65
  5. package/components/input/test/input-integrations.test.js +3 -2
  6. package/components/input/test/lion-input-integrations.test.js +2 -1
  7. package/components/input-amount/test/lion-input-amount-integrations.test.js +1 -1
  8. package/components/input-amount-dropdown/src/LionInputAmountDropdown.js +22 -4
  9. package/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.js +22 -0
  10. package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +59 -3
  11. package/components/input-date/test/lion-input-date-integrations.test.js +1 -1
  12. package/components/input-datepicker/test/lion-input-datepicker-integrations.test.js +1 -1
  13. package/components/input-email/test/lion-input-email-integrations.test.js +1 -1
  14. package/components/input-iban/test/lion-input-iban-integrations.test.js +1 -1
  15. package/components/input-stepper/test-suites/lion-input-stepper.integration.suite.js +2 -2
  16. package/components/overlays/test-suites/WithHoverInteraction.suite.js +212 -0
  17. package/components/textarea/test/lion-textarea-integrations.test.js +2 -1
  18. package/components/tooltip/test/lion-tooltip.test.js +9 -1
  19. package/custom-elements.json +1382 -1255
  20. package/dist-types/components/form-core/src/FormatMixin.d.ts.map +1 -1
  21. package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts +50 -5
  22. package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts.map +1 -1
  23. package/dist-types/components/icon/src/LionIcon.d.ts +2 -2
  24. package/dist-types/components/input-amount-dropdown/src/LionInputAmountDropdown.d.ts.map +1 -1
  25. package/dist-types/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.d.ts +2 -0
  26. package/dist-types/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.d.ts.map +1 -0
  27. package/dist-types/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.d.ts.map +1 -1
  28. package/dist-types/components/overlays/test-suites/WithHoverInteraction.suite.d.ts +17 -0
  29. package/dist-types/components/overlays/test-suites/WithHoverInteraction.suite.d.ts.map +1 -0
  30. package/dist-types/components/tooltip/test/lion-tooltip.test.d.ts.map +1 -1
  31. package/dist-types/exports/calendar-suites.d.ts +2 -0
  32. package/dist-types/exports/calendar-suites.d.ts.map +1 -0
  33. package/dist-types/exports/input-datepicker-suites.d.ts +2 -0
  34. package/dist-types/exports/input-datepicker-suites.d.ts.map +1 -0
  35. package/dist-types/exports/overlays-test-suites.d.ts +1 -0
  36. package/dist-types/tsconfig.tsbuildinfo +1 -1
  37. package/docs/components/checkbox-group/overview.md +2 -2
  38. package/docs/components/collapsible/overview.md +1 -1
  39. package/docs/components/combobox/overview.md +1 -1
  40. package/docs/components/combobox/use-cases.md +1 -1
  41. package/docs/components/dialog/overview.md +1 -1
  42. package/docs/components/fieldset/overview.md +5 -5
  43. package/docs/components/form/overview.md +3 -3
  44. package/docs/components/form/use-cases.md +2 -2
  45. package/docs/components/icon/use-cases.md +1 -1
  46. package/docs/components/input/overview.md +1 -1
  47. package/docs/components/input-amount/overview.md +3 -3
  48. package/docs/components/input-amount-dropdown/api-table.md +2 -2
  49. package/docs/components/input-date/overview.md +3 -3
  50. package/docs/components/input-datepicker/overview.md +5 -5
  51. package/docs/components/input-email/overview.md +2 -2
  52. package/docs/components/input-file/overview.md +1 -1
  53. package/docs/components/input-iban/overview.md +2 -2
  54. package/docs/components/input-range/overview.md +2 -2
  55. package/docs/components/input-stepper/overview.md +1 -1
  56. package/docs/components/input-tel/overview.md +1 -1
  57. package/docs/components/input-tel/use-cases.md +6 -6
  58. package/docs/components/input-tel-dropdown/overview.md +1 -1
  59. package/docs/components/listbox/use-cases.md +1 -1
  60. package/docs/components/radio-group/overview.md +3 -3
  61. package/docs/components/select/use-cases.md +1 -1
  62. package/docs/components/select-rich/use-cases.md +2 -2
  63. package/docs/components/tabs/examples.md +1 -1
  64. package/docs/fundamentals/index.md +4 -4
  65. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  66. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  67. package/docs/fundamentals/rationales/accessibility.md +1 -1
  68. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  69. package/docs/fundamentals/systems/core/overview.md +1 -1
  70. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  71. package/docs/fundamentals/systems/form/model-value.md +1 -1
  72. package/docs/fundamentals/systems/form/overview.md +28 -28
  73. package/docs/fundamentals/systems/form/validate.md +2 -2
  74. package/docs/fundamentals/systems/localize/overview.md +4 -4
  75. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  76. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  77. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  78. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  79. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  80. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  81. package/docs/guides/how-to/create-a-form.md +4 -4
  82. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  83. package/docs/guides/how-to/index.md +1 -1
  84. package/docs/guides/index.md +8 -8
  85. package/docs/guides/principles/index.md +5 -5
  86. package/docs/guides/principles/styling.md +1 -1
  87. package/exports/calendar-suites.js +1 -0
  88. package/exports/input-datepicker-suites.js +1 -0
  89. package/exports/overlays-test-suites.js +1 -0
  90. package/input-datepicker-suites.js +1 -0
  91. package/overlays-test-suites.js +1 -0
  92. package/package.json +1 -1
  93. package/components/overlays/test/withHoverInteraction.test.js +0 -118
  94. package/dist-types/components/overlays/test/withHoverInteraction.test.d.ts +0 -2
  95. package/dist-types/components/overlays/test/withHoverInteraction.test.d.ts.map +0 -1
@@ -0,0 +1,212 @@
1
+ import { expect, fixture, html, unsafeStatic } from '@open-wc/testing';
2
+ import sinon from 'sinon';
3
+
4
+ /**
5
+ * @typedef {import('lit').LitElement & {_overlayCtrl: import('../src/OverlayController.js').OverlayController}} HoverInteractionEl
6
+ * @typedef {{ tagString: string; invokerTagString: string; suffix?: string }} WithHoverInteractionConfig
7
+ */
8
+
9
+ /**
10
+ * @param {WithHoverInteractionConfig} config
11
+ */
12
+ export function runWithHoverInteractionSuite({ tagString, invokerTagString, suffix = '' }) {
13
+ const tag = unsafeStatic(tagString);
14
+ const invokerTag = unsafeStatic(invokerTagString);
15
+
16
+ describe(`inherited withHoverInteraction behavior (touch)${suffix}`, () => {
17
+ /** @type {sinon.SinonFakeTimers} */
18
+ let clock;
19
+ /** @type {typeof window.matchMedia} */
20
+ let originalMatchMedia;
21
+
22
+ beforeEach(() => {
23
+ clock = sinon.useFakeTimers();
24
+ originalMatchMedia = window.matchMedia;
25
+ window.matchMedia = query =>
26
+ /** @type {MediaQueryList} */ ({
27
+ matches: query === '(hover: hover)' ? false : originalMatchMedia(query).matches,
28
+ media: query,
29
+ onchange: null,
30
+ addListener: () => {},
31
+ removeListener: () => {},
32
+ addEventListener: () => {},
33
+ removeEventListener: () => {},
34
+ dispatchEvent: () => false,
35
+ });
36
+ });
37
+
38
+ afterEach(() => {
39
+ window.matchMedia = originalMatchMedia;
40
+ clock.restore();
41
+ });
42
+
43
+ it('opens after holding for longpressDuration (500ms)', async () => {
44
+ const el = /** @type {HoverInteractionEl} */ (
45
+ await fixture(html`
46
+ <${tag}>
47
+ <div slot="content">Tooltip content</div>
48
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
49
+ </${tag}>
50
+ `)
51
+ );
52
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
53
+
54
+ invoker.dispatchEvent(
55
+ new PointerEvent('pointerdown', { pointerType: 'touch', bubbles: true }),
56
+ );
57
+ clock.runAll();
58
+ await Promise.resolve();
59
+
60
+ expect(el._overlayCtrl.isShown).to.equal(true);
61
+ });
62
+
63
+ it('stays hidden on brief touch: pointerup cancels the timer', async () => {
64
+ const el = /** @type {HoverInteractionEl} */ (
65
+ await fixture(html`
66
+ <${tag}>
67
+ <div slot="content">Tooltip content</div>
68
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
69
+ </${tag}>
70
+ `)
71
+ );
72
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
73
+
74
+ invoker.dispatchEvent(
75
+ new PointerEvent('pointerdown', { pointerType: 'touch', bubbles: true }),
76
+ );
77
+ invoker.dispatchEvent(new PointerEvent('pointerup', { pointerType: 'touch', bubbles: true }));
78
+ clock.tick(500);
79
+ await el.updateComplete;
80
+
81
+ expect(el._overlayCtrl.isShown).to.equal(false);
82
+ });
83
+
84
+ it('ignores non-touch pointer events (mouse)', async () => {
85
+ const el = /** @type {HoverInteractionEl} */ (
86
+ await fixture(html`
87
+ <${tag}>
88
+ <div slot="content">Tooltip content</div>
89
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
90
+ </${tag}>
91
+ `)
92
+ );
93
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
94
+
95
+ invoker.dispatchEvent(
96
+ new PointerEvent('pointerdown', { pointerType: 'mouse', bubbles: true }),
97
+ );
98
+ clock.tick(500);
99
+ await el.updateComplete;
100
+
101
+ expect(el._overlayCtrl.isShown).to.equal(false);
102
+ });
103
+
104
+ it('auto-closes after longpressDuration once press ends', async () => {
105
+ const el = /** @type {HoverInteractionEl} */ (
106
+ await fixture(html`
107
+ <${tag}>
108
+ <div slot="content">Tooltip content</div>
109
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
110
+ </${tag}>
111
+ `)
112
+ );
113
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
114
+
115
+ invoker.dispatchEvent(
116
+ new PointerEvent('pointerdown', { pointerType: 'touch', bubbles: true }),
117
+ );
118
+ clock.runAll();
119
+ await Promise.resolve();
120
+ expect(el._overlayCtrl.isShown).to.equal(true);
121
+
122
+ invoker.dispatchEvent(new PointerEvent('pointerup', { pointerType: 'touch', bubbles: true }));
123
+ await clock.tickAsync(501);
124
+ expect(el._overlayCtrl.isShown).to.equal(false);
125
+ });
126
+
127
+ it('disables text selection on the invoker on init and restores it on teardown', async () => {
128
+ const el = /** @type {HoverInteractionEl} */ (
129
+ await fixture(html`
130
+ <${tag}>
131
+ <div slot="content">Tooltip content</div>
132
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
133
+ </${tag}>
134
+ `)
135
+ );
136
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
137
+ const getUserSelect = () =>
138
+ invoker.style.getPropertyValue('user-select') ||
139
+ invoker.style.getPropertyValue('-webkit-user-select');
140
+ expect(getUserSelect()).to.equal('none');
141
+
142
+ el._overlayCtrl.teardown();
143
+ expect(getUserSelect()).to.equal('');
144
+ });
145
+
146
+ it('does not open on tap-triggered focusin', async () => {
147
+ const el = /** @type {HoverInteractionEl} */ (
148
+ await fixture(html`
149
+ <${tag}>
150
+ <div slot="content">Tooltip content</div>
151
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
152
+ </${tag}>
153
+ `)
154
+ );
155
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
156
+
157
+ invoker.dispatchEvent(new Event('focusin', { bubbles: true }));
158
+ clock.tick(300);
159
+ await el.updateComplete;
160
+
161
+ expect(el._overlayCtrl.isShown).to.equal(false);
162
+ });
163
+
164
+ it('suppresses focusin that immediately follows a touch pointerdown', async () => {
165
+ const el = /** @type {HoverInteractionEl} */ (
166
+ await fixture(html`
167
+ <${tag}>
168
+ <div slot="content">Tooltip content</div>
169
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
170
+ </${tag}>
171
+ `)
172
+ );
173
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
174
+
175
+ invoker.dispatchEvent(
176
+ new PointerEvent('pointerdown', { pointerType: 'touch', bubbles: true }),
177
+ );
178
+ invoker.dispatchEvent(new PointerEvent('pointerup', { pointerType: 'touch', bubbles: true }));
179
+ invoker.dispatchEvent(new Event('focusin', { bubbles: true }));
180
+ clock.tick(1);
181
+ await el.updateComplete;
182
+
183
+ expect(el._overlayCtrl.isShown).to.equal(false);
184
+ });
185
+
186
+ it('suppresses click after completed longpress', async () => {
187
+ const el = /** @type {HoverInteractionEl} */ (
188
+ await fixture(html`
189
+ <${tag}>
190
+ <div slot="content">Tooltip content</div>
191
+ <${invokerTag} slot="invoker">Invoker</${invokerTag}>
192
+ </${tag}>
193
+ `)
194
+ );
195
+ const invoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
196
+ let clickTriggered = false;
197
+
198
+ invoker.addEventListener('click', () => {
199
+ clickTriggered = true;
200
+ });
201
+
202
+ invoker.dispatchEvent(
203
+ new PointerEvent('pointerdown', { pointerType: 'touch', bubbles: true }),
204
+ );
205
+ clock.runAll();
206
+ await Promise.resolve();
207
+
208
+ invoker.dispatchEvent(new MouseEvent('click', { bubbles: true }));
209
+ expect(clickTriggered).to.equal(false);
210
+ });
211
+ });
212
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
- runInteractionStateMixinSuite,
3
2
  runFormatMixinSuite,
3
+ runInteractionStateMixinSuite,
4
4
  runNativeTextFieldMixinSuite,
5
5
  } from '@lion/ui/form-core-test-suites.js';
6
6
 
@@ -15,6 +15,7 @@ describe('<lion-textarea> integrations', () => {
15
15
 
16
16
  runFormatMixinSuite({
17
17
  tagString,
18
+ modelValueType: String,
18
19
  });
19
20
 
20
21
  runNativeTextFieldMixinSuite({
@@ -1,6 +1,9 @@
1
1
  import '@lion/ui/define/lion-tooltip.js';
2
2
  import { aTimeout, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
3
- import { runOverlayMixinSuite } from '@lion/ui/overlays-test-suites.js';
3
+ import {
4
+ runOverlayMixinSuite,
5
+ runWithHoverInteractionSuite,
6
+ } from '@lion/ui/overlays-test-suites.js';
4
7
  import sinon from 'sinon';
5
8
 
6
9
  /**
@@ -20,6 +23,11 @@ describe('lion-tooltip', () => {
20
23
  });
21
24
  });
22
25
 
26
+ runWithHoverInteractionSuite({
27
+ tagString: 'lion-tooltip',
28
+ invokerTagString: 'button',
29
+ });
30
+
23
31
  describe('Basic', () => {
24
32
  /** @type {sinon.SinonFakeTimers} */
25
33
  let clock;