qc-trousse-sdg 1.3.2 → 1.4.0-develop.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 (46) hide show
  1. package/README.md +5 -1
  2. package/dist/js/qc-sdg.min.js +1 -1
  3. package/package.json +3 -3
  4. package/public/index.html +375 -296
  5. package/public/js/qc-doc-sdg.js +5043 -1580
  6. package/public/js/qc-sdg.js +8111 -3685
  7. package/rollup.config.js +1 -0
  8. package/src/doc/components/Code.svelte +10 -15
  9. package/src/doc/components/Exemple.svelte +18 -15
  10. package/src/doc/components/Switch.svelte +7 -6
  11. package/src/doc/components/TopNav.svelte +6 -3
  12. package/src/doc/components/color-doc.svelte +2 -2
  13. package/src/doc/qc-doc-sdg.js +4 -1
  14. package/src/sdg/_components.js +10 -9
  15. package/src/sdg/components/Alert/Alert.svelte +69 -0
  16. package/src/sdg/components/Alert/AlertWC.svelte +24 -0
  17. package/src/sdg/components/ExternalLink/ExternalLink.svelte +96 -0
  18. package/src/sdg/components/ExternalLink/ExternalLinkWC.svelte +15 -0
  19. package/src/sdg/components/Icon/Icon.svelte +26 -0
  20. package/src/sdg/components/Icon/IconWC.svelte +20 -0
  21. package/src/sdg/components/IconButton/IconButton.svelte +30 -0
  22. package/src/sdg/components/IconButton/IconButtonWC.svelte +19 -0
  23. package/src/sdg/components/Notice/Notice.svelte +83 -0
  24. package/src/sdg/components/Notice/NoticeWC.svelte +25 -0
  25. package/src/sdg/components/PivFooter/PivFooter.svelte +51 -0
  26. package/src/sdg/components/PivFooter/PivFooterWC.svelte +52 -0
  27. package/src/sdg/components/PivFooter/_defaultCopyright.svelte +11 -0
  28. package/src/sdg/components/PivHeader/PivHeader.svelte +144 -0
  29. package/src/sdg/components/PivHeader/PivHeaderWC.svelte +68 -0
  30. package/src/sdg/components/PivHeader/_defaultLinks.svelte +24 -0
  31. package/src/sdg/components/SearchBar/SearchBar.svelte +67 -0
  32. package/src/sdg/components/SearchBar/SearchBarWC.svelte +17 -0
  33. package/src/sdg/components/SearchInput/SearchInput.svelte +17 -26
  34. package/src/sdg/components/SearchInput/SearchInputWC.svelte +16 -0
  35. package/src/sdg/components/{toTop.svelte → ToTop/ToTop.svelte} +31 -38
  36. package/src/sdg/components/ToTop/ToTopWC.svelte +16 -0
  37. package/src/sdg/components/utils.js +1 -1
  38. package/src/sdg/components/Button/IconButton.svelte +0 -29
  39. package/src/sdg/components/Icon.svelte +0 -39
  40. package/src/sdg/components/PivHeader/pivHeader.svelte +0 -158
  41. package/src/sdg/components/SearchBar/searchBar.svelte +0 -87
  42. package/src/sdg/components/alert.svelte +0 -88
  43. package/src/sdg/components/componentWrapper.js +0 -24
  44. package/src/sdg/components/externalLink.svelte +0 -92
  45. package/src/sdg/components/notice.svelte +0 -83
  46. package/src/sdg/components/pivFooter.svelte +0 -65
