@lion/ui 0.0.14 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/components/calendar/src/LionCalendar.js +2 -3
  2. package/components/calendar/test/lion-calendar.test.js +5 -3
  3. package/components/form-core/src/validate/ValidateMixin.js +7 -3
  4. package/components/form-core/src/validate/validators/DateValidators.js +1 -1
  5. package/components/form-core/test/lion-field.test.js +4 -2
  6. package/components/form-core/test/validate/DateValidators.test.js +1 -1
  7. package/components/form-core/test-suites/FormatMixin.suite.js +1 -1
  8. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +6 -4
  9. package/components/form-integrations/test/form-validation-integrations.test.js +11 -10
  10. package/components/input-amount/src/LionInputAmount.js +2 -2
  11. package/components/input-amount/src/formatters.js +5 -1
  12. package/components/input-amount/src/parsers.js +1 -1
  13. package/components/input-amount/test/formatters.test.js +5 -3
  14. package/components/input-date/src/LionInputDate.js +1 -1
  15. package/components/input-date/test/lion-input-date.test.js +91 -43
  16. package/components/input-datepicker/src/LionInputDatepicker.js +1 -1
  17. package/components/input-email/src/LionInputEmail.js +1 -1
  18. package/components/input-iban/src/LionInputIban.js +1 -1
  19. package/components/input-iban/src/validators.js +14 -8
  20. package/components/input-range/src/LionInputRange.js +1 -1
  21. package/components/input-tel/src/LionInputTel.js +3 -3
  22. package/components/input-tel/test-suites/LionInputTel.suite.js +3 -2
  23. package/components/input-tel-dropdown/src/LionInputTelDropdown.js +7 -4
  24. package/components/localize/src/LocalizeMixin.js +24 -9
  25. package/components/localize/src/date/formatDate.js +4 -3
  26. package/components/localize/src/date/parseDate.js +5 -3
  27. package/components/localize/src/getLocalizeManager.js +74 -0
  28. package/components/localize/src/number/formatNumber.js +5 -4
  29. package/components/localize/src/number/getCurrencyName.js +3 -2
  30. package/components/localize/src/number/parseNumber.js +3 -2
  31. package/components/localize/src/number/utils/emptyStringWhenNumberNan.js +3 -2
  32. package/components/localize/src/singleton.js +6 -9
  33. package/components/localize/src/utils/getLocale.js +3 -8
  34. package/components/localize/test/LocalizeManager.test.js +1 -1
  35. package/components/localize/test/LocalizeMixin.test.js +17 -15
  36. package/components/localize/test/date/formatDate.test.js +25 -24
  37. package/components/localize/test/date/getDateFormatBasedOnLocale.test.js +8 -3
  38. package/components/localize/test/date/parseDate.test.js +22 -7
  39. package/components/localize/test/getLocalizeManager.test.js +31 -0
  40. package/components/localize/test/localize.test.js +5 -4
  41. package/components/localize/test/number/formatNumber.test.js +31 -29
  42. package/components/localize/test/number/formatNumberToParts.test.js +5 -3
  43. package/components/localize/test/number/getCurrencyName.test.js +1 -1
  44. package/components/localize/test/number/parseNumber.test.js +37 -19
  45. package/components/localize/test/side-effect-free-entrypoint.test.js +38 -0
  46. package/components/localize/test-helpers/localizeTearDown.js +5 -4
  47. package/components/localize/types/LocalizeMixinTypes.ts +9 -1
  48. package/components/pagination/src/LionPagination.js +1 -1
  49. package/components/progress-indicator/src/LionProgressIndicator.js +3 -2
  50. package/components/select/src/LionSelect.js +15 -0
  51. package/components/select/test/lion-select.test.js +25 -0
  52. package/components/validate-messages/src/loadDefaultFeedbackMessages.js +2 -2
  53. package/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.js +6 -4
  54. package/custom-elements.json +395 -17
  55. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  56. package/dist-types/components/form-core/src/validate/ValidateMixin.d.ts.map +1 -1
  57. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  58. package/dist-types/components/input-amount/src/formatters.d.ts.map +1 -1
  59. package/dist-types/components/input-date/src/LionInputDate.d.ts +1 -1
  60. package/dist-types/components/input-iban/src/validators.d.ts.map +1 -1
  61. package/dist-types/components/input-tel/test-suites/LionInputTel.suite.d.ts.map +1 -1
  62. package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts.map +1 -1
  63. package/dist-types/components/localize/src/LocalizeMixin.d.ts.map +1 -1
  64. package/dist-types/components/localize/src/date/formatDate.d.ts.map +1 -1
  65. package/dist-types/components/localize/src/date/parseDate.d.ts.map +1 -1
  66. package/dist-types/components/localize/src/getLocalizeManager.d.ts +60 -0
  67. package/dist-types/components/localize/src/getLocalizeManager.d.ts.map +1 -0
  68. package/dist-types/components/localize/src/number/formatNumber.d.ts.map +1 -1
  69. package/dist-types/components/localize/src/number/getCurrencyName.d.ts.map +1 -1
  70. package/dist-types/components/localize/src/number/parseNumber.d.ts.map +1 -1
  71. package/dist-types/components/localize/src/number/utils/emptyStringWhenNumberNan.d.ts.map +1 -1
  72. package/dist-types/components/localize/src/singleton.d.ts +5 -3
  73. package/dist-types/components/localize/src/singleton.d.ts.map +1 -1
  74. package/dist-types/components/localize/src/utils/getLocale.d.ts.map +1 -1
  75. package/dist-types/components/localize/test/getLocalizeManager.test.d.ts +2 -0
  76. package/dist-types/components/localize/test/getLocalizeManager.test.d.ts.map +1 -0
  77. package/dist-types/components/localize/test/side-effect-free-entrypoint.test.d.ts +2 -0
  78. package/dist-types/components/localize/test/side-effect-free-entrypoint.test.d.ts.map +1 -0
  79. package/dist-types/components/localize/test-helpers/localizeTearDown.d.ts.map +1 -1
  80. package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts +4 -1
  81. package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts.map +1 -1
  82. package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts.map +1 -1
  83. package/dist-types/components/select/src/LionSelect.d.ts +1 -0
  84. package/dist-types/components/select/src/LionSelect.d.ts.map +1 -1
  85. package/dist-types/exports/localize-no-side-effects.d.ts +18 -0
  86. package/dist-types/tsconfig.tsbuildinfo +1 -1
  87. package/docs/components/checkbox-group/overview.md +2 -2
  88. package/docs/components/collapsible/overview.md +1 -1
  89. package/docs/components/combobox/overview.md +1 -1
  90. package/docs/components/combobox/use-cases.md +1 -1
  91. package/docs/components/dialog/overview.md +1 -1
  92. package/docs/components/fieldset/overview.md +5 -5
  93. package/docs/components/form/overview.md +3 -3
  94. package/docs/components/icon/use-cases.md +1 -1
  95. package/docs/components/input/overview.md +1 -1
  96. package/docs/components/input-amount/overview.md +3 -3
  97. package/docs/components/input-date/overview.md +3 -3
  98. package/docs/components/input-datepicker/overview.md +5 -5
  99. package/docs/components/input-email/overview.md +2 -2
  100. package/docs/components/input-iban/overview.md +2 -2
  101. package/docs/components/input-range/overview.md +2 -2
  102. package/docs/components/input-stepper/overview.md +1 -1
  103. package/docs/components/input-tel/overview.md +1 -1
  104. package/docs/components/input-tel/use-cases.md +6 -6
  105. package/docs/components/input-tel-dropdown/overview.md +1 -1
  106. package/docs/components/radio-group/overview.md +3 -3
  107. package/docs/components/select-rich/use-cases.md +1 -1
  108. package/docs/components/tabs/examples.md +1 -1
  109. package/docs/fundamentals/index.md +4 -4
  110. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  111. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  112. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  113. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  114. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  115. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  116. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  117. package/docs/fundamentals/systems/core/overview.md +1 -1
  118. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  119. package/docs/fundamentals/systems/form/model-value.md +1 -1
  120. package/docs/fundamentals/systems/form/overview.md +28 -28
  121. package/docs/fundamentals/systems/form/validate.md +1 -1
  122. package/docs/fundamentals/systems/localize/overview.md +4 -4
  123. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  124. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  125. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  126. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  127. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  128. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  129. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  130. package/docs/guides/index.md +8 -8
  131. package/docs/guides/principles/index.md +5 -5
  132. package/docs/guides/principles/styling.md +1 -1
  133. package/exports/localize-no-side-effects.js +19 -0
  134. package/package.json +1 -1
