qc-trousse-sdg 1.4.3 → 1.4.5

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 (60) hide show
  1. package/README.md +76 -51
  2. package/dist/css/qc-sdg-design-tokens.min.css +1 -1
  3. package/dist/css/qc-sdg-no-grid.min.css +1 -1
  4. package/dist/css/qc-sdg.min.css +1 -1
  5. package/dist/img/QUEBEC_blanc.svg +3 -12
  6. package/dist/img/QUEBEC_couleur.svg +3 -23
  7. package/dist/js/qc-sdg.min.js +1 -1
  8. package/index.html +1 -1
  9. package/package.json +1 -1
  10. package/public/css/qc-sdg-design-tokens.css +0 -2
  11. package/public/css/qc-sdg-no-grid.css +154 -110
  12. package/public/css/qc-sdg.css +154 -110
  13. package/public/img/QUEBEC_blanc.svg +3 -12
  14. package/public/img/QUEBEC_couleur.svg +3 -23
  15. package/public/img/favicon.ico +0 -0
  16. package/public/index.html +13 -0
  17. package/public/js/qc-doc-sdg.js +31 -34
  18. package/public/js/qc-sdg.js +2049 -1268
  19. package/src/doc/_index.html +3 -0
  20. package/src/sdg/_components.js +0 -1
  21. package/src/sdg/bases/form/_form.scss +0 -4
  22. package/src/sdg/components/Alert/Alert.svelte +1 -1
  23. package/src/sdg/components/Button/_button.scss +35 -12
  24. package/src/sdg/components/Checkbox/Checkbox.svelte +3 -3
  25. package/src/sdg/components/Checkbox/CheckboxWC.svelte +3 -3
  26. package/src/sdg/components/Checkbox/{updateInput.svelte.js → updateChoiceInput.svelte.js} +6 -1
  27. package/src/sdg/components/ChoiceGroup/ChoiceGroup.svelte +2 -2
  28. package/src/sdg/components/ChoiceGroup/Test/ChoiceGroupeEmbededTest.svelte +3 -0
  29. package/src/sdg/components/ChoiceGroup/Test/checkboxBaselineTest.html +3 -0
  30. package/src/sdg/components/DropdownList/DropdownList.svelte +4 -7
  31. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItems.svelte +1 -6
  32. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsMultiple/_dropdownListItemsMultiple.scss +3 -8
  33. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsSingle/_dropdownListItemsSingle.scss +1 -2
  34. package/src/sdg/components/DropdownList/DropdownListItems/_dropdownListItems.scss +2 -4
  35. package/src/sdg/components/DropdownList/SelectWC.svelte +31 -50
  36. package/src/sdg/components/DropdownList/Test/DropdownListSvelteTest.svelte +37 -2
  37. package/src/sdg/components/DropdownList/Test/{dropdownListTest.html → dropdownListBaselineTest.html} +19 -1
  38. package/src/sdg/components/DropdownList/Test/dropdownListTestUtils.js +14 -0
  39. package/src/sdg/components/DropdownList/_dropdownList.scss +11 -16
  40. package/src/sdg/components/DropdownList/_select.html +9 -0
  41. package/src/sdg/components/Fieldset/_fieldset.scss +17 -4
  42. package/src/sdg/components/Label/_label.scss +1 -0
  43. package/src/sdg/components/PivFooter/PivFooter.svelte +2 -2
  44. package/src/sdg/components/PivHeader/PivHeader.svelte +79 -74
  45. package/src/sdg/components/PivHeader/Test/pivHeaderBaselineTest.html +12 -1
  46. package/src/sdg/components/PivHeader/Test/pivHeaderTest.js +9 -0
  47. package/src/sdg/components/PivHeader/_pivHeader.html +1 -0
  48. package/src/sdg/components/PivHeader/_pivHeader.scss +46 -19
  49. package/src/sdg/components/TextField/Test/textFieldBaselineTest.html +24 -5
  50. package/src/sdg/components/TextField/TextField.svelte +29 -25
  51. package/src/sdg/components/TextField/TextFieldWC.svelte +8 -0
  52. package/src/sdg/components/TextField/_textField.scss +6 -13
  53. package/src/sdg/qc-sdg-test.js +4 -0
  54. package/src/sdg/scss/settings/_tokens.scss +0 -4
  55. package/tests/buildSvelteTestsIgnore.json +2 -1
  56. package/tests/dropdown-list-baseline.spec.ts +51 -4
  57. package/tests/piv-header-baseline.spec.ts +3 -0
  58. package/src/sdg/components/Button/Button.svelte +0 -50
  59. package/src/sdg/components/Button/ButtonWC.svelte +0 -36
  60. package/tests/piv-header-svelte.spec.ts +0 -11
