qc-trousse-sdg 1.4.8 → 1.4.9
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.
- package/README.md +4 -139
- package/dist/css/qc-sdg-no-grid.min.css +1 -1
- package/dist/css/qc-sdg.min.css +1 -1
- package/dist/js/qc-sdg.min.js +1 -1
- package/package.json +1 -1
- package/public/css/qc-doc-sdg.css +11 -33
- package/public/css/qc-sdg-no-grid.css +31 -23
- package/public/css/qc-sdg.css +31 -23
- package/public/index.html +1 -1
- package/public/js/qc-doc-sdg.js +20 -12
- package/public/js/qc-sdg.js +110 -38
- package/src/doc/scss/qc-doc-sdg.scss +9 -37
- package/src/sdg/bases/links/_links.html +1 -1
- package/src/sdg/bases/links/_links.scss +19 -18
- package/src/sdg/components/Button/_button.scss +14 -6
- package/src/sdg/components/DropdownList/DropdownList.svelte +8 -0
- package/src/sdg/components/ExternalLink/ExternalLink.svelte +72 -13
- package/src/sdg/components/ExternalLink/ExternalLinkWC.svelte +6 -10
- package/tests/dropdown-list-baseline.spec.ts +17 -0
package/public/js/qc-sdg.js
CHANGED
|
@@ -11437,7 +11437,7 @@
|
|
|
11437
11437
|
|
|
11438
11438
|
ExternalLink[FILENAME] = 'src/sdg/components/ExternalLink/ExternalLink.svelte';
|
|
11439
11439
|
|
|
11440
|
-
var root$d = add_locations(from_html(`<div hidden=""><!></div>`), ExternalLink[FILENAME], [[
|
|
11440
|
+
var root$d = add_locations(from_html(`<div hidden=""><!></div>`), ExternalLink[FILENAME], [[108, 0]]);
|
|
11441
11441
|
|
|
11442
11442
|
function ExternalLink($$anchor, $$props) {
|
|
11443
11443
|
check_target(new.target);
|
|
@@ -11451,22 +11451,80 @@
|
|
|
11451
11451
|
nestedExternalLinks = prop($$props, 'nestedExternalLinks', 7, false);
|
|
11452
11452
|
|
|
11453
11453
|
let imgElement = tag(state(void 0), 'imgElement');
|
|
11454
|
-
let processedLinks = new Set();
|
|
11455
11454
|
|
|
11456
|
-
function
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11460
|
-
|
|
11455
|
+
function createVisibleNodesTreeWalker(link) {
|
|
11456
|
+
return document.createTreeWalker(link, NodeFilter.SHOW_ALL, {
|
|
11457
|
+
acceptNode: (node) => {
|
|
11458
|
+
if (node instanceof Element) {
|
|
11459
|
+
if (node.hasAttribute('hidden')) {
|
|
11460
|
+
return NodeFilter.FILTER_REJECT;
|
|
11461
|
+
}
|
|
11462
|
+
|
|
11463
|
+
const style = window.getComputedStyle(node);
|
|
11461
11464
|
|
|
11462
|
-
|
|
11465
|
+
// Si l'élément est masqué par CSS (display ou visibility), on l'ignore
|
|
11466
|
+
if (strict_equals(style.display, 'none') || strict_equals(style.visibility, 'hidden') || strict_equals(style.position, 'absolute')) {
|
|
11467
|
+
return NodeFilter.FILTER_REJECT;
|
|
11468
|
+
}
|
|
11469
|
+
}
|
|
11470
|
+
|
|
11471
|
+
if (!node instanceof Text) {
|
|
11472
|
+
return NodeFilter.FILTER_SKIP;
|
|
11473
|
+
}
|
|
11463
11474
|
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11475
|
+
// Ignore les nœuds vides
|
|
11476
|
+
if (!(/\S/).test(node.textContent)) {
|
|
11477
|
+
return NodeFilter.FILTER_SKIP;
|
|
11478
|
+
}
|
|
11479
|
+
|
|
11480
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
11481
|
+
}
|
|
11467
11482
|
});
|
|
11468
11483
|
}
|
|
11469
11484
|
|
|
11485
|
+
function addExternalLinkIcon(link) {
|
|
11486
|
+
// Crée un TreeWalker pour parcourir uniquement les nœuds texte visibles
|
|
11487
|
+
const walker = createVisibleNodesTreeWalker(link);
|
|
11488
|
+
|
|
11489
|
+
let lastTextNode = null;
|
|
11490
|
+
|
|
11491
|
+
while (walker.nextNode()) {
|
|
11492
|
+
lastTextNode = walker.currentNode;
|
|
11493
|
+
}
|
|
11494
|
+
|
|
11495
|
+
// S'il n'y a pas de nœud texte visible, on ne fait rien
|
|
11496
|
+
if (!lastTextNode) {
|
|
11497
|
+
return;
|
|
11498
|
+
}
|
|
11499
|
+
|
|
11500
|
+
// Séparer le contenu du dernier nœud texte en deux parties :
|
|
11501
|
+
// le préfixe (éventuel) et le dernier mot
|
|
11502
|
+
const text = lastTextNode.textContent;
|
|
11503
|
+
|
|
11504
|
+
const match = text.match(/^([\s\S]*\s)?(\S+)\s*$/m);
|
|
11505
|
+
|
|
11506
|
+
if (!match) {
|
|
11507
|
+
return;
|
|
11508
|
+
}
|
|
11509
|
+
|
|
11510
|
+
const prefix = match[1] || "";
|
|
11511
|
+
const lastWord = match[2].replace(/([\/\-\u2013\u2014])/g, "$1<wbr>");
|
|
11512
|
+
|
|
11513
|
+
// Crée un span avec white-space: nowrap pour empêcher le saut de ligne de l'image de lien externe
|
|
11514
|
+
const span = document.createElement('span');
|
|
11515
|
+
|
|
11516
|
+
span.classList.add('img-wrap');
|
|
11517
|
+
span.innerHTML = `${lastWord}${get(imgElement).outerHTML}`;
|
|
11518
|
+
|
|
11519
|
+
// Met à jour le nœud texte : on garde le préfixe et on insère le span après
|
|
11520
|
+
if (prefix) {
|
|
11521
|
+
lastTextNode.textContent = prefix;
|
|
11522
|
+
lastTextNode.parentNode.insertBefore(span, lastTextNode.nextSibling);
|
|
11523
|
+
} else {
|
|
11524
|
+
lastTextNode.parentNode.replaceChild(span, lastTextNode);
|
|
11525
|
+
}
|
|
11526
|
+
}
|
|
11527
|
+
|
|
11470
11528
|
user_effect(() => {
|
|
11471
11529
|
if (nestedExternalLinks() || links().length <= 0 || !get(imgElement)) {
|
|
11472
11530
|
return;
|
|
@@ -11475,7 +11533,11 @@
|
|
|
11475
11533
|
isUpdating(true);
|
|
11476
11534
|
|
|
11477
11535
|
tick().then(() => {
|
|
11478
|
-
|
|
11536
|
+
links().forEach((link) => {
|
|
11537
|
+
if (!link.querySelector('.qc-ext-link-img')) {
|
|
11538
|
+
addExternalLinkIcon(link);
|
|
11539
|
+
}
|
|
11540
|
+
});
|
|
11479
11541
|
|
|
11480
11542
|
return tick();
|
|
11481
11543
|
}).then(() => {
|
|
@@ -11528,10 +11590,10 @@
|
|
|
11528
11590
|
};
|
|
11529
11591
|
|
|
11530
11592
|
var div = root$d();
|
|
11531
|
-
var
|
|
11593
|
+
var node_1 = child(div);
|
|
11532
11594
|
|
|
11533
11595
|
add_svelte_meta(
|
|
11534
|
-
() => Icon(
|
|
11596
|
+
() => Icon(node_1, {
|
|
11535
11597
|
type: 'external-link',
|
|
11536
11598
|
|
|
11537
11599
|
get alt() {
|
|
@@ -11539,6 +11601,7 @@
|
|
|
11539
11601
|
},
|
|
11540
11602
|
|
|
11541
11603
|
class: 'qc-ext-link-img',
|
|
11604
|
+
color: 'link-text',
|
|
11542
11605
|
|
|
11543
11606
|
get rootElement() {
|
|
11544
11607
|
return get(imgElement);
|
|
@@ -11550,7 +11613,7 @@
|
|
|
11550
11613
|
}),
|
|
11551
11614
|
'component',
|
|
11552
11615
|
ExternalLink,
|
|
11553
|
-
|
|
11616
|
+
109,
|
|
11554
11617
|
4,
|
|
11555
11618
|
{ componentTag: 'Icon' }
|
|
11556
11619
|
);
|
|
@@ -11581,11 +11644,11 @@
|
|
|
11581
11644
|
push($$props, true);
|
|
11582
11645
|
|
|
11583
11646
|
const props = rest_props($$props, ['$$slots', '$$events', '$$legacy', '$$host']);
|
|
11584
|
-
|
|
11585
|
-
let links = tag(state(proxy([])), 'links');
|
|
11586
|
-
const observer = Utils.createMutationObserver($$props.$$host, refreshLinks);
|
|
11647
|
+
let links = tag(state(proxy(queryLinks())), 'links');
|
|
11587
11648
|
let isUpdating = tag(state(false), 'isUpdating');
|
|
11588
11649
|
let pendingUpdate = false;
|
|
11650
|
+
const nestedExternalLinks = $$props.$$host.querySelector('qc-external-link');
|
|
11651
|
+
const observer = Utils.createMutationObserver($$props.$$host, refreshLinks);
|
|
11589
11652
|
|
|
11590
11653
|
function queryLinks() {
|
|
11591
11654
|
return Array.from($$props.$$host.querySelectorAll('a'));
|
|
@@ -11612,29 +11675,30 @@
|
|
|
11612
11675
|
|
|
11613
11676
|
onMount(() => {
|
|
11614
11677
|
$$props.$$host.classList.add('qc-external-link');
|
|
11615
|
-
set(links, queryLinks(), true);
|
|
11616
11678
|
observer?.observe($$props.$$host, { childList: true, characterData: true, subtree: true });
|
|
11617
11679
|
});
|
|
11618
11680
|
|
|
11619
|
-
onDestroy(() =>
|
|
11620
|
-
observer?.disconnect();
|
|
11621
|
-
});
|
|
11681
|
+
onDestroy(() => observer?.disconnect());
|
|
11622
11682
|
|
|
11623
11683
|
var $$exports = { ...legacy_api() };
|
|
11624
11684
|
|
|
11625
11685
|
add_svelte_meta(
|
|
11626
11686
|
() => ExternalLink($$anchor, spread_props(
|
|
11627
11687
|
{
|
|
11628
|
-
get links() {
|
|
11629
|
-
return get(links);
|
|
11630
|
-
},
|
|
11631
|
-
|
|
11632
11688
|
get nestedExternalLinks() {
|
|
11633
11689
|
return nestedExternalLinks;
|
|
11634
11690
|
}
|
|
11635
11691
|
},
|
|
11636
11692
|
() => props,
|
|
11637
11693
|
{
|
|
11694
|
+
get links() {
|
|
11695
|
+
return get(links);
|
|
11696
|
+
},
|
|
11697
|
+
|
|
11698
|
+
set links($$value) {
|
|
11699
|
+
set(links, $$value, true);
|
|
11700
|
+
},
|
|
11701
|
+
|
|
11638
11702
|
get isUpdating() {
|
|
11639
11703
|
return get(isUpdating);
|
|
11640
11704
|
},
|
|
@@ -11646,7 +11710,7 @@
|
|
|
11646
11710
|
)),
|
|
11647
11711
|
'component',
|
|
11648
11712
|
ExternalLinkWC,
|
|
11649
|
-
|
|
11713
|
+
54,
|
|
11650
11714
|
0,
|
|
11651
11715
|
{ componentTag: 'ExternalLink' }
|
|
11652
11716
|
);
|
|
@@ -16347,9 +16411,9 @@
|
|
|
16347
16411
|
|
|
16348
16412
|
DropdownList[FILENAME] = 'src/sdg/components/DropdownList/DropdownList.svelte';
|
|
16349
16413
|
|
|
16350
|
-
var root_2 = add_locations(from_html(`<div class="qc-dropdown-list-search"><!></div>`), DropdownList[FILENAME], [[
|
|
16351
|
-
var root_3 = add_locations(from_html(`<span> </span>`), DropdownList[FILENAME], [[
|
|
16352
|
-
var root$1 = add_locations(from_html(`<div><div><!> <div tabindex="-1"><!> <div class="qc-dropdown-list-expanded" tabindex="-1" role="listbox"><!> <!> <div role="status" class="qc-sr-only"><!></div></div></div></div> <!></div>`), DropdownList[FILENAME], [[
|
|
16414
|
+
var root_2 = add_locations(from_html(`<div class="qc-dropdown-list-search"><!></div>`), DropdownList[FILENAME], [[394, 20]]);
|
|
16415
|
+
var root_3 = add_locations(from_html(`<span> </span>`), DropdownList[FILENAME], [[435, 24]]);
|
|
16416
|
+
var root$1 = add_locations(from_html(`<div><div><!> <div tabindex="-1"><!> <div class="qc-dropdown-list-expanded" tabindex="-1" role="listbox"><!> <!> <div role="status" class="qc-sr-only"><!></div></div></div></div> <!></div>`), DropdownList[FILENAME], [[324, 0, [[329, 4, [[348, 8, [[377, 12, [[433, 16]]]]]]]]]]);
|
|
16353
16417
|
|
|
16354
16418
|
function DropdownList($$anchor, $$props) {
|
|
16355
16419
|
check_target(new.target);
|
|
@@ -16626,6 +16690,14 @@
|
|
|
16626
16690
|
}
|
|
16627
16691
|
});
|
|
16628
16692
|
|
|
16693
|
+
user_effect(() => {
|
|
16694
|
+
if (value()) {
|
|
16695
|
+
items().forEach((item) => {
|
|
16696
|
+
item.checked = value().includes(item.value);
|
|
16697
|
+
});
|
|
16698
|
+
}
|
|
16699
|
+
});
|
|
16700
|
+
|
|
16629
16701
|
user_effect(() => {
|
|
16630
16702
|
items().forEach((item) => {
|
|
16631
16703
|
if (!item.id) {
|
|
@@ -16898,7 +16970,7 @@
|
|
|
16898
16970
|
}),
|
|
16899
16971
|
'component',
|
|
16900
16972
|
DropdownList,
|
|
16901
|
-
|
|
16973
|
+
335,
|
|
16902
16974
|
12,
|
|
16903
16975
|
{ componentTag: 'Label' }
|
|
16904
16976
|
);
|
|
@@ -16910,7 +16982,7 @@
|
|
|
16910
16982
|
}),
|
|
16911
16983
|
'if',
|
|
16912
16984
|
DropdownList,
|
|
16913
|
-
|
|
16985
|
+
334,
|
|
16914
16986
|
8
|
|
16915
16987
|
);
|
|
16916
16988
|
}
|
|
@@ -16982,7 +17054,7 @@
|
|
|
16982
17054
|
}),
|
|
16983
17055
|
'component',
|
|
16984
17056
|
DropdownList,
|
|
16985
|
-
|
|
17057
|
+
357,
|
|
16986
17058
|
12,
|
|
16987
17059
|
{ componentTag: 'DropdownListButton' }
|
|
16988
17060
|
);
|
|
@@ -17037,7 +17109,7 @@
|
|
|
17037
17109
|
),
|
|
17038
17110
|
'component',
|
|
17039
17111
|
DropdownList,
|
|
17040
|
-
|
|
17112
|
+
395,
|
|
17041
17113
|
24,
|
|
17042
17114
|
{ componentTag: 'SearchInput' }
|
|
17043
17115
|
);
|
|
@@ -17053,7 +17125,7 @@
|
|
|
17053
17125
|
}),
|
|
17054
17126
|
'if',
|
|
17055
17127
|
DropdownList,
|
|
17056
|
-
|
|
17128
|
+
393,
|
|
17057
17129
|
16
|
|
17058
17130
|
);
|
|
17059
17131
|
}
|
|
@@ -17113,7 +17185,7 @@
|
|
|
17113
17185
|
),
|
|
17114
17186
|
'component',
|
|
17115
17187
|
DropdownList,
|
|
17116
|
-
|
|
17188
|
+
413,
|
|
17117
17189
|
16,
|
|
17118
17190
|
{ componentTag: 'DropdownListItems' }
|
|
17119
17191
|
);
|
|
@@ -17133,7 +17205,7 @@
|
|
|
17133
17205
|
}),
|
|
17134
17206
|
'key',
|
|
17135
17207
|
DropdownList,
|
|
17136
|
-
|
|
17208
|
+
434,
|
|
17137
17209
|
20
|
|
17138
17210
|
);
|
|
17139
17211
|
|
|
@@ -17181,7 +17253,7 @@
|
|
|
17181
17253
|
}),
|
|
17182
17254
|
'component',
|
|
17183
17255
|
DropdownList,
|
|
17184
|
-
|
|
17256
|
+
443,
|
|
17185
17257
|
4,
|
|
17186
17258
|
{ componentTag: 'FormError' }
|
|
17187
17259
|
);
|
|
@@ -94,53 +94,25 @@ h1,h2,h3,h4,h5,h6 {
|
|
|
94
94
|
|
|
95
95
|
a {
|
|
96
96
|
|
|
97
|
-
&.pseudo-visited {
|
|
98
|
-
color: token-value(color,link,visited);
|
|
99
|
-
& > .qc-ext-link-img {
|
|
100
|
-
background-color: token-value(color, link, visited);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
97
|
&.pseudo-hover {
|
|
104
98
|
@include hover-link();
|
|
105
|
-
|
|
106
|
-
background-color: token-value(color, link, hover);
|
|
107
|
-
}
|
|
99
|
+
--qc-color-link-visited: var(--qc-color-link-hover);
|
|
108
100
|
}
|
|
109
101
|
&.pseudo-active {
|
|
110
102
|
@include active-link();
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
103
|
+
--qc-color-link-visited: var(--qc-color-link-active);
|
|
104
|
+
--qc-color-link-focus: var(--qc-color-link-active);
|
|
105
|
+
--qc-color-link-hover: var(--qc-color-link-active );
|
|
114
106
|
}
|
|
115
107
|
&.pseudo-focus {
|
|
116
108
|
@include focus-link();
|
|
117
|
-
|
|
118
|
-
background-color: token-value(color, link, text);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
&.not-visited:visited:not(:hover) {
|
|
122
|
-
color: token-value(color,link,text);
|
|
123
|
-
& > .qc-ext-link-text {
|
|
124
|
-
color: token-value(color,link,text);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
div.qc-ext-link-img {
|
|
130
|
-
a.pseudo-visited & {
|
|
131
|
-
background: token-value(color link visited)!important;
|
|
109
|
+
--qc-color-link-visited: var(--qc-color-link-focus);
|
|
132
110
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
a.pseudo-hover & {
|
|
137
|
-
background: token-value(color link hover)!important;
|
|
138
|
-
}
|
|
139
|
-
a.pseudo-active & {
|
|
140
|
-
background: token-value(color link active)!important;
|
|
111
|
+
&.pseudo-visited {
|
|
112
|
+
--qc-color-link-text: var(--qc-color-link-visited);
|
|
141
113
|
}
|
|
142
|
-
|
|
143
|
-
|
|
114
|
+
&.not-visited {
|
|
115
|
+
--qc-color-link-visited: var(--qc-color-link-text);
|
|
144
116
|
}
|
|
145
117
|
}
|
|
146
118
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<h2 id="liens">Liens</h2>
|
|
2
2
|
<qc-doc-exemple caption="Exemple de différents liens hypertexte selon leurs états.">
|
|
3
3
|
<dl>
|
|
4
|
-
<dt>Lien
|
|
4
|
+
<dt>Lien non visité</dt>
|
|
5
5
|
<dd><a href="#" class="not-visited">Lien interne</a></dd>
|
|
6
6
|
<dd>
|
|
7
7
|
<qc-external-link><a href="#" class="not-visited">Lien externe</a></qc-external-link>
|
|
@@ -4,10 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
a {
|
|
6
6
|
color: token-value(color, link, text);
|
|
7
|
-
&:has(.qc-ext-link-text) {
|
|
8
|
-
white-space: nowrap;
|
|
9
|
-
text-decoration: none;
|
|
10
|
-
}
|
|
11
7
|
&:visited {
|
|
12
8
|
color: token-value(color, link, visited);
|
|
13
9
|
}
|
|
@@ -23,35 +19,40 @@ a {
|
|
|
23
19
|
.img-wrap {
|
|
24
20
|
white-space: nowrap;
|
|
25
21
|
}
|
|
26
|
-
}
|
|
27
22
|
|
|
28
|
-
.qc-external-link {
|
|
29
|
-
.qc-ext-link-text {
|
|
30
|
-
white-space: normal;
|
|
31
|
-
text-decoration: underline;
|
|
32
|
-
}
|
|
33
23
|
}
|
|
24
|
+
div.qc-ext-link-img {
|
|
34
25
|
|
|
35
|
-
.qc-ext-link-img {
|
|
36
26
|
@extend .icon-external-link;
|
|
37
27
|
$ratio : math.div(11,16) * 1em;
|
|
38
28
|
height: $ratio;
|
|
39
29
|
width: $ratio;
|
|
30
|
+
display: inline-block;
|
|
40
31
|
background: token-value(color link text);
|
|
41
32
|
mask-size: $ratio;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
a:visited & {
|
|
33
|
+
margin-left: 4px;
|
|
34
|
+
a:visited & {
|
|
46
35
|
background: token-value(color link visited);
|
|
47
36
|
}
|
|
48
|
-
a:focus
|
|
37
|
+
a:focus & {
|
|
49
38
|
background: token-value(color link hover);
|
|
50
39
|
}
|
|
51
|
-
a:hover
|
|
40
|
+
a:hover & {
|
|
52
41
|
background: token-value(color link hover);
|
|
53
42
|
}
|
|
54
|
-
a:active
|
|
43
|
+
a:active & {
|
|
55
44
|
background: token-value(color link active);
|
|
56
45
|
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
.img-wrap + & {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.qc-external-link .qc-button {
|
|
54
|
+
gap: 0;
|
|
55
|
+
> .img-wrap::before {
|
|
56
|
+
content: "\a0";
|
|
57
|
+
}
|
|
57
58
|
}
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
.qc-button {
|
|
11
|
+
--qc-color-link-focus: var(--qc-color-link-text);
|
|
12
|
+
--qc-color-link-hover: var(--qc-color-link-text);
|
|
13
|
+
--qc-color-link-visited: var(--qc-color-link-text);
|
|
11
14
|
font-family: token-value(font family, content);
|
|
12
15
|
font-size: token-value(font size, md);
|
|
13
16
|
font-weight: token-value(font weight, bold);
|
|
@@ -15,7 +18,7 @@
|
|
|
15
18
|
display: inline-flex;
|
|
16
19
|
align-items: center;
|
|
17
20
|
justify-content: center;
|
|
18
|
-
gap:
|
|
21
|
+
gap: token-value(spacer, xs);
|
|
19
22
|
box-sizing: border-box;
|
|
20
23
|
min-width: rem(112);
|
|
21
24
|
max-width: rem(360);
|
|
@@ -47,6 +50,7 @@
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
&.qc-primary {
|
|
53
|
+
--qc-color-link-text: #{token-value(color white)};
|
|
50
54
|
color: token-value(color white);
|
|
51
55
|
background-color: token-value(color blue piv);
|
|
52
56
|
border-color: token-value(color blue piv);
|
|
@@ -83,6 +87,7 @@
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
&.qc-secondary {
|
|
90
|
+
--qc-color-link-text: #{token-value(color blue, piv)};
|
|
86
91
|
color: token-value(color blue, piv);
|
|
87
92
|
background-color: token-value(color white);
|
|
88
93
|
border-color: token-value(color blue, piv);
|
|
@@ -91,7 +96,8 @@
|
|
|
91
96
|
&:focus:not(:disabled),
|
|
92
97
|
&:active:not(:disabled),
|
|
93
98
|
&.qc-hover, &.qc-focus, &.qc-active {
|
|
94
|
-
|
|
99
|
+
|
|
100
|
+
background-color: rgba(var(--qc-color-blue-piv-rgb), 0.16);
|
|
95
101
|
}
|
|
96
102
|
|
|
97
103
|
&:focus:not(:disabled),
|
|
@@ -102,7 +108,7 @@
|
|
|
102
108
|
|
|
103
109
|
&:active:not(:disabled),
|
|
104
110
|
&.qc-active {
|
|
105
|
-
background-color: rgba(
|
|
111
|
+
background-color: rgba(var(--qc-color-blue-piv-rgb), 0.08);
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
&:disabled,
|
|
@@ -114,26 +120,28 @@
|
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
&.qc-tertiary {
|
|
123
|
+
--qc-color-link-text: #{token-value(color blue, piv)};
|
|
117
124
|
color: token-value(color blue, piv);
|
|
118
125
|
background-color: token-value(color white);
|
|
119
126
|
border-color: token-value(color white);
|
|
120
127
|
|
|
121
128
|
&:hover:not(:disabled),
|
|
122
129
|
&.qc-hover{
|
|
123
|
-
|
|
130
|
+
|
|
131
|
+
background-color: rgba(var(--qc-color-grey-light-rgb), 0.24);
|
|
124
132
|
text-decoration: underline;
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
&:focus:not(:disabled),
|
|
128
136
|
&.qc-focus {
|
|
129
|
-
background-color: rgba(
|
|
137
|
+
background-color: rgba(var(--qc-color-grey-light-rgb), 0.24);
|
|
130
138
|
border-color: token-value(color blue, dark);
|
|
131
139
|
box-shadow: 0 0 0 2px token-value(color blue, light);
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
&:active:not(:disabled),
|
|
135
143
|
&.qc-active {
|
|
136
|
-
background-color: rgba(
|
|
144
|
+
background-color: rgba(var(--qc-color-grey-light-rgb), 0.16);
|
|
137
145
|
}
|
|
138
146
|
|
|
139
147
|
&:disabled,
|
|
@@ -13,20 +13,76 @@ let {
|
|
|
13
13
|
} = $props();
|
|
14
14
|
|
|
15
15
|
let imgElement = $state();
|
|
16
|
-
let processedLinks = new Set();
|
|
17
16
|
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
function createVisibleNodesTreeWalker(link) {
|
|
18
|
+
return document.createTreeWalker(
|
|
19
|
+
link,
|
|
20
|
+
NodeFilter.SHOW_ALL,
|
|
21
|
+
{
|
|
22
|
+
acceptNode: node => {
|
|
23
|
+
if (node instanceof Element) {
|
|
24
|
+
if (node.hasAttribute('hidden')) {
|
|
25
|
+
return NodeFilter.FILTER_REJECT;
|
|
26
|
+
}
|
|
27
|
+
const style = window.getComputedStyle(node);
|
|
28
|
+
// Si l'élément est masqué par CSS (display ou visibility), on l'ignore
|
|
29
|
+
if (style.display === 'none'
|
|
30
|
+
|| style.visibility === 'hidden'
|
|
31
|
+
|| style.position === 'absolute') {
|
|
32
|
+
return NodeFilter.FILTER_REJECT;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!node instanceof Text) {
|
|
36
|
+
return NodeFilter.FILTER_SKIP;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Ignore les nœuds vides
|
|
40
|
+
if (!/\S/.test(node.textContent)) {
|
|
41
|
+
return NodeFilter.FILTER_SKIP;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
45
|
+
}
|
|
22
46
|
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
23
49
|
|
|
24
|
-
|
|
25
|
-
|
|
50
|
+
function addExternalLinkIcon(link) {
|
|
51
|
+
// Crée un TreeWalker pour parcourir uniquement les nœuds texte visibles
|
|
52
|
+
const walker = createVisibleNodesTreeWalker(link);
|
|
26
53
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
54
|
+
let lastTextNode = null;
|
|
55
|
+
while (walker.nextNode()) {
|
|
56
|
+
lastTextNode = walker.currentNode;
|
|
57
|
+
}
|
|
58
|
+
// S'il n'y a pas de nœud texte visible, on ne fait rien
|
|
59
|
+
if (!lastTextNode) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Séparer le contenu du dernier nœud texte en deux parties :
|
|
64
|
+
// le préfixe (éventuel) et le dernier mot
|
|
65
|
+
const text = lastTextNode.textContent;
|
|
66
|
+
const match = text.match(/^([\s\S]*\s)?(\S+)\s*$/m);
|
|
67
|
+
if (!match) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const prefix = match[1] || "";
|
|
72
|
+
const lastWord = match[2].replace(/([\/\-\u2013\u2014])/g, "$1<wbr>");
|
|
73
|
+
|
|
74
|
+
// Crée un span avec white-space: nowrap pour empêcher le saut de ligne de l'image de lien externe
|
|
75
|
+
const span = document.createElement('span');
|
|
76
|
+
span.classList.add('img-wrap')
|
|
77
|
+
span.innerHTML = `${lastWord}${imgElement.outerHTML}`;
|
|
78
|
+
|
|
79
|
+
// Met à jour le nœud texte : on garde le préfixe et on insère le span après
|
|
80
|
+
if (prefix) {
|
|
81
|
+
lastTextNode.textContent = prefix;
|
|
82
|
+
lastTextNode.parentNode.insertBefore(span, lastTextNode.nextSibling);
|
|
83
|
+
} else {
|
|
84
|
+
lastTextNode.parentNode.replaceChild(span, lastTextNode);
|
|
85
|
+
}
|
|
30
86
|
}
|
|
31
87
|
|
|
32
88
|
$effect(() => {
|
|
@@ -37,7 +93,11 @@ $effect(() => {
|
|
|
37
93
|
isUpdating = true;
|
|
38
94
|
|
|
39
95
|
tick().then(() => {
|
|
40
|
-
|
|
96
|
+
links.forEach(link => {
|
|
97
|
+
if (!link.querySelector('.qc-ext-link-img')) {
|
|
98
|
+
addExternalLinkIcon(link);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
41
101
|
return tick();
|
|
42
102
|
}).then(() => {
|
|
43
103
|
isUpdating = false;
|
|
@@ -51,8 +111,7 @@ $effect(() => {
|
|
|
51
111
|
alt={externalIconAlt}
|
|
52
112
|
bind:rootElement={imgElement}
|
|
53
113
|
class="qc-ext-link-img"
|
|
114
|
+
color="link-text"
|
|
54
115
|
/>
|
|
55
116
|
</div>
|
|
56
117
|
|
|
57
|
-
|
|
58
|
-
|
|
@@ -8,17 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
<script>
|
|
10
10
|
import ExternalLink from "./ExternalLink.svelte";
|
|
11
|
-
import {onDestroy, onMount, tick} from "svelte";
|
|
12
11
|
import {Utils} from "../utils";
|
|
12
|
+
import {onDestroy, onMount, tick} from "svelte";
|
|
13
13
|
|
|
14
14
|
const props = $props();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let links = $state([]);
|
|
18
|
-
const observer = Utils.createMutationObserver($host(), refreshLinks);
|
|
15
|
+
let links = $state(queryLinks());
|
|
19
16
|
let isUpdating = $state(false);
|
|
20
17
|
let pendingUpdate = false;
|
|
18
|
+
const nestedExternalLinks = $host().querySelector('qc-external-link');
|
|
21
19
|
|
|
20
|
+
const observer = Utils.createMutationObserver($host(), refreshLinks);
|
|
22
21
|
function queryLinks() {
|
|
23
22
|
return Array.from($host().querySelectorAll('a'));
|
|
24
23
|
}
|
|
@@ -41,7 +40,6 @@
|
|
|
41
40
|
|
|
42
41
|
onMount(() => {
|
|
43
42
|
$host().classList.add('qc-external-link');
|
|
44
|
-
links = queryLinks();
|
|
45
43
|
|
|
46
44
|
observer?.observe($host(), {
|
|
47
45
|
childList: true,
|
|
@@ -50,9 +48,7 @@
|
|
|
50
48
|
});
|
|
51
49
|
});
|
|
52
50
|
|
|
53
|
-
onDestroy(() =>
|
|
54
|
-
observer?.disconnect();
|
|
55
|
-
});
|
|
51
|
+
onDestroy(() => observer?.disconnect());
|
|
56
52
|
</script>
|
|
57
53
|
|
|
58
|
-
<ExternalLink
|
|
54
|
+
<ExternalLink bind:links bind:isUpdating {nestedExternalLinks} {...props} />
|