@@ -1,158 +0,0 @@
1
- <svelte:options customElement="{{
2
- tag: 'qc-piv-header'
3
- , props: {
4
- logoUrl : {attribute: 'logo-url'}
5
- , fullWidth : {attribute: 'full-width'}
6
- , logoSrc : {attribute: 'logo-src'}
7
- , logoAlt : {attribute: 'logo-alt'}
8
- , titleUrl : {attribute: 'title-url'}
9
- , titleText: {attribute: 'title-text'}
10
- , linksLabel: {attribute: 'links-label'}
11
- , altLanguageText: {attribute: 'alt-language-text'}
12
- , altLanguageUrl: {attribute: 'alt-language-url'}
13
- , joinUsText: {attribute: 'join-us-text'}
14
- , joinUsUrl: {attribute: 'join-us-url'}
15
- , goToContent: {attribute: 'go-to-content'}
16
- , goToContentAnchor : {attribute: 'go-to-content-anchor'}
17
- , goToContentText: {attribute: 'go-to-content-text'}
18
- , displaySearchText : {attribute: 'display-search-text'}
19
- , hideSearchText : {attribute: 'hide-search-text'}
20
- , enableSearch : {attribute: 'enable-search'}
21
- , showSearch : {attribute: 'show-search'}
22
- }
23
- }}" />
24
-
25
- <script>
26
- import { onMount } from "svelte";
27
- import { Utils } from "../utils"
28
-
29
- const
30
- lang = Utils.getPageLanguage()
31
-
32
- export let
33
- logoUrl= '/'
34
- , fullWidth = 'false'
35
- , logoSrc = Utils.imagesRelativePath + 'QUEBEC_blanc.svg'
36
- , logoAlt = lang === 'fr'
37
- ? 'Logo du gouvernement du Québec'
38
- : 'Logo of government of Québec'
39
- , titleUrl= '/'
40
- , titleText= ''
41
- , linksLabel= lang === 'fr'
42
- ? 'Navigation PIV'
43
- : 'PIV navigation'
44
- , altLanguageText= lang === 'fr'
45
- ? 'English'
46
- : 'Français'
47
- , altLanguageUrl= ''
48
- , joinUsText= lang === 'fr'
49
- ? 'Nous joindre'
50
- : 'Contact us'
51
- , joinUsUrl= ''
52
- , goToContent = 'true'
53
- , goToContentAnchor = '#main'
54
- , goToContentText= lang === 'fr'
55
- ? 'Passer au contenu'
56
- : 'Skip to content'
57
- , displaySearchText = lang === 'fr'
58
- ? 'Cliquer pour faire une recherche'
59
- : 'Click to search'
60
- , hideSearchText = lang === 'fr'
61
- ? 'Masquer la barre de recherche'
62
- : 'Hide search bar'
63
- , enableSearch = 'false'
64
- , showSearch = 'false'
65
-
66
- export function focusOnSearchInput() {
67
- if (displaySearchForm) {
68
- document.querySelector('[slot="search-zone"] input')?.focus();
69
- }
70
- }
71
-
72
- let
73
- containerClass = 'qc-container'
74
- , displaySearchForm = false
75
- ;
76
-
77
- onMount(() => {
78
- containerClass += fullWidth === 'true' ? '-fluid' : '';
79
- if (showSearch === 'true') {
80
- enableSearch = 'true'
81
- displaySearchForm = true;
82
- }
83
- })
84
-
85
-
86
- </script>
87
-
88
- <div role="banner"
89
- class="qc-piv-header qc-component"
90
- style="--logo-src:url({logoSrc})"
91
- >
92
- <div class="{containerClass}">
93
- {#if goToContent == 'true'}
94
- <div class="go-to-content">
95
- <a href="{goToContentAnchor}">
96
- {goToContentText}
97
- </a>
98
- </div>
99
- {/if}
100
- <div class="piv-top">
101
- <div class="signature-group">
102
- <a href="{logoUrl}"
103
- class="logo"
104
- rel="noreferrer">
105
- <div role="img"
106
- aria-label="{logoAlt}"
107
- ></div>
108
- </a>
109
-
110
- {#if titleText}
111
- <div class="title">
112
- <a href="{titleUrl}"
113
- class="title">
114
- {titleText}
115
- </a>
116
- </div>
117
-
118
- {/if}
119
- </div>
120
-
121
- <div class="right-section">
122
- {#if enableSearch == 'true'}
123
- <a class="qc-search"
124
- href="/"
125
- role="button"
126
- on:click|preventDefault = {() => displaySearchForm = !displaySearchForm}
127
- on:click ={focusOnSearchInput}>
128
- <span>{displaySearchForm ? hideSearchText : displaySearchText}</span>
129
- </a>
130
- {/if}
131
- <div class="links">
132
- <slot name="links">
133
- {#if joinUsUrl || altLanguageUrl}
134
- <nav aria-label="{linksLabel}">
135
- <ul>
136
- {#if altLanguageUrl}
137
- <li><a href="{altLanguageUrl}">{altLanguageText}</a></li>
138
- {/if}
139
- {#if joinUsUrl}
140
- <li><a href="{joinUsUrl}">{joinUsText}</a></li>
141
- {/if}
142
- </ul>
143
- </nav>
144
- {/if}
145
- </slot>
146
- </div>
147
- </div>
148
- </div>
149
- <div class="piv-bottom">
150
- {#if displaySearchForm}
151
- <div class="search-zone">
152
- <slot name="search-zone" />
153
- </div>
154
- {/if}
155
- </div>
156
- </div>
157
- </div>
158
- <link rel='stylesheet' href='{Utils.cssPath}'>
@@ -1,87 +0,0 @@
1
- <svelte:options customElement="{{
2
- tag: 'qc-search-bar',
3
- shadow: 'none',
4
- props: {
5
- value: {attribute: 'input-value', type:'String'},
6
- name: {attribute: 'input-name', type:'String'},
7
- pivBackground: {attribute: 'piv-background', type:'Boolean'},
8
- }
9
- }}" />
10
-
11
- <script>
12
- import {Utils} from "../utils";
13
- import SearchInput from "../SearchInput/SearchInput.svelte";
14
- import IconButton from "../Button/IconButton.svelte";
15
-
16
- const
17
- lang = Utils.getPageLanguage(),
18
- inputDefaultPlaceholder = lang === "fr"
19
- ? "Rechercher…"
20
- : "Search",
21
- submitDefaultAriaLabel = lang === "fr"
22
- ? "Lancer la recherche"
23
- : "Submit search"
24
- ;
25
- export let
26
- value = '',
27
- name = 'q',
28
- pivBackground = false
29
- ;
30
-
31
- let defaultsAttributes = {
32
- input: {
33
- "placeholder": inputDefaultPlaceholder,
34
- "aria-label": inputDefaultPlaceholder
35
- },
36
- submit: {
37
- "aria-label": submitDefaultAriaLabel
38
- }
39
- },
40
- inputProps = {},
41
- submitProps = {}
42
-
43
- $: [inputProps, submitProps] = computeFieldsAttributes($$restProps)
44
- $: inputProps = {
45
- "value": value,
46
- "name": name,
47
- ...inputProps
48
- }
49
-
50
- /**
51
- * @param {{[p: string]: T}} restProps
52
- */
53
- function computeFieldsAttributes(restProps) {
54
- return ["input","submit"]
55
- .map(control => {
56
- const prefix = `${control}-`;
57
- return {
58
- ...defaultsAttributes[control],
59
- ...Object.fromEntries(Object
60
- .entries(restProps)
61
- .map(([k,v]) => k.startsWith(prefix)
62
- ? [k.replace(prefix, ''),v]
63
- : null
64
- )
65
- .filter(x => x) // élimine les éléments null
66
- )
67
- }
68
- }
69
- )
70
- }
71
-
72
-
73
- </script>
74
- <div class="qc-search-bar"
75
- class:piv-background={pivBackground}
76
- >
77
- <SearchInput {...inputProps}/>
78
- {#if true}
79
- <IconButton
80
- type="submit"
81
- iconColor={pivBackground ? 'blue-piv' : 'background'}
82
- icon="loupe-piv-fine"
83
- iconSize="md"
84
- {...submitProps}
85
- />
86
- {/if}
87
- </div>
@@ -1,88 +0,0 @@
1
- <svelte:options customElement="{{
2
- tag:'qc-alert',
3
- props: {
4
- type : {attribute: 'type'},
5
- maskable : {attribute: 'maskable'},
6
- fullWidth : {attribute: 'full-width'},
7
- content: {attribute: 'content'},
8
- hide: {attribute: 'hide'},
9
- }
10
- }}"/>
11
-
12
- <script>
13
- import {Utils} from "./utils";
14
- import Icon from "./Icon.svelte";
15
- import IconButton from "./Button/IconButton.svelte";
16
-
17
- export let
18
- type = "general"
19
- , maskable = ""
20
- , content = ""
21
- , hide = "false"
22
- , fullWidth = 'false'
23
- ;
24
-
25
- let
26
- rootElement
27
- , hiddenFlag
28
- , typeClass = (type !== "")
29
- ? type
30
- : 'general'
31
- , closeLabel = Utils.getPageLanguage() === 'fr'
32
- ? "Fermer l’alerte"
33
- : "Close l’alerte"
34
- , warningLabel = Utils.getPageLanguage() === 'fr'
35
- ? "Information d'importance élevée"
36
- : "Information of high importance"
37
- , generalLabel = Utils.getPageLanguage() === 'fr'
38
- ? "Information importante"
39
- : "Important information"
40
- , label = type === 'general'
41
- ? generalLabel
42
- : warningLabel
43
- , containerClass
44
- ;
45
-
46
- $: hiddenFlag = hide === 'true'
47
- $: containerClass = "qc-container" + (fullWidth === 'true' ? '-fluid' : '');
48
-
49
- function hideAlert() {
50
- hide='true'
51
- rootElement.dispatchEvent(
52
- new CustomEvent('qc.alert.hide',{
53
- bubbles: true,
54
- composed: true
55
- }))
56
- }
57
-
58
- </script>
59
- {#if !hiddenFlag}
60
- <div bind:this={rootElement}
61
- class="qc-general-alert {typeClass}"
62
- role="alert">
63
- <div class={containerClass}>
64
- <div class="qc-general-alert-elements">
65
- <Icon type={type == 'warning' ? 'warning' : 'information'}
66
- color="{type == 'general' ? 'blue-piv' : 'yellow-dark'}"
67
- size="nm"
68
- label={label}
69
- />
70
- <div class="qc-alert-content">
71
- {@html content}
72
- <slot />
73
- </div>
74
- {#if maskable === "true"}
75
- <IconButton aria-label={closeLabel}
76
- on:click={hideAlert}
77
- size="nm"
78
- icon="clear-input"
79
- iconSize="sm"
80
- iconColor="text-primary"
81
- />
82
- {/if}
83
- </div>
84
- </div>
85
- </div>
86
- {/if}
87
- <link rel='stylesheet'
88
- href='{Utils.cssPath}'>
@@ -1,24 +0,0 @@
1
- /*! Wrapper needed to support kebab case svelte customElements attributes.
2
- Référence : https://github.com/sveltejs/svelte/issues/3852
3
- */
4
- export const customElements = {
5
- define: (tagName, CustomElement) => {
6
- class CustomElementWrapper extends CustomElement {
7
- static get observedAttributes() {
8
- return (super.observedAttributes || []).map((attr) =>
9
- attr.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase(),
10
- );
11
- }
12
-
13
- attributeChangedCallback(attrName, oldValue, newValue) {
14
- super.attributeChangedCallback(
15
- attrName.replace(/-([a-z])/g, (_, up) => up.toUpperCase()),
16
- oldValue,
17
- newValue === '' ? true : newValue, // [Tweaked] Value of omitted value attribute will be true
18
- );
19
- }
20
- }
21
-
22
- window.customElements.define(tagName, CustomElementWrapper); // <--- Call the actual customElements.define with our wrapper
23
- }
24
- };
@@ -1,92 +0,0 @@
1
- <svelte:options customElement="{{
2
- tag:'qc-external-link',
3
- shadow:'none',
4
- props: {
5
- externalIconAlt : {attribute: 'img-alt'}
6
- }
7
- }}"/>
8
-
9
- <script>
10
- import {Utils} from "./utils";
11
- import {onMount} from "svelte";
12
-
13
- export
14
- let externalIconAlt = Utils.getPageLanguage() == "fr"
15
- ? "Ce lien dirige vers un autre site."
16
- : "This link directs to another site."
17
- ;
18
- let imgElement;
19
-
20
- onMount(() => {
21
- imgElement.parentElement.querySelectorAll('a').forEach(link => {
22
-
23
- // Crée un TreeWalker pour parcourir uniquement les nœuds texte visibles
24
- const walker = document.createTreeWalker(
25
- link,
26
- NodeFilter.SHOW_ALL,
27
- {
28
- acceptNode: node => {
29
- if (node instanceof Element) {
30
- if (node.hasAttribute('hidden')) {
31
- return NodeFilter.FILTER_REJECT;
32
- }
33
- const style = window.getComputedStyle(node);
34
- // Si l'élément est masqué par CSS (display ou visibility), on l'ignore
35
- if (style.display === 'none'
36
- || style.visibility === 'hidden'
37
- || style.position === 'absolute') {
38
- return NodeFilter.FILTER_REJECT;
39
- }
40
- }
41
- if (!node instanceof Text) {
42
- return NodeFilter.FILTER_SKIP
43
- }
44
- // Ignore les nœuds vides
45
- if (!/\S/.test(node.textContent)) {
46
- return NodeFilter.FILTER_SKIP;
47
- }
48
- return NodeFilter.FILTER_ACCEPT;
49
- }
50
- }
51
- );
52
-
53
- let lastTextNode = null;
54
- while (walker.nextNode()) {
55
- lastTextNode = walker.currentNode;
56
- }
57
-
58
- // S'il n'y a pas de nœud texte visible, on ne fait rien
59
- if (!lastTextNode) return;
60
-
61
- // Séparer le contenu du dernier nœud texte en deux parties :
62
- // le préfixe (éventuel) et le dernier mot
63
- const text = lastTextNode.textContent;
64
- const regex = /^(.*\s)?(\S+)\s*$/m;
65
- const match = text.match(regex);
66
- if (!match) return;
67
- const prefix = match[1] || "";
68
- const lastWord = match[2];
69
-
70
- // Crée un span avec white-space: nowrap pour empêcher le saut de ligne de l'image de lien externe
71
- const span = document.createElement('span');
72
- span.classList.add('img-wrap')
73
- span.innerHTML = `${lastWord}`;
74
- span.appendChild(imgElement)
75
-
76
- // Met à jour le nœud texte : on garde le préfixe et on insère le span après
77
- if (prefix) {
78
- lastTextNode.textContent = prefix;
79
- lastTextNode.parentNode.insertBefore(span, lastTextNode.nextSibling);
80
- } else {
81
- lastTextNode.parentNode.replaceChild(span, lastTextNode);
82
- }
83
- });
84
- });
85
- </script>
86
- <span bind:this={imgElement}
87
- role="img"
88
- class="qc-ext-link-img"
89
- aria-label={externalIconAlt}></span>
90
-
91
-
92
-
@@ -1,83 +0,0 @@
1
- <svelte:options customElement="qc-notice" />
2
-
3
- <script>
4
- import { Utils } from "./utils"
5
- import Icon from "./Icon.svelte";
6
-
7
- const
8
- isFr = Utils.getPageLanguage() == 'fr'
9
- , defaultHeader = 'h2'
10
- , defaultType = 'information'
11
- , typesDescriptions = {
12
- 'advice': isFr ? "Avis conseil" : "Advisory notice",
13
- 'note': isFr ? "Avis explicatif" : "Explanatory notice"
14
- , 'information': isFr ? "Avis général" : "General notice"
15
- , 'warning': isFr ? "Avis d’avertissement" : "Warning notice"
16
- , 'success': isFr ? "Avis de réussite" : "Success notice"
17
- , 'error': isFr ? "Avis d’erreur" : "Error notice"
18
- }
19
- , types = Object.keys(typesDescriptions);
20
-
21
- let noticeElement;
22
- export let
23
- title = ""
24
- , type = defaultType
25
- , content = ""
26
- , header = defaultHeader
27
- , icon;
28
-
29
- $: header = header.match(/h[1-6]/)
30
- ? header
31
- : defaultHeader;
32
-
33
- $: type = types.includes(type)
34
- ? type
35
- : defaultType;
36
-
37
- $: role = type === "success"
38
- ? "status"
39
- : (type === "error" ? "alert" : null);
40
-
41
- $: if (role) {
42
- if (noticeElement) {
43
- const tempNodes = Array.from(noticeElement.childNodes);
44
- // console.log("temp: ",tempNodes);
45
- noticeElement.innerHTML = "";
46
- // Réinsère le contenu pour qu'il soit détecté par le lecteur d'écran.
47
- tempNodes.forEach(node => noticeElement.appendChild(node)); }
48
- }
49
-
50
- $: shouldUseIcon = type === "advice" || type === "note";
51
- // Si le type est "advice" ou "note", on force "neutral" (le gris), sinon on garde le type normal
52
- $: computedType = shouldUseIcon ? "neutral" : type;
53
- $: iconType = shouldUseIcon ? (icon ?? "note") : type;
54
- $: iconLabel = typesDescriptions[type] ?? typesDescriptions['information'];
55
-
56
-
57
- </script>
58
-
59
- <!-- TODO Confirmer tabindex. On pense que c'est important de recevoir le focus (notamment dans les formulaires) en fait pour nous c'est très important, sinon en mode formulaire au lecteur écran (nav avec TAB, ce n'est jamais lu). -->
60
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
61
- <div class="qc-component qc-notice qc-{computedType}"
62
- tabindex="0">
63
- <div class="icon-container">
64
- <div class="qc-icon">
65
- <Icon type="{iconType}"
66
- label={iconLabel}
67
- size="nm"
68
- />
69
- </div>
70
- </div>
71
- <div class="content-container">
72
- <div class="content" {role} bind:this={noticeElement}>
73
- {#if title}
74
- <svelte:element this={header}>
75
- {@html title}
76
- </svelte:element>
77
- {/if}
78
- {@html content}
79
- <slot />
80
- </div>
81
- </div>
82
- </div>
83
- <link rel='stylesheet' href='{Utils.cssPath}'>
@@ -1,65 +0,0 @@
1
- <svelte:options customElement="{{
2
- tag: 'qc-piv-footer'
3
- , props: {
4
- logoUrl : {attribute: 'logo-url'}
5
- , logoSrc : {attribute: 'logo-src'}
6
- , logoSrcDarkTheme: {attribute: 'logo-src-dark-theme'}
7
- , logoAlt : {attribute: 'logo-alt'}
8
- , logoWidth: {attribute: 'logo-width'}
9
- , logoHeight: {attribute: 'logo-height'}
10
- , copyrightText : {attribute: 'copyright-text'}
11
- , copyrightUrl : {attribute: 'copyright-url'}
12
-
13
- }}
14
- }}" />
15
-
16
- <script>
17
-
18
- import { Utils } from "./utils"
19
- import { get_current_component } from "svelte/internal"
20
-
21
- const
22
- lang = Utils.getPageLanguage()
23
- ;
24
-
25
- export let
26
- logoUrl = '/'
27
- , logoSrc = Utils.imagesRelativePath + '/QUEBEC_couleur.svg'
28
- , logoSrcDarkTheme = Utils.imagesRelativePath + '/QUEBEC_blanc.svg'
29
- , logoAlt = lang === 'fr'
30
- ? 'Logo du gouvernement du Québec'
31
- : 'Logo of the Quebec government'
32
- , copyrightText = '© Gouvernement du Québec, ' + (new Date()).getFullYear()
33
- , logoWidth = 139
34
- , logoHeight = 50
35
- , copyrightUrl = lang === 'fr'
36
- ? 'https://www.quebec.ca/droit-auteur'
37
- : 'https://www.quebec.ca/en/copyright'
38
- ;
39
- </script>
40
- <div class="qc-piv-footer qc-container-fluid">
41
- <slot/>
42
- <a href="{logoUrl}"
43
- class="logo"
44
- style:--logo-width={logoWidth}
45
- style:--logo-height={logoHeight}
46
- >
47
- {#each [
48
- ['light', logoSrc],
49
- ['dark', logoSrcDarkTheme]]
50
- as [theme, src]}
51
- <img {src}
52
- alt="{logoAlt}"
53
- class="qc-{theme}-theme-show"/>
54
- {/each}
55
- </a>
56
- <span class="copyright">
57
- <slot name="copyright">
58
- <a href="{copyrightUrl}">
59
- {copyrightText}
60
- </a>
61
- </slot>
62
- </span>
63
- </div>
64
- <link rel='stylesheet' href='{Utils.cssPath}'>
65
-