@@ -6,18 +6,11 @@
6
6
  $min-height: 40;
7
7
  $border: 1;
8
8
 
9
- .qc-dropdown-list-margin {
9
+ .qc-select {
10
+ display: block;
10
11
  margin-bottom: rem(32);
11
- }
12
-
13
- .qc-dropdown-list-root {
14
- width: 100%;
15
12
 
16
- &-xs { max-width: token-value(size, max-width, xs); }
17
- &-sm { max-width: token-value(size, max-width, sm); }
18
- &-md { max-width: token-value(size, max-width, md); }
19
- &-lg { max-width: token-value(size, max-width, lg); }
20
- &-xl { max-width: token-value(size, max-width, xl); }
13
+ max-width: 100%;
21
14
  }
22
15
 
23
16
  .qc-dropdown-list-container {
@@ -26,12 +19,6 @@ $border: 1;
26
19
  .qc-label {
27
20
  margin-bottom: rem(4);
28
21
  }
29
-
30
- &-xs { max-width: token-value(size, max-width, xs); }
31
- &-sm { max-width: token-value(size, max-width, sm); }
32
- &-md { max-width: token-value(size, max-width, md); }
33
- &-lg { max-width: token-value(size, max-width, lg); }
34
- &-xl { max-width: token-value(size, max-width, xl); }
35
22
  }
36
23
 
37
24
  .qc-dropdown-list {
@@ -40,6 +27,8 @@ $border: 1;
40
27
  border: rem($border) solid token-value(color, grey, medium);
41
28
  min-height: rem($min-height);
42
29
  background-color: token-value(color, background);
30
+ max-width: 100%;
31
+ min-width: 0;
43
32
 
44
33
  &.qc-dropdown-list-invalid {
45
34
  border: rem(2) solid token-value(color, red, regular) !important;
@@ -48,6 +37,12 @@ $border: 1;
48
37
  height: rem(36);
49
38
  }
50
39
  }
40
+
41
+ &-xs { width: token-value(size, max-width, xs); }
42
+ &-sm { width: token-value(size, max-width, sm); }
43
+ &-md { width: token-value(size, max-width, md); }
44
+ &-lg { width: token-value(size, max-width, lg); }
45
+ &-xl { width: token-value(size, max-width, xl); }
51
46
  }
52
47
 
