qc-trousse-sdg 1.4.6 → 1.4.7

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 (57) hide show
  1. package/README.md +10 -0
  2. package/dist/css/qc-sdg-no-grid.min.css +1 -1
  3. package/dist/css/qc-sdg.min.css +1 -1
  4. package/dist/js/qc-sdg.min.js +1 -1
  5. package/package-lock.json +4689 -0
  6. package/package.json +1 -1
  7. package/public/css/qc-doc-sdg.css +38 -6
  8. package/public/css/qc-sdg-no-grid.css +47 -20
  9. package/public/css/qc-sdg.css +47 -20
  10. package/public/index.html +58 -20
  11. package/public/js/qc-doc-sdg.js +294 -204
  12. package/public/js/qc-sdg.js +663 -315
  13. package/src/doc/qc-doc-sdg.js +6 -1
  14. package/src/doc/scss/components/_exemple.scss +5 -1
  15. package/src/doc/scss/qc-doc-sdg.scss +22 -4
  16. package/src/sdg/bases/Icon/Icon.svelte +2 -0
  17. package/src/sdg/bases/links/_links.scss +18 -12
  18. package/src/sdg/components/Alert/Alert.svelte +28 -9
  19. package/src/sdg/components/Alert/AlertWC.svelte +20 -5
  20. package/src/sdg/components/Alert/Test/AlertSvelteTest.svelte +25 -0
  21. package/src/sdg/components/Alert/Test/alertBaselineTest.html +13 -0
  22. package/src/sdg/components/Alert/Test/alertSvelteTest.html +1 -0
  23. package/src/sdg/components/Alert/_alert.html +23 -11
  24. package/src/sdg/components/Checkbox/Checkbox.svelte +6 -5
  25. package/src/sdg/components/DropdownList/DropdownList.svelte +65 -14
  26. package/src/sdg/components/DropdownList/DropdownListButton/DropdownListButton.svelte +2 -6
  27. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItems.svelte +4 -22
  28. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsMultiple/DropdownListItemsMultiple.svelte +2 -1
  29. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsSingle/DropdownListItemsSingle.svelte +2 -1
  30. package/src/sdg/components/DropdownList/SelectWC.svelte +39 -13
  31. package/src/sdg/components/DropdownList/Test/DropdownListSvelteTest.svelte +2 -2
  32. package/src/sdg/components/DropdownList/Test/dropdownListBaselineTest.html +7 -0
  33. package/src/sdg/components/DropdownList/_dropdownList.scss +7 -5
  34. package/src/sdg/components/DropdownList/_select.html +31 -5
  35. package/src/sdg/components/ExternalLink/ExternalLink.svelte +36 -74
  36. package/src/sdg/components/ExternalLink/ExternalLinkWC.svelte +44 -1
  37. package/src/sdg/components/ExternalLink/externalLinkBaselineTest.html +45 -0
  38. package/src/sdg/components/Fieldset/_fieldset.scss +1 -1
  39. package/src/sdg/components/Label/LabelText.svelte +2 -1
  40. package/src/sdg/components/Label/_label.scss +10 -2
  41. package/src/sdg/components/PivFooter/_pivFooter.html +4 -4
  42. package/src/sdg/components/TextField/Test/TextFieldEmbededTest.svelte +19 -3
  43. package/src/sdg/components/TextField/Test/textFieldBaselineTest.html +5 -2
  44. package/src/sdg/components/TextField/TextField.svelte +12 -6
  45. package/src/sdg/components/TextField/TextFieldWC.svelte +18 -6
  46. package/src/sdg/components/TextField/textFieldUtils.js +3 -2
  47. package/src/sdg/components/utils.js +23 -0
  48. package/src/sdg/qc-sdg-test.js +2 -1
  49. package/src/sdg/scss/lib/_mixins.scss +6 -0
  50. package/src/sdg/scss/utilities/_states.scss +1 -1
  51. package/tests/alert-baseline.spec.ts +23 -0
  52. package/tests/alert-svelte.spec.ts +23 -0
  53. package/tests/buildSvelteTestsIgnore.json +2 -1
  54. package/tests/dropdown-list-baseline.spec.ts +8 -0
  55. package/tests/external-link-baseline.spec.ts +30 -0
  56. package/tests/textfield-baseline.spec.ts +5 -5
  57. package/tests/textfield-svelte.spec.ts +5 -5
@@ -34,7 +34,9 @@
34
34
  rootElement = $state(),
35
35
  textFieldRow = $state(),