@@ -1,16 +1,21 @@
1
1
  import { expect } from '@open-wc/testing';
2
- import { localize, getDateFormatBasedOnLocale } from '@lion/ui/localize.js';
2
+ import {
3
+ getLocalizeManager,
4
+ getDateFormatBasedOnLocale,
5
+ } from '@lion/ui/localize-no-side-effects.js';
3
6
  import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
4
7
 
5
8
  describe('getDateFormatBasedOnLocale()', () => {
9
+ const localizeManager = getLocalizeManager();
10
+
6
11
  beforeEach(() => {
7
12
  localizeTearDown();
8
13
  });
9
14
 
10
15
  it('returns the positions of day, month and year', async () => {
11
- localize.locale = 'en-GB';
16
+ localizeManager.locale = 'en-GB';
12
17
  expect(getDateFormatBasedOnLocale()).to.equal('day-month-year');
13
- localize.locale = 'en-US';
18
+ localizeManager.locale = 'en-US';
14
19
  expect(getDateFormatBasedOnLocale()).to.equal('month-day-year');
15
20
  });
16
21
  });
@@ -1,23 +1,24 @@
1
1
  import { expect } from '@open-wc/testing';
2
- import { parseDate, localize } from '@lion/ui/localize.js';
2
+ import { parseDate, getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
3
3
  import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
4
4
 
5
5
  /**
6
6
  *
7
7
  * @param {Date | undefined} value
8
- * @param {Date} date
8
+ * @param {Date | undefined} date
9
9
  */
10
10
  function equalsDate(value, date) {
11
11
  return (
12
12
  Object.prototype.toString.call(value) === '[object Date]' && // is Date Object
13
13
  value &&
14
- value.getDate() === date.getDate() && // day
14
+ value.getDate() === date?.getDate() && // day
15
15
  value.getMonth() === date.getMonth() && // month
16
16
  value.getFullYear() === date.getFullYear() // year
17
17
  );
18
18
  }
19
19
 
20
20
  describe('parseDate()', () => {
21
+ const localizeManager = getLocalizeManager();
21
22
  beforeEach(() => {
22
23
  localizeTearDown();
23
24
  });
@@ -45,21 +46,35 @@ describe('parseDate()', () => {
45
46
  });
46
47
 
47
48
  it('handles different locales', () => {
48
- localize.locale = 'en-GB';
49
+ localizeManager.locale = 'en-GB';
49
50
  expect(equalsDate(parseDate('31-12-1976'), new Date('1976/12/31'))).to.equal(true);
50
- localize.locale = 'en-US';
51
+ localizeManager.locale = 'en-US';
51
52
  expect(equalsDate(parseDate('12-31-1976'), new Date('1976/12/31'))).to.equal(true);
52
53
  });
53
54
 
55
+ it('handles timezones of the browser and parsed date correctly', () => {
56
+ const referenceDate = new Date('2020/01/30');
57
+ localizeManager.locale = 'nl-NL';
58
+ const parsedDate = parseDate('30-01-2020');
59
+ // time zone offset of parsed date: this value is dependent on the browser (basically where the ci or local machine it runs in is located)
60
+ const parseDateOffset = parsedDate?.getTimezoneOffset();
61
+ // The parseDate time zone should be equal to the default offset of the browser
62
+ const browserTimeZoneOffset = referenceDate.getTimezoneOffset();
63
+ // This will pass, since parseDate respects browser timezone, and not UTC format
64
+ expect(parseDateOffset).to.equal(browserTimeZoneOffset);
65
+ // Optional: verify we are dealing with the same date (this is already tested in other tests?)
66
+ expect(equalsDate(referenceDate, parsedDate)).to.be.true;
67
+ });
68
+
54
69
  it('return undefined when no valid date provided', () => {
55
70
  expect(parseDate('12.12.1976.,')).to.equal(undefined); // wrong delimiter
56
71
  expect(parseDate('foo')).to.equal(undefined); // no date
57
72
 
58
- localize.locale = 'en-GB';
73
+ localizeManager.locale = 'en-GB';
59
74
  expect(parseDate('31.02.2020')).to.equal(undefined); // non existing date
60
75
  expect(parseDate('12.31.2020')).to.equal(undefined); // day & month switched places
61
76
 
62
- localize.locale = 'en-US';
77
+ localizeManager.locale = 'en-US';
63
78
  expect(parseDate('02.31.2020')).to.equal(undefined); // non existing date
64
79
  expect(parseDate('31.12.2020')).to.equal(undefined); // day & month switched places
65
80
  });
@@ -0,0 +1,31 @@
1
+ import { expect } from '@open-wc/testing';
2
+ // @ts-ignore
3
+ import { singletonManager } from 'singleton-manager';
4
+ import { LocalizeManager } from '../src/LocalizeManager.js';
5
+ import { getLocalizeManager } from '../src/getLocalizeManager.js';
6
+
7
+ describe('getLocalizeManager', () => {
8
+ beforeEach(() => {
9
+ // @ts-ignore
10
+ singletonManager._map.clear();
11
+ });
12
+
13
+ it('gets a default instance when nothing registered on singletonManager with "@lion/ui::localize::0.x"', () => {
14
+ expect(singletonManager.get('@lion/ui::localize::0.x')).to.be.undefined;
15
+ const localizeManager = getLocalizeManager();
16
+ expect(localizeManager).to.equal(singletonManager.get('@lion/ui::localize::0.x'));
17
+ });
18
+
19
+ it('gets the same instance when called multiple times', () => {
20
+ const localizeManager = getLocalizeManager();
21
+ const localizeManagerSecondCall = getLocalizeManager();
22
+ expect(localizeManager).to.equal(localizeManagerSecondCall);
23
+ });
24
+
25
+ it('gets the instance that was registered on singletonManager with "@lion/ui::localize::0.x"', () => {
26
+ // Set your own for custom behavior or for deduping purposes
27
+ class MyLocalizeManager extends LocalizeManager {}
28
+ singletonManager.set('@lion/ui::localize::0.x', MyLocalizeManager);
29
+ expect(getLocalizeManager()).to.equal(MyLocalizeManager);
30
+ });
31
+ });
@@ -1,6 +1,6 @@
1
1
  import { expect } from '@open-wc/testing';
2
2
 
3
- import { localize, LocalizeManager } from '@lion/ui/localize.js';
3
+ import { getLocalizeManager, LocalizeManager } from '@lion/ui/localize-no-side-effects.js';
4
4
 
5
5
  /**
6
6
  * @param {LocalizeManager} localizeManagerEl
@@ -16,6 +16,7 @@ function getProtectedMembers(localizeManagerEl) {
16
16
  }
17
17
 
18
18
  describe('localize', () => {
19
+ const localizeManager = getLocalizeManager();
19
20
  // this is an important mindset:
20
21
  // we don't test the singleton
21
22
  // we check that it is an instance of the right class
@@ -23,16 +24,16 @@ describe('localize', () => {
23
24
  // this allows to avoid any side effects caused by changing singleton state between tests
24
25
 
25
26
  it('is an instance of LocalizeManager', () => {
26
- expect(localize).to.be.an.instanceOf(LocalizeManager);
27
+ expect(localizeManager).to.be.an.instanceOf(LocalizeManager);
27
28
  });
28
29
 
29
30
  it('is configured to automatically load namespaces if locale is changed', () => {
30
- const { autoLoadOnLocaleChange } = getProtectedMembers(localize);
31
+ const { autoLoadOnLocaleChange } = getProtectedMembers(localizeManager);
31
32
  expect(autoLoadOnLocaleChange).to.equal(true);
32
33
  });
33
34
 
34
35
  it('is configured to fallback to the locale "en-GB"', () => {
35
- const { fallbackLocale } = getProtectedMembers(localize);
36
+ const { fallbackLocale } = getProtectedMembers(localizeManager);
36
37
  expect(fallbackLocale).to.equal('en-GB');
37
38
  });
38
39
  });
@@ -1,5 +1,5 @@
1
1
  import { expect } from '@open-wc/testing';
2
- import { localize, formatNumber } from '@lion/ui/localize.js';
2
+ import { getLocalizeManager, formatNumber } from '@lion/ui/localize-no-side-effects.js';
3
3
  import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
4
4
 
5
5
  // TODO: This is broken only in Safari 13.1.2 Wait till ci is on 13.1.3 and remove
@@ -20,6 +20,8 @@ const currencySymbol = /** @param {string} currency */ currency => ({
20
20
  });
21
21
 
22
22
  describe('formatNumber', () => {
23
+ const localizeManager = getLocalizeManager();
24
+
23
25
  afterEach(localizeTearDown);
24
26
 
25
27
  it('displays the appropriate amount of decimal places based on currencies spec http://www.currency-iso.org/en/home/tables/table-a1.html', () => {
@@ -74,14 +76,14 @@ describe('formatNumber', () => {
74
76
  expect(formatNumber(undefined)).to.equal('');
75
77
  });
76
78
 
77
- it('uses `localize.formatNumberOptions.returnIfNaN`', () => {
78
- const savedReturnIfNaN = localize.formatNumberOptions.returnIfNaN;
79
+ it('uses `localizeManager.formatNumberOptions.returnIfNaN`', () => {
80
+ const savedReturnIfNaN = localizeManager.formatNumberOptions.returnIfNaN;
79
81
 
80
- localize.formatNumberOptions.returnIfNaN = '-';
82
+ localizeManager.formatNumberOptions.returnIfNaN = '-';
81
83
  // @ts-ignore
82
84
  expect(formatNumber('foo')).to.equal('-');
83
85
 
84
- localize.formatNumberOptions.returnIfNaN = savedReturnIfNaN;
86
+ localizeManager.formatNumberOptions.returnIfNaN = savedReturnIfNaN;
85
87
  });
86
88
 
87
89
  it("can set what to returns when NaN via `returnIfNaN: 'foo'`", () => {
@@ -89,11 +91,11 @@ describe('formatNumber', () => {
89
91
  expect(formatNumber('foo', { returnIfNaN: '-' })).to.equal('-');
90
92
  });
91
93
 
92
- it('uses `localize.locale`', () => {
94
+ it('uses `localizeManager.locale`', () => {
93
95
  expect(formatNumber(123456.789, { style: 'decimal', maximumFractionDigits: 2 })).to.equal(
94
96
  '123,456.79',
95
97
  );
96
- localize.locale = 'de-DE';
98
+ localizeManager.locale = 'de-DE';
97
99
  expect(formatNumber(123456.789, { style: 'decimal', maximumFractionDigits: 2 })).to.equal(
98
100
  '123.456,79',
99
101
  );
@@ -136,7 +138,7 @@ describe('formatNumber', () => {
136
138
  });
137
139
 
138
140
  it('formats numbers correctly', () => {
139
- localize.locale = 'nl-NL';
141
+ localizeManager.locale = 'nl-NL';
140
142
  expect(formatNumber(0, { style: 'decimal', minimumFractionDigits: 2 })).to.equal('0,00');
141
143
  expect(formatNumber(0.1, { style: 'decimal', minimumFractionDigits: 2 })).to.equal('0,10');
142
144
  expect(formatNumber(0.12, { style: 'decimal', minimumFractionDigits: 2 })).to.equal('0,12');
@@ -190,7 +192,7 @@ describe('formatNumber', () => {
190
192
  });
191
193
 
192
194
  it('throws when decimal and group separator are the same value, only when problematic', () => {
193
- localize.locale = 'nl-NL';
195
+ localizeManager.locale = 'nl-NL';
194
196
  const fn = () =>
195
197
  formatNumber(112345678, {
196
198
  style: 'decimal',
@@ -239,7 +241,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
239
241
  });
240
242
 
241
243
  it('formats 2-digit decimals correctly', () => {
242
- localize.locale = 'nl-NL';
244
+ localizeManager.locale = 'nl-NL';
243
245
  Array.from(new Array(100), (val, index) => index).forEach(i => {
244
246
  const iString = `${i}`;
245
247
  let number = 0.0;
@@ -253,7 +255,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
253
255
  describe('normalization', () => {
254
256
  describe('en-GB', () => {
255
257
  it('supports basics', () => {
256
- localize.locale = 'en-GB';
258
+ localizeManager.locale = 'en-GB';
257
259
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('EUR 123,456.79');
258
260
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79');
259
261
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457');
@@ -265,7 +267,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
265
267
 
266
268
  describe('en-US', () => {
267
269
  it('supports basics', () => {
268
- localize.locale = 'en-US';
270
+ localizeManager.locale = 'en-US';
269
271
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('EUR 123,456.79');
270
272
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79');
271
273
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457');
@@ -282,7 +284,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
282
284
  }
283
285
 
284
286
  it('supports basics', () => {
285
- localize.locale = 'en-AU';
287
+ localizeManager.locale = 'en-AU';
286
288
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('EUR 123,456.79');
287
289
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79');
288
290
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457');
@@ -294,7 +296,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
294
296
 
295
297
  describe('en-PH', () => {
296
298
  it('supports basics', () => {
297
- localize.locale = 'en-PH';
299
+ localizeManager.locale = 'en-PH';
298
300
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('EUR 123,456.79');
299
301
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79');
300
302
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457');
@@ -306,7 +308,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
306
308
 
307
309
  describe('nl-NL', () => {
308
310
  it('supports basics', () => {
309
- localize.locale = 'nl-NL';
311
+ localizeManager.locale = 'nl-NL';
310
312
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123.456,79 EUR');
311
313
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123.456,79 USD');
312
314
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123.457 JPY');
@@ -323,7 +325,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
323
325
  }
324
326
 
325
327
  it('supports basics', () => {
326
- localize.locale = 'nl-BE';
328
+ localizeManager.locale = 'nl-BE';
327
329
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123.456,79 EUR');
328
330
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123.456,79 USD');
329
331
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123.457 JPY');
@@ -335,7 +337,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
335
337
 
336
338
  describe('fr-FR', () => {
337
339
  it('supports basics', () => {
338
- localize.locale = 'fr-FR';
340
+ localizeManager.locale = 'fr-FR';
339
341
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123 456,79 EUR');
340
342
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD');
341
343
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY');
@@ -351,7 +353,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
351
353
  if (isSafari) {
352
354
  return;
353
355
  }
354
- localize.locale = 'fr-BE';
356
+ localizeManager.locale = 'fr-BE';
355
357
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123 456,79 EUR');
356
358
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD');
357
359
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY');
@@ -363,7 +365,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
363
365
 
364
366
  describe('bg-BG', () => {
365
367
  it('supports basics', () => {
366
- localize.locale = 'bg-BG';
368
+ localizeManager.locale = 'bg-BG';
367
369
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123 456,79 EUR');
368
370
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD');
369
371
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY');
@@ -373,7 +375,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
373
375
  });
374
376
 
375
377
  it('normalizes group separator', () => {
376
- localize.locale = 'bg-BG';
378
+ localizeManager.locale = 'bg-BG';
377
379
  expect(formatNumber(1.234, currencyCode('EUR'))).to.equal('1,23 EUR');
378
380
  expect(formatNumber(1234.567, currencyCode('EUR'))).to.equal('1 234,57 EUR');
379
381
  expect(formatNumber(-1234.567, currencyCode('EUR'))).to.equal('−1 234,57 EUR');
@@ -382,7 +384,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
382
384
 
383
385
  describe('cs-CZ', () => {
384
386
  it('supports basics', () => {
385
- localize.locale = 'cs-CZ';
387
+ localizeManager.locale = 'cs-CZ';
386
388
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123 456,79 EUR');
387
389
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD');
388
390
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY');
@@ -401,7 +403,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
401
403
  }
402
404
 
403
405
  it('supports basics', () => {
404
- localize.locale = 'tr-TR';
406
+ localizeManager.locale = 'tr-TR';
405
407
  expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123.456,79 EUR');
406
408
  expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123.456,79 USD');
407
409
  expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123.457 JPY');
@@ -413,7 +415,7 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
413
415
  });
414
416
 
415
417
  it('forces turkish currency code ', () => {
416
- localize.locale = 'tr-TR';
418
+ localizeManager.locale = 'tr-TR';
417
419
  expect(
418
420
  formatNumber(1234.56, { style: 'currency', currencyDisplay: 'code', currency: 'TRY' }),
419
421
  ).to.equal('1.234,56 TL');
@@ -428,10 +430,10 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
428
430
  /** @type {Map<string, import('../../types/LocalizeMixinTypes.js').NumberPostProcessor>} */
429
431
  let savedpostProcessors;
430
432
  beforeEach(() => {
431
- savedpostProcessors = localize.formatNumberOptions.postProcessors;
433
+ savedpostProcessors = localizeManager.formatNumberOptions.postProcessors;
432
434
  });
433
435
  afterEach(() => {
434
- localize.formatNumberOptions.postProcessors = savedpostProcessors;
436
+ localizeManager.formatNumberOptions.postProcessors = savedpostProcessors;
435
437
  });
436
438
 
437
439
  /**
@@ -460,8 +462,8 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
460
462
  ).to.equal('112 345 678');
461
463
  });
462
464
 
463
- it('uses `localize.formatNumberOptions.postProcessors`', () => {
464
- localize.setNumberPostProcessorForLocale({
465
+ it('uses `localizeManager.formatNumberOptions.postProcessors`', () => {
466
+ localizeManager.setNumberPostProcessorForLocale({
465
467
  locale: 'en-GB',
466
468
  postProcessor: commaToSpaceProcessor,
467
469
  });
@@ -469,11 +471,11 @@ Please specify .groupSeparator / .decimalSeparator on the formatOptions object t
469
471
  expect(formatNumber(112345678)).to.equal('112 345 678');
470
472
  });
471
473
 
472
- it('uses `options.postProcessors` and `localize.formatNumberOptions.postProcessors`', () => {
474
+ it('uses `options.postProcessors` and `localizeManager.formatNumberOptions.postProcessors`', () => {
473
475
  const postProcessors = new Map();
474
476
  postProcessors.set('en-GB', commaToSpaceProcessor);
475
477
 
476
- localize.setNumberPostProcessorForLocale({
478
+ localizeManager.setNumberPostProcessorForLocale({
477
479
  locale: 'en-GB',
478
480
  postProcessor: firstSpaceToDotProcessor,
479
481
  });
@@ -1,5 +1,5 @@
1
1
  import { expect } from '@open-wc/testing';
2
- import { localize, formatNumberToParts } from '@lion/ui/localize.js';
2
+ import { getLocalizeManager, formatNumberToParts } from '@lion/ui/localize-no-side-effects.js';
3
3
  import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
4
4
 
5
5
  // TODO: This is broken only in Safari 13.1.2 Wait till ci is on 13.1.3 and remove
@@ -28,6 +28,8 @@ const stringifyParts =
28
28
  parts => parts.map(part => part.value).join('');
29
29
 
30
30
  describe('formatNumberToParts', () => {
31
+ const localizeManager = getLocalizeManager();
32
+
31
33
  afterEach(localizeTearDown);
32
34
 
33
35
  describe("style: 'currency symbol'", () => {
@@ -114,7 +116,7 @@ describe('formatNumberToParts', () => {
114
116
  it(`formats ${locale} ${amount} as "${stringifyParts(
115
117
  /** @type {FormatNumberPart[]} */ (expectedResult),
116
118
  )}"`, () => {
117
- localize.locale = locale;
119
+ localizeManager.locale = locale;
118
120
  expect(
119
121
  formatNumberToParts(Number(amount), {
120
122
  style: 'decimal',
@@ -143,7 +145,7 @@ describe('formatNumberToParts', () => {
143
145
  it(`formats ${locale} ${amount} as "${stringifyParts(
144
146
  /** @type {FormatNumberPart[]} */ (expectedResult),
145
147
  )}"`, () => {
146
- localize.locale = locale;
148
+ localizeManager.locale = locale;
147
149
  expect(
148
150
  formatNumberToParts(Number(amount), {
149
151
  style: 'decimal',
@@ -1,5 +1,5 @@
1
1
  import { expect } from '@open-wc/testing';
2
- import { getCurrencyName } from '@lion/ui/localize.js';
2
+ import { getCurrencyName } from '@lion/ui/localize-no-side-effects.js';
3
3
  import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
4
4
 
5
5
  describe('getCurrencyName', () => {
@@ -1,7 +1,9 @@
1
1
  import { expect } from '@open-wc/testing';
2
- import { localize, parseNumber } from '@lion/ui/localize.js';
2
+ import { getLocalizeManager, parseNumber } from '@lion/ui/localize-no-side-effects.js';
3
3
 
4
4
  describe('parseNumber()', () => {
5
+ const localizeManager = getLocalizeManager();
6
+
5
7
  it('parses integers', () => {
6
8
  expect(parseNumber('1')).to.equal(1);
7
9
  expect(parseNumber('12')).to.equal(12);
@@ -79,13 +81,13 @@ describe('parseNumber()', () => {
79
81
  });
80
82
 
81
83
  it('uses locale to parse amount if there is only one separator e.g. 1.234', () => {
82
- localize.locale = 'en-GB';
84
+ localizeManager.locale = 'en-GB';
83
85
  expect(parseNumber('12.34')).to.equal(12.34);
84
86
  expect(parseNumber('12,34')).to.equal(1234);
85
87
  expect(parseNumber('1.234')).to.equal(1.234);
86
88
  expect(parseNumber('1,234')).to.equal(1234);
87
89
 
88
- localize.locale = 'nl-NL';
90
+ localizeManager.locale = 'nl-NL';
89
91
  expect(parseNumber('12.34')).to.equal(1234);
90
92
  expect(parseNumber('12,34')).to.equal(12.34);
91
93
  expect(parseNumber('1.234')).to.equal(1234);
@@ -105,30 +107,46 @@ describe('parseNumber()', () => {
105
107
  expect(parseNumber('1 23.4')).to.equal(123.4);
106
108
  });
107
109
 
108
- it('parses negative numbers', () => {
109
- expect(parseNumber('-0')).to.equal(0);
110
- expect(parseNumber('-1')).to.equal(-1);
111
- expect(parseNumber('-1234')).to.equal(-1234);
112
- expect(parseNumber('-1.234,5')).to.equal(-1234.5);
113
- expect(parseNumber('-1,234.5')).to.equal(-1234.5);
114
- expect(parseNumber('-1.234,5678')).to.equal(-1234.5678);
115
- expect(parseNumber('-1,234.5678')).to.equal(-1234.5678);
116
- });
117
-
118
110
  it('ignores all non-number symbols (including currency)', () => {
119
111
  expect(parseNumber('€ 1,234.56')).to.equal(1234.56);
120
- expect(parseNumber('€ -1,234.56')).to.equal(-1234.56);
121
- expect(parseNumber('-€ 1,234.56')).to.equal(-1234.56);
122
112
  expect(parseNumber('1,234.56 €')).to.equal(1234.56);
123
- expect(parseNumber('-1,234.56 €')).to.equal(-1234.56);
124
113
  expect(parseNumber('EUR 1,234.56')).to.equal(1234.56);
125
- expect(parseNumber('EUR -1,234.56')).to.equal(-1234.56);
126
- expect(parseNumber('-EUR 1,234.56')).to.equal(-1234.56);
127
114
  expect(parseNumber('1,234.56 EUR')).to.equal(1234.56);
128
- expect(parseNumber('-1,234.56 EUR')).to.equal(-1234.56);
129
115
  expect(parseNumber('Number is 1,234.56')).to.equal(1234.56);
130
116
  });
131
117
 
118
+ describe('negative numbers', () => {
119
+ it('can get parsed', () => {
120
+ expect(parseNumber('-0')).to.equal(0);
121
+ expect(parseNumber('-1')).to.equal(-1);
122
+ expect(parseNumber('-1234')).to.equal(-1234);
123
+ expect(parseNumber('-1.234,5')).to.equal(-1234.5);
124
+ expect(parseNumber('-1,234.5')).to.equal(-1234.5);
125
+ expect(parseNumber('-1.234,5678')).to.equal(-1234.5678);
126
+ expect(parseNumber('-1,234.5678')).to.equal(-1234.5678);
127
+ });
128
+
129
+ it('parses different type of hypens', () => {
130
+ expect(parseNumber('-1')).to.equal(-1, 'Hypen');
131
+ expect(parseNumber('−1')).to.equal(-1, 'Minus-Sign');
132
+ });
133
+
134
+ it('ignores all non-number symbols (including currency)', () => {
135
+ expect(parseNumber('€ -1,234.56')).to.equal(-1234.56);
136
+ expect(parseNumber('-€ 1,234.56')).to.equal(-1234.56);
137
+ expect(parseNumber('-1,234.56 €')).to.equal(-1234.56);
138
+ expect(parseNumber('EUR -1,234.56')).to.equal(-1234.56);
139
+ expect(parseNumber('-EUR 1,234.56')).to.equal(-1234.56);
140
+ expect(parseNumber('-1,234.56 EUR')).to.equal(-1234.56);
141
+ });
142
+
143
+ it('detects separators unparseable when there are 2 same ones e.g. -1.234.56', () => {
144
+ expect(parseNumber('-1.234.56')).to.equal(-123456);
145
+ expect(parseNumber('-1,234,56')).to.equal(-123456);
146
+ expect(parseNumber('-1 234 56')).to.equal(-123456);
147
+ });
148
+ });
149
+
132
150
  it('ignores non-number characters and returns undefined', () => {
133
151
  expect(parseNumber('A')).to.equal(undefined);
134
152
  expect(parseNumber('EUR')).to.equal(undefined);
@@ -0,0 +1,38 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import sinon from 'sinon';
3
+ // @ts-ignore
4
+ import { singletonManager } from 'singleton-manager';
5
+
6
+ /**
7
+ * @typedef {import('../types/LocalizeMixinTypes.js').LocalizeMixin} LocalizeMixinHost
8
+ */
9
+
10
+ describe('Entrypoints localize', () => {
11
+ /** @type {import('sinon').SinonSpy} */
12
+ let singletonManagerSetSpy;
13
+ beforeEach(() => {
14
+ singletonManagerSetSpy = sinon.spy(singletonManager, 'set');
15
+ });
16
+ afterEach(() => {
17
+ singletonManagerSetSpy.restore();
18
+ });
19
+
20
+ it('"@lion/ui/localize-no-side-effects.js" has no side effects (c.q. does not register itself on singletonManager)', async () => {
21
+ await import('@lion/ui/localize-no-side-effects.js');
22
+
23
+ expect(singletonManagerSetSpy).to.not.have.been.called;
24
+ });
25
+
26
+ it('"@lion/ui/localize.js" has side effects (c.q. registers itself on singletonManager)', async () => {
27
+ await import('@lion/ui/localize.js');
28
+
29
+ expect(singletonManagerSetSpy).to.have.been.calledOnce;
30
+
31
+ const { getLocalizeManager } = await import('@lion/ui/localize-no-side-effects.js');
32
+
33
+ expect(singletonManagerSetSpy).to.have.been.calledWith(
34
+ '@lion/ui::localize::0.x',
35
+ getLocalizeManager(),
36
+ );
37
+ });
38
+ });
@@ -1,11 +1,12 @@
1
- import { localize } from '@lion/ui/localize.js';
1
+ import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
2
2
 
3
3
  export const localizeTearDown = () => {
4
+ const localizeManager = getLocalizeManager();
4
5
  // makes sure that between tests the localization is reset to default state
5
6
  // @ts-ignore
6
- localize._teardownHtmlLangAttributeObserver();
7
+ localizeManager._teardownHtmlLangAttributeObserver();
7
8
  document.documentElement.lang = 'en-GB';
8
9
  // @ts-ignore
9
- localize._setupHtmlLangAttributeObserver();
10
- localize.reset();
10
+ localizeManager._setupHtmlLangAttributeObserver();
11
+ localizeManager.reset();
11
12
  };
@@ -1,5 +1,7 @@
1
1
  import { Constructor } from '@open-wc/dedupe-mixin';
2
2
  import { LitElement } from 'lit';
3
+ import { DirectiveResult } from 'lit/directive.js';
4
+ import { LocalizeManager } from '../src/LocalizeManager.js';
3
5
 
4
6
  export interface FormatNumberPart {
5
7
  type: string;
@@ -75,7 +77,13 @@ export declare class LocalizeMixinHost {
75
77
  public onLocaleUpdated(): void;
76
78
  public connectedCallback(): void;
77
79
  public disconnectedCallback(): void;
78
- public msgLit(keys: string | string[], variables?: msgVariables, options?: msgOptions): void;
80
+ public msgLit(
81
+ keys: string | string[],
82
+ variables?: msgVariables,
83
+ options?: msgOptions,
84
+ ): string | DirectiveResult;
85
+
86
+ protected _localizeManager: LocalizeManager;
79
87
 
80
88
  private __boundLocalizeOnLocaleChanged(...args: Object[]): void;
81
89
  private __boundLocalizeOnLocaleChanging(...args: Object[]): void;
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable import/no-extraneous-dependencies */
2
2
  import { LitElement, html, css } from 'lit';
3
- import { LocalizeMixin } from '@lion/ui/localize.js';
3
+ import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js';
4
4
 
5
5
  /**
6
6
  * @typedef {import('lit').TemplateResult} TemplateResult
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable import/no-extraneous-dependencies */
2
2
  import { LitElement, nothing } from 'lit';
3
- import { localize, LocalizeMixin } from '@lion/ui/localize.js';
3
+ import { getLocalizeManager, LocalizeMixin } from '@lion/ui/localize-no-side-effects.js';
4
4
 
5
5
  /**
6
6
  * @typedef {import('lit').TemplateResult} TemplateResult
@@ -195,10 +195,11 @@ export class LionProgressIndicator extends LocalizeMixin(LitElement) {
195
195
  }
196
196
 
197
197
  _setDefaultLabel() {
198
+ const localizeManager = getLocalizeManager();
198
199
  if (this._ariaLabelledby) {
199
200
  this.removeAttribute('aria-label');
200
201
  } else if (!this._ariaLabel) {
201
- this.setAttribute('aria-label', localize.msg('lion-progress-indicator:loading'));
202
+ this.setAttribute('aria-label', localizeManager.msg('lion-progress-indicator:loading'));
202
203
  this.__hasDefaultLabelSet = true;
203
204
  }
204
205
  }
@@ -60,6 +60,20 @@ export class LionSelect extends LionFieldWithSelect {
60
60
  connectedCallback() {
61
61
  super.connectedCallback();
62
62
  this._inputNode.addEventListener('change', this._proxyChangeEvent);
63
+
64
+ this.__selectObserver = new MutationObserver(() => {
65
+ this._syncValueUpwards();
66
+ // We need to force computation of other values in case model didn't change
67
+ // This can happen when options are loaded asynchronously so the modelValue doesn't change
68
+ // The MutationObserver detects this and makes sure the modelValue is updated
69
+ this._calculateValues({ source: 'model' });
70
+ });
71
+
72
+ this.__selectObserver.observe(this._inputNode, {
73
+ attributes: true,
74
+ childList: true,
75
+ subtree: true,
76
+ });
63
77
  }
64
78
 
65
79
  /** @param {import('lit').PropertyValues } changedProperties */
@@ -82,6 +96,7 @@ export class LionSelect extends LionFieldWithSelect {
82
96
  disconnectedCallback() {
83
97
  super.disconnectedCallback();
84
98
  this._inputNode.removeEventListener('change', this._proxyChangeEvent);
99
+ this.__selectObserver?.disconnect();
85
100
  }
86
101
 
87
102
  /**