53
48
  .qc-dropdown-list-search {
@@ -75,6 +75,15 @@
75
75
  <option value="2">Option 2</option>
76
76
  </select>
77
77
  </qc-select>
78
+
79
+ <qc-select id="qc-select-multiple-choices-sm" width="sm">
80
+ <label for="select-multiple-choices-sm">Débordement</label>
81
+ <select id="select-multiple-choices-sm" multiple>
82
+ <option value="1">Option 1 + texte de remplissage</option>
83
+ <option value="2">Option 2 + texte de remplissage</option>
84
+ <option value="3">Option 3 + texte de remplissage</option>
85
+ </select>
86
+ </qc-select>
78
87
  </qc-doc-exemple>
79
88
 
80
89
  <h4>Documentation technique</h4>
@@ -1,4 +1,5 @@
1
1
  @use "qc-sdg-lib" as *;
2
+ @use "sass:map";
2
3
 
3
4
  .qc-fieldset {
4
5
  border: none;
@@ -76,7 +77,8 @@ $invalid-border-width: 2px;
76
77
  gap: 0 rem(32);
77
78
  flex-wrap: wrap;
78
79
  margin-bottom: rem(32);
79
- margin-top: rem(-8);
80
+ $mb : token-value(spacer, xs);
81
+ margin-top: calc(-1 * $mb);
80
82
 
81
83
  > .qc-form-error {
82
84
  width: 100%;
@@ -84,12 +86,23 @@ $invalid-border-width: 2px;
84
86
  qc-textfield,
85
87
  .qc-textfield {
86
88
  margin-top: token-value(spacer, xs);
87
- display: block;
88
- width: auto;
89
89
  margin-bottom: 0;
90
+ min-width: 0;
91
+
92
+ $sizes: map.get($lg-tokens, size, max-width);
93
+ @each $size, $width in $sizes {
94
+ [size="#{$size}"] {
95
+ input {
96
+ width: $width;
97
+ max-width: $width;
98
+ }
99
+ }
100
+ }
90
101
  }
91
- .qc-dropdown-list-root {
102
+
103
+ .qc-select {
92
104
  margin-top: token-value(spacer, xs);
93
105
  margin-bottom: 0;
106
+ width: fit-content;
94
107
  }
95
108
  }
@@ -3,6 +3,7 @@
3
3
  .qc-label {
4
4
  font-weight: token-value(font weight content bold);
5
5
  display: block;
6
+ width: fit-content;
6
7
 
7
8
  &.qc-compact {
8
9
  font-size: token-value(font size sm);
@@ -4,8 +4,8 @@
4
4
 
5
5
  let {
6
6
  logoUrl = '/',
7
- logoSrc = Utils.imagesRelativePath + '/QUEBEC_couleur.svg',
8
- logoSrcDarkTheme = Utils.imagesRelativePath + '/QUEBEC_blanc.svg',
7
+ logoSrc = Utils.imagesRelativePath + 'QUEBEC_couleur.svg',
8
+ logoSrcDarkTheme = Utils.imagesRelativePath + 'QUEBEC_blanc.svg',
9
9
  logoAlt = lang === 'fr' ? 'Logo du gouvernement du Québec' : 'Logo of the Quebec government',
10
10
  logoWidth = 139,
11
11
  logoHeight = 50,
@@ -1,6 +1,6 @@
1
1
  <script>
2
- import { onMount, tick } from "svelte";
3
- import { Utils } from "../utils"
2
+ import {onMount, tick} from "svelte";
3
+ import {Utils} from "../utils"
4
4
 
5
5
  const lang = Utils.getPageLanguage();
6
6
 
@@ -46,93 +46,98 @@
46
46
  }
47
47
 
48
48
  onMount(() => {
49
- containerClass += fullWidth === 'true' ? '-fluid' : '';
50
- if (showSearch === 'true') {
51
- enableSearch = 'true'
52
- displaySearchForm = true;
53
- }
49
+ containerClass += fullWidth === 'true' ? '-fluid' : '';
50
+ if (showSearch === 'true') {
51
+ enableSearch = 'true'
52
+ displaySearchForm = true;
53
+ }
54
54
  });
55
55
  </script>
56
56
 
57
57
  <div role="banner"
58
58
  class="qc-piv-header qc-component"
59
- style="--logo-src:url({logoSrc})"
60
59
  >
61
- <div class="{containerClass}">
62
- {#if goToContent === 'true'}
63
- <div class="go-to-content">
64
- <a href="{goToContentAnchor}">
65
- {goToContentText}
66
- </a>
67
- </div>
68
- {/if}
69
- {#snippet title()}
70
- {#if titleUrl && titleText}
71
- <div class="title">
72
- <a href="{titleUrl}">
73
- {titleText}
74
- </a>
75
- </div>
76
- {/if}
77
- {/snippet}
78
- <div class="piv-top">
60
+ <div class="{containerClass}">
61
+ {#if goToContent === 'true'}
62
+ <div class="go-to-content">
63
+ <a href="{goToContentAnchor}">
64
+ {goToContentText}
65
+ </a>
66
+ </div>
67
+ {/if}
68
+ {#snippet title()}
69
+ {#if titleText}
70
+ <div class="title">
71
+ {#if titleUrl && titleUrl.length > 0}
72
+ <a class="page-title" href="{titleUrl}">{titleText}</a>
73
+ {:else}
74
+ <span class="page-title" role="heading" aria-level="1">{titleText}</span>
75
+ {/if}
76
+ </div>
77
+ {/if}
78
+ {/snippet}
79
+ <div class="piv-top">
80
+ <div class="signature-group">
81
+ <div class="logo">
82
+ <a
83
+ href="{logoUrl}"
84
+ rel="noreferrer"
85
+ >
86
+ <img src="{logoSrc}" alt="{logoAlt}" />
87
+ </a>
88
+ </div>
79
89
 
80
- <a href="{logoUrl}"
81
- class="logo"
82
- rel="noreferrer"
83
- aria-label="{logoAlt}"
84
- >
85
- <div role="img"></div>
86
- </a>
90
+ {@render title()}
91
+ </div>
87
92
 
88
- {@render title()}
89
- <div class="right-section">
90
- {#if Utils.isTruthy(enableSearch)}
91
- <a class="qc-search"
92
- href="/"
93
- role="button"
94
- onclick = {(evt) => {
93
+ <div class="right-section">
94
+ {#if Utils.isTruthy(enableSearch)}
95
+ <a class="qc-search"
96
+ href="/"
97
+ role="button"
98
+ onclick={(evt) => {
95
99
  evt.preventDefault();
96
100
  displaySearchForm = !displaySearchForm;
97
101
  tick().then(() => {
98
102
  focusOnSearchInput()
99
103
  });
100
- }}
101
- >
102
- <span>{displaySearchForm ? hideSearchText : displaySearchText}</span>
103
- </a>
104
- {/if}
105
- <div class="links">
106
- {#if (!slots || slots['links']) && linksSlot }
107
- {@render linksSlot()}
108
- <!-- Le bloc else est present uniquement pour le cas ou PivHeader est utilise sans le wrapper PivHeaderWC.svelte -->
109
- {:else}
110
- {#if joinUsUrl || altLanguageUrl}
111
- <nav aria-label="{linksLabel}">
112
- <ul>
113
- {#if altLanguageUrl}
114
- <li><a href="{altLanguageUrl}">{altLanguageText}</a></li>
115
- {/if}
116
- {#if joinUsUrl}
117
- <li><a href="{joinUsUrl}">{joinUsText}</a></li>
118
- {/if}
119
- </ul>
120
- </nav>
104
+ }}
105
+ >
106
+ <span class="no-link-title" role="heading"
107
+ aria-level="1">{displaySearchForm ? hideSearchText : displaySearchText}</span>
108
+ </a>
121
109
  {/if}
110
+ <div class="links">
111
+ {#if (!slots || slots['links']) && linksSlot }
112
+ {@render linksSlot()}
113
+ <!-- Le bloc else est present uniquement pour le cas ou PivHeader est utilise sans le wrapper PivHeaderWC.svelte -->
114
+ {:else}
115
+ {#if joinUsUrl || altLanguageUrl}
116
+ <nav aria-label="{linksLabel}">
117
+ <ul>
118
+ {#if altLanguageUrl}
119
+ <li><a href="{altLanguageUrl}">{altLanguageText}</a></li>
120
+ {/if}
121
+ {#if joinUsUrl}
122
+ <li><a href="{joinUsUrl}">{joinUsText}</a></li>
123
+ {/if}
124
+ </ul>
125
+ </nav>
126
+ {/if}
127
+ {/if}
128
+ </div>
129
+ </div>
130
+ </div>
131
+ {@render title()}
132
+
133
+ <div class="piv-bottom">
134
+ {#if displaySearchForm}
135
+ <div class="search-zone" bind:this={searchZone}>
136
+ {#if searchZoneSlot}
137
+ {@render searchZoneSlot()}
138
+ {/if}
139
+ </div>
122
140
  {/if}
123
141
  </div>
124
- </div>
125
142
  </div>
126
- {@render title()}
127
-
128
- <div class="piv-bottom">
129
- {#if displaySearchForm}
130
- <div class="search-zone" bind:this={searchZone}>
131
- {#if searchZoneSlot}
132
- {@render searchZoneSlot()}
133
- {/if}
134
- </div>
135
- {/if}
136
- </div>
137
- </div>
138
143
  </div>
@@ -23,6 +23,7 @@
23
23
 
24
24
  <div id="pivEnteteExempleRecherchePersonnalisee">
25
25
  <qc-piv-header title-text="Titre du site ou du service"
26
+ title-url=""
26
27
  alt-logo="Accédez à Québec.ca"
27
28
  enable-search="true"
28
29
  show-search="true">
@@ -40,4 +41,14 @@
40
41
  piv-background=""></qc-search-bar>
41
42
  </form>
42
43
  </qc-piv-header>
43
- </div>
44
+ </div>
45
+
46
+ <br>
47
+
48
+ <qc-piv-header
49
+ id="piv-header-mce"
50
+ alt-logo="Accédez à Québec.ca"
51
+ join-us-url="#join-us"
52
+ alt-language-url="#fakeEnglish"
53
+ >
54
+ </qc-piv-header>
@@ -0,0 +1,9 @@
1
+ import {Utils} from "../../utils";
2
+
3
+ export function setMcePivHeaderLogoSrc() {
4
+ document.getElementById('piv-header-mce')
5
+ ?.setAttribute(
6
+ 'logo-src',
7
+ `${Utils.imagesRelativePath}piv-mce-theme-sombre.svg`
8
+ );
9
+ }
@@ -39,6 +39,7 @@
39
39
  >
40
40
  <div id="pivEnteteExempleRecherchePersonnalisee">
41
41
  <qc-piv-header title-text="Titre du site ou du service"
42
+ title-url=""
42
43
  alt-logo="Accédez à Québec.ca"
43
44
  enable-search="true"
44
45
  show-search="true"
@@ -44,27 +44,48 @@ qc-piv-header {
44
44
  }
45
45
  .piv-top {
46
46
  display: flex;
47
+ flex-wrap: nowrap;
48
+ gap: token-value(spacer sm);
47
49
  align-items: start;
48
50
  min-width: rem(72);
49
- .logo {
51
+
52
+ .signature-group {
50
53
  display: flex;
51
- flex-basis: rem(256);
52
- margin-right: 0;
53
- [role=img] {
54
- background-image: var(--logo-src);
55
- background-repeat: no-repeat;
56
- background-size: 100%;
57
- background-position: center;
58
- margin-right: 16px;
59
- min-width: 150px;
60
- width: 100%;
61
- max-width: rem(200);
54
+ flex-grow: 1;
55
+ flex-wrap: wrap;
56
+ align-items: start;
57
+ margin-right: auto;
58
+ & > * {
62
59
  min-height: rem(72);
63
60
  }
61
+
62
+ .logo {
63
+ display: flex;
64
+ align-items: center;
65
+ flex-basis: rem(264);
66
+
67
+ a {
68
+ display: flex;
69
+ height: fit-content;
70
+ width: fit-content;
71
+ outline-offset: rem(4);
72
+
73
+ img {
74
+ display: flex;
75
+ flex-basis: min-content;
76
+ min-width: 150px;
77
+ width: 100%;
78
+ height: 100%;
79
+ max-width: rem(200);
80
+ min-height: rem(40);
81
+ }
82
+ }
83
+ }
64
84
  }
85
+
65
86
  .title {
66
- align-items: center;
67
- align-self: center;
87
+ display: block;
88
+ align-content: center;
68
89
  }
69
90
  .right-section {
70
91
  min-width: fit-content;
@@ -108,10 +129,14 @@ qc-piv-header {
108
129
  }
109
130
  }
110
131
 
132
+ .page-title {
133
+ display: inline-block;
134
+ }
135
+
111
136
  qc-piv-header,
112
137
  .qc-piv-header {
113
138
  a {
114
- --qc-color-link-focus-outline: #{token-value(color blue pale)};
139
+ --qc-color-link-focus-outline: #{map.get($colors, blue, pale)};
115
140
  --qc-color-link-hover: white;
116
141
  --qc-color-link-text: white;
117
142
  --qc-color-link-visited: white;
@@ -161,10 +186,6 @@ qc-piv-header,
161
186
  flex: 1 1 auto;
162
187
  margin-right: auto;
163
188
  min-width: 0;
164
- img {
165
- width: 100%;
166
- margin-right: rem(16);
167
- }
168
189
  }
169
190
 
170
191
  .title {
@@ -191,6 +212,12 @@ qc-piv-header,
191
212
  }
192
213
  }
193
214
 
215
+ .no-link-title {
216
+ margin: 0;
217
+ font-weight: token-value(font weight regular);
218
+ font-size: token-value(font size md);
219
+ }
220
+
194
221
 
195
222
 
196
223
 
@@ -35,7 +35,6 @@
35
35
  name="text-lg"
36
36
  />
37
37
  </qc-textfield>
38
-
39
38
  <qc-textfield
40
39
  label="Très large"
41
40
  size="xl"
@@ -47,11 +46,23 @@
47
46
  disabled
48
47
  />
49
48
  </qc-textfield>
49
+ <div style="width: 500px; max-width: 100%;padding: 10px; border: 1px solid #ccc;">
50
+ <qc-textfield
51
+ label="Très large"
52
+ size="xl"
50
53
 
54
+ >
55
+ <input type="text"
56
+ placeholder="Long placeholder lorem ipsum dolor sit amet"
57
+ name="text-xl"
58
+ disabled
59
+ />
60
+ </qc-textfield>
61
+ </div>
51
62
  <div class="qc-formfield-row">
52
63
  <qc-textfield
53
- label="Combiné 1"
54
- size="sm"
64
+ label="Combiné 1 Long placeholder lorem ipsum dolor sit amet"
65
+ size="lg"
55
66
  >
56
67
  <input type="text"
57
68
  placeholder="Long placeholder lorem ipsum dolor sit amet"
@@ -60,7 +71,7 @@
60
71
  </qc-textfield>
61
72
 
62
73
  <qc-textfield
63
- label="Combiné 2"
74
+ label="Combiné 2 Long placeholder lorem ipsum dolor sit amet"
64
75
  size="xs"
65
76
  >
66
77
  <input type="text"
@@ -92,12 +103,20 @@
92
103
  </div>
93
104
 
94
105
  <qc-textfield label="Commentaires"
95
- size="lg"
96
106
  description="Vous pouvez entrer des commentaires dans la zone de texte ci-dessous."
97
107
  >
98
108
  <textarea name="zone-lg" id="zone-lg"></textarea>
99
109
  </qc-textfield>
100
110
 
111
+ <qc-textfield label="Commentaires"
112
+ description="Vous pouvez entrer des commentaires dans la zone de texte ci-dessous."
113
+ >
114
+ <input type="text"
115
+ name="zone-lg-input"
116
+ placeholder="Long placeholder lorem ipsum dolor sit amet"
117
+ />
118
+ </qc-textfield>
119
+
101
120
  <qc-textfield
102
121
  label="Suggestions"
103
122
  description="Vous pouvez entrer des suggestions dans la zone de texte ci-dessous."
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { Utils } from "../utils";
2
+ import {Utils} from "../utils";
3
3
  import Label from "../Label/Label.svelte";
4
4
  import {getContext, onMount} from "svelte";
5
5
  import FormError from "../FormError/FormError.svelte";
@@ -11,7 +11,7 @@
11
11
  label = '',
12
12
  required = $bindable(false),
13
13
  description,
14
- size,
14
+ size = $bindable(),
15
15
  maxlength,
16
16
  maxlengthReached = $bindable(false),
17
17
  invalidAtSubmit = $bindable(false),
@@ -43,7 +43,7 @@
43
43
 
44
44
  onMount(() => {
45
45
  if (webComponentMode) return;
46
- if (! input) {
46
+ if (!input) {
47
47
  input = rootElement.querySelector('input,textarea');
48
48
  }
49
49
  onMountInput(
@@ -54,6 +54,12 @@
54
54
  )
55
55
  })
56
56
 
57
+ $effect(() => {
58
+ if (size) return;
59
+ if (!input) return;
60
+ size = input.tagName === 'INPUT' ? 'md' : 'lg';
61
+ })
62
+
57
63
  $effect(() => {
58
64
  invalidAtSubmit = (required && !value) || maxlengthReached;
59
65
  })
@@ -72,7 +78,6 @@
72
78
  })
73
79
 
74
80
 
75
-
76
81
  $effect(() => {
77
82
  charCountText = ''
78
83
  if (!maxlength) return;
@@ -83,12 +88,12 @@
83
88
  const s = over > 1 ? 's' : '';
84
89
  charCountText =
85
90
  remaining >= 0
86
- ? lang === 'fr'
87
- ? `${remaining} caractère${s} restant${s}`
88
- : `${remaining} character${s} remaining`
89
- : lang === 'fr'
90
- ? `${over} caractère${s} en trop`
91
- : `${over} character${s} over the limit`
91
+ ? lang === 'fr'
92
+ ? `${remaining} caractère${s} restant${s}`
93
+ : `${remaining} character${s} remaining`
94
+ : lang === 'fr'
95
+ ? `${over} caractère${s} en trop`
96
+ : `${over} character${s} over the limit`
92
97
 
93
98
  });
94
99
 
@@ -107,7 +112,7 @@
107
112
  invalid && errorId,
108
113
  maxlength && charCountId,
109
114
  ].filter(Boolean)
110
- .join(' ')
115
+ .join(' ')
111
116
  )
112
117
  input.setAttribute('aria-invalid', invalid)
113
118
  input.setAttribute('aria-required', required)
@@ -116,7 +121,6 @@
116
121
  </script>
117
122
 
118
123
  {#snippet textfield()}
119
-
120
124
  {#if label}
121
125
  <Label
122
126
  {required}
@@ -124,29 +128,29 @@
124
128
  text={label}
125
129
  forId={input?.id}
126
130
  bind:rootElement={labelElement}
127
- />
131
+ />
128
132
  {/if}
129
133
 
130
134
  {#if description}
131
135
  <div
132
- bind:this={descriptionElement}
133
- id={descriptionId}
134
- class="qc-description">
135
- {@html description}
136
+ bind:this={descriptionElement}
137
+ id={descriptionId}
138
+ class="qc-description">
139
+ {@html description}
136
140
  </div>
137
141
  {/if}
138
142
 
139
143
  {@render children()}
140
144
 
141
- {#if maxlength !== null}
145
+ {#if maxlength && maxlength !== null}
142
146
  <div
143
- bind:this={maxlengthElement}
144
- id={charCountId}
145
- class={[
146
- 'qc-textfield-charcount',
147
- maxlengthReached && 'qc-max-reached'
148
- ]}
149
- aria-live="polite"
147
+ bind:this={maxlengthElement}
148
+ id={charCountId}
149
+ class={[
150
+ 'qc-textfield-charcount',
151
+ maxlengthReached && 'qc-max-reached'
152
+ ]}
153
+ aria-live="polite"
150
154
  >
151
155
  {@html charCountText}
152
156
  </div>
@@ -26,6 +26,7 @@
26
26
  description,
27
27
  required,
28
28
  maxlength,
29
+ size,
29
30
  maxlengthReached = $bindable(false),
30
31
  invalidAtSubmit = $bindable(false),
31
32
  } = $props();
@@ -46,6 +47,12 @@
46
47
  invalidParam => invalid = invalidParam
47
48
  )
48
49
  })
50
+
51
+ $effect(() => {
52
+ if (!size) return;
53
+ $host().setAttribute('size', size);
54
+ })
55
+
49
56
  $effect(() => {
50
57
  if (!input) return;
51
58
  if (label) {
@@ -75,6 +82,7 @@
75
82
  {required}
76
83
  {maxlength}
77
84
  {value}
85
+ bind:size
78
86
  bind:invalid
79
87
  bind:invalidText
80
88
  bind:maxlengthReached