36
36
  defaultInvalidText = $derived.by(() => {
37
- if (!maxlengthReached) return '';
37
+ if (!maxlengthReached) {
38
+ return undefined;
39
+ }
38
40
  return lang === 'fr'
39
41
  ? `La limite de caractères du champ ${label} est dépassée.`
40
42
  : `The character limit for the ${label} field has been exceeded.`
@@ -44,13 +46,18 @@
44
46
  onMount(() => {
45
47
  if (webComponentMode) return;
46
48
  if (!input) {
47
- input = rootElement.querySelector('input,textarea');
49
+ input = rootElement?.querySelector('input,textarea');
48
50
  }
49
51
  onMountInput(
50
52
  input,
51
53
  textFieldRowParam => textFieldRow = textFieldRowParam,
52
54
  valueParam => value = valueParam,
53
- invalidParam => invalid = invalidParam
55
+ invalidParam => invalid = invalidParam,
56
+ requiredParam => {
57
+ if (requiredParam) {
58
+ required = requiredParam;
59
+ }
60
+ }
54
61
  )
55
62
  })
56
63
 
@@ -117,7 +124,6 @@
117
124
  input.setAttribute('aria-invalid', invalid)
118
125
  input.setAttribute('aria-required', required)
119
126
  })
120
-
121
127
  </script>
122
128
 
123
129
  {#snippet textfield()}
@@ -140,7 +146,7 @@
140
146
  </div>
141
147
  {/if}
142
148
 
143
- {@render children()}
149
+ {@render children?.()}
144
150
 
145
151
  {#if maxlength && maxlength !== null}
146
152
  <div
@@ -157,7 +163,7 @@
157
163
  {/if}
158
164
 
159
165
  <FormError {invalid}
160
- invalidText={invalidText ? invalidText : defaultInvalidText}
166
+ invalidText={invalidText ? invalidText : defaultInvalidText}
161
167
  label={label ? label : input?.getAttribute("aria-label")}
162
168
  bind:id={errorId}
163
169
  extraClasses={['qc-xs-mt']}
@@ -40,11 +40,22 @@
40
40
  textFieldRow = $state()
41
41
  ;
42
42
  onMount(() => {
43
- input = $host().querySelector('input,textarea');
43
+ const initialLabelElement = $host()?.querySelector('label');
44
+ if (initialLabelElement) {
45
+ label = initialLabelElement.innerHTML;
46
+ initialLabelElement.remove();
47
+ }
48
+
49
+ input = $host()?.querySelector('input,textarea');
44
50
  onMountInput(input,
45
51
  textFieldRowParam => textFieldRow = textFieldRowParam,
46
52
  valueParam => value = valueParam,
47
- invalidParam => invalid = invalidParam
53
+ invalidParam => invalid = invalidParam,
54
+ requiredParam => {
55
+ if (requiredParam) {
56
+ required = requiredParam;
57
+ }
58
+ }
48
59
  )
49
60
  })
50
61
 
@@ -55,9 +66,6 @@
55
66
 
56
67
  $effect(() => {
57
68
  if (!input) return;
58
- if (label) {
59
- input.before(labelElement);
60
- }
61
69
  if (description) {
62
70
  input.before(descriptionElement);
63
71
  }
@@ -72,7 +80,11 @@
72
80
  textFieldRow.appendChild(formErrorElement);
73
81
  }
74
82
  else {
75
- input.after(formErrorElement);
83
+ if (maxlengthElement) {
84
+ maxlengthElement.after(formErrorElement);
85
+ } else {
86
+ input.after(formErrorElement);
87
+ }
76
88
  }
77
89
  })
78
90
  </script>
@@ -1,6 +1,6 @@
1
1
  import {Utils} from "../utils";
2
2
 
3
- export function onMountInput(input, setTextFieldRow, setValue, setInvalid) {
3
+ export function onMountInput(input, setTextFieldRow, setValue, setInvalid, setRequired) {
4
4
  if (!input) return;
5
5
  if (!input.autocomplete) {
6
6
  input.autocomplete = "off"
@@ -8,7 +8,8 @@ export function onMountInput(input, setTextFieldRow, setValue, setInvalid) {
8
8
  if (!input.id) {
9
9
  input.id = Utils.generateId(input.type);
10
10
  }
11
- setValue(input.value)
11
+ setValue(input.value);
12
+ setRequired(input.required);
12
13
  input.addEventListener(
13
14
  'input',
14
15
  () => {
@@ -134,6 +134,29 @@ export class Utils {
134
134
  // Convertit le mot en minuscules.
135
135
  return word.toLowerCase();
136
136
  }
137
+
138
+ static now() {
139
+ return (new Date()).getTime();
140
+ }
141
+
142
+ /**
143
+ * Creates a MutationObserver instance with selector nesting check
144
+ * @param rootElement
145
+ * @param callback
146
+ * @param selector
147
+ * @returns {MutationObserver | null}
148
+ */
149
+ static createMutationObserver(rootElement, callback, selector) {
150
+ if (!selector) {
151
+ selector = rootElement.tagName.toLowerCase();
152
+ }
153
+ if (rootElement.querySelector(selector)) {
154
+ console.warn(`Imbrication d'éléments "${selector}" détectée. Le MutationObserver n'est pas créé`);
155
+ return null;
156
+ }
157
+
158
+ return new MutationObserver(callback);
159
+ }
137
160
  }
138
161
 
139
162
  function getCacheBustingParam(cssPath, currentScriptSrc) {
@@ -7,4 +7,5 @@ export * from './components/TextField/Test/TextFieldEmbededTest.svelte';
7
7
  export * from "./components/DropdownList/Test/DropdownListSvelteTest.svelte";
8
8
  export * from "./components/ChoiceGroup/Test/ChoiceGroupeEmbededTest.svelte";
9
9
  export * from "./components/ToggleSwitch/Test/ToggleSwitchEmbeddedTest.svelte";
10
- export * from "./components/PivHeader/Test/pivHeaderEmbeddedTest.svelte";
10
+ export * from "./components/PivHeader/Test/pivHeaderEmbeddedTest.svelte";
11
+ export * from "./components/Alert/Test/AlertSvelteTest.svelte";
@@ -38,11 +38,17 @@
38
38
  @mixin hover-link() {
39
39
  color: token-value(color, link, hover);
40
40
  text-decoration: none;
41
+ .qc-ext-link-text {
42
+ text-decoration: none;
43
+ }
41
44
  }
42
45
 
43
46
  @mixin active-link() {
44
47
  color: token-value(color, link, active);
45
48
  text-decoration: none;
49
+ .qc-ext-link-text {
50
+ text-decoration: none;
51
+ }
46
52
  }
47
53
 
48
54
  @mixin focus-link() {
@@ -3,7 +3,7 @@
3
3
  .qc-required {
4
4
  @include content-font(md, bold);
5
5
  color: token-value(color, red, regular);
6
- margin-left: rem(6);
6
+ margin-left: token-value(spacer, xs);
7
7
  }
8
8
 
9
9
  .qc-disabled {
@@ -0,0 +1,23 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import path = require('path');
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ const htmlFilePath = path.resolve(__dirname, '../public/alertBaseline.test.html');
6
+ await page.goto(`file://${htmlFilePath}`);
7
+ });
8
+
9
+ test('Alert baseline', {
10
+ tag: ['@alert', '@baseline']
11
+ }, async ({ page }) => {
12
+ await expect(page).toHaveScreenshot('alert.png', { fullPage: true });
13
+ });
14
+
15
+ test('Fermeture d\'alerte', {
16
+ tag: ['@alert', '@baseline']
17
+ }, async ({ page }) => {
18
+ await page.getByRole('button', { name: 'Fermer l’alerte' }).click();
19
+ await expect(page).toHaveScreenshot('alert-hide.png', { fullPage: true });
20
+
21
+ await page.reload();
22
+ await expect(page).toHaveScreenshot('alert-hide.png', { fullPage: true });
23
+ });
@@ -0,0 +1,23 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import path = require('path');
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ const htmlFilePath = path.resolve(__dirname, '../public/alertSvelte.test.html');
6
+ await page.goto(`file://${htmlFilePath}`);
7
+ });
8
+
9
+ test('Alert svelte', {
10
+ tag: ['@alert', '@svelte']
11
+ }, async ({ page }) => {
12
+ await expect(page).toHaveScreenshot('alert.png', { fullPage: true });
13
+ });
14
+
15
+ test('Fermeture d\'alerte', {
16
+ tag: ['@alert', '@svelte']
17
+ }, async ({ page }) => {
18
+ await page.getByRole('button', { name: 'Fermer l’alerte' }).click();
19
+ await expect(page).toHaveScreenshot('alert-hide.png', { fullPage: true });
20
+
21
+ await page.reload();
22
+ await expect(page).toHaveScreenshot('alert-hide.png', { fullPage: true });
23
+ });
@@ -1,5 +1,6 @@
1
1
  [
2
2
  "**/button-baseline.spec.ts",
3
3
  "**/dropdown-list-baseline.spec.ts",
4
- "**/piv-header-baseline.spec.ts"
4
+ "**/piv-header-baseline.spec.ts",
5
+ "**/external-link-baseline.spec.ts"
5
6
  ]
@@ -26,6 +26,14 @@ test.describe('Rendu visuel',
26
26
  await expect(page).toHaveScreenshot('dropdownListTextWrap.png', {fullPage: true});
27
27
  });
28
28
 
29
+ test('Select tiroir au-dessus', {
30
+ tag: ['@baseline', '@popup-above', '@dropdownlist']
31
+ }, async ({ page }) => {
32
+ await page.getByRole('combobox', { name: 'Régions desservies' }).click();
33
+
34
+ await expect(page).toHaveScreenshot('dropdownListPopupAbove.png', {fullPage: true});
35
+ });
36
+
29
37
  test('Select svelte', {
30
38
  tag: ['@svelte', '@dropdownlist']
31
39
  }, async ({ page }) => {
@@ -0,0 +1,30 @@
1
+ import {expect, test} from "@playwright/test";
2
+ import path = require('path');
3
+ import {link} from "node:fs";
4
+
5
+ test.beforeEach(async ({ page }) => {
6
+ const htmlFilePath = path.resolve(__dirname, '../public/externalLinkBaseline.test.html');
7
+ await page.goto(`file://${htmlFilePath}`);
8
+ });
9
+
10
+ test.describe('Rendu visuel', () => {
11
+ test(
12
+ 'Survol de lien', {
13
+ tag: ['@baseline', '@external-link']
14
+ }, async ({ page }) => {
15
+ await page.getByRole('link', { name: 'Lorem ipsum dolor sit amet,' }).first().hover();
16
+
17
+ await expect(page).toHaveScreenshot('externalLinkHover.png', {fullPage: true});
18
+ });
19
+
20
+ test(
21
+ 'Clique sur lien', {
22
+ tag: ['@baseline', '@external-link']
23
+ }, async ({ page }) => {
24
+ await page.locator('#multi-links').evaluate((link: HTMLElement) => {
25
+ link.querySelector('a').innerHTML = 'Cliquez ici';
26
+ });
27
+
28
+ await expect(page).toHaveScreenshot('externalLinkChange.png', {fullPage: true});
29
+ })
30
+ });
@@ -15,14 +15,14 @@ test('textfield baseline', {
15
15
 
16
16
  test.describe('Aria', () => {
17
17
  test('aria-required', async ({ page }) => {
18
- await expect(page.getByRole('textbox', { name: 'Large', exact: true })).toHaveAttribute('aria-required', 'true');
18
+ await expect(page.locator('#text-lg')).toHaveAttribute('aria-required', 'true');
19
19
  });
20
20
 
21
21
  test('aria-invalid', async ({ page }) => {
22
- await expect(page.getByRole('textbox', { name: 'Moyen', exact: true })).toHaveAttribute('aria-invalid', 'true');
22
+ await expect(page.locator('#text-md')).toHaveAttribute('aria-invalid', 'true');
23
23
 
24
- await page.getByRole('textbox', { name: 'Moyen' }).click();
25
- await page.getByRole('textbox', { name: 'Moyen' }).fill('1');
26
- await expect(page.getByRole('textbox', { name: 'Moyen', exact: true })).toHaveAttribute('aria-invalid', 'false');
24
+ await page.locator('#text-md').click();
25
+ await page.locator('#text-md').fill('1');
26
+ await expect(page.locator('#text-md')).toHaveAttribute('aria-invalid', 'false');
27
27
  });
28
28
  });
@@ -15,14 +15,14 @@ test('textfield svelte', {
15
15
 
16
16
  test.describe('Aria', () => {
17
17
  test('aria-required', async ({ page }) => {
18
- await expect(page.getByRole('textbox', { name: 'Large', exact: true })).toHaveAttribute('aria-required', 'true');
18
+ await expect(page.locator('#text-lg')).toHaveAttribute('aria-required', 'true');
19
19
  });
20
20
 
21
21
  test('aria-invalid', async ({ page }) => {
22
- await expect(page.getByRole('textbox', { name: 'Moyen', exact: true })).toHaveAttribute('aria-invalid', 'true');
22
+ await expect(page.locator('#text-md')).toHaveAttribute('aria-invalid', 'true');
23
23
 
24
- await page.getByRole('textbox', { name: 'Moyen' }).click();
25
- await page.getByRole('textbox', { name: 'Moyen' }).fill('1');
26
- await expect(page.getByRole('textbox', { name: 'Moyen', exact: true })).toHaveAttribute('aria-invalid', 'false');
24
+ await page.locator('#text-md').click();
25
+ await page.locator('#text-md').fill('1');
26
+ await expect(page.locator('#text-md')).toHaveAttribute('aria-invalid', 'false');
27
27
  });
28
28
  });