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.
@@ -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], [[48, 0]]);
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 addExternalLinkIcon(links) {
11457
- links.forEach((link) => {
11458
- if (processedLinks.has(link.innerHTML)) {
11459
- return;
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
- let linkContent = link.innerHTML;
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
- linkContent = `<span class="qc-ext-link-text">${linkContent}</span>&nbsp;${get(imgElement).outerHTML}`;
11465
- link.innerHTML = linkContent;
11466
- processedLinks.add(linkContent);
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
- addExternalLinkIcon(links());
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 node = child(div);
11593
+ var node_1 = child(div);
11532
11594
 
11533
11595
  add_svelte_meta(
11534
- () => Icon(node, {
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
- 49,
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
- const nestedExternalLinks = $$props.$$host.querySelector('qc-external-link');
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
- 58,
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], [[386, 20]]);
16351
- var root_3 = add_locations(from_html(`<span> </span>`), DropdownList[FILENAME], [[427, 24]]);
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], [[316, 0, [[321, 4, [[340, 8, [[369, 12, [[425, 16]]]]]]]]]]);
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
- 327,
16973
+ 335,
16902
16974
  12,
16903
16975
  { componentTag: 'Label' }
16904
16976
  );
@@ -16910,7 +16982,7 @@
16910
16982
  }),
16911
16983
  'if',
16912
16984
  DropdownList,
16913
- 326,
16985
+ 334,
16914
16986
  8
16915
16987
  );
16916
16988
  }
@@ -16982,7 +17054,7 @@
16982
17054
  }),
16983
17055
  'component',
16984
17056
  DropdownList,
16985
- 349,
17057
+ 357,
16986
17058
  12,
16987
17059
  { componentTag: 'DropdownListButton' }
16988
17060
  );
@@ -17037,7 +17109,7 @@
17037
17109
  ),
17038
17110
  'component',
17039
17111
  DropdownList,
17040
- 387,
17112
+ 395,
17041
17113
  24,
17042
17114
  { componentTag: 'SearchInput' }
17043
17115
  );
@@ -17053,7 +17125,7 @@
17053
17125
  }),
17054
17126
  'if',
17055
17127
  DropdownList,
17056
- 385,
17128
+ 393,
17057
17129
  16
17058
17130
  );
17059
17131
  }
@@ -17113,7 +17185,7 @@
17113
17185
  ),
17114
17186
  'component',
17115
17187
  DropdownList,
17116
- 405,
17188
+ 413,
17117
17189
  16,
17118
17190
  { componentTag: 'DropdownListItems' }
17119
17191
  );
@@ -17133,7 +17205,7 @@
17133
17205
  }),
17134
17206
  'key',
17135
17207
  DropdownList,
17136
- 426,
17208
+ 434,
17137
17209
  20
17138
17210
  );
17139
17211
 
@@ -17181,7 +17253,7 @@
17181
17253
  }),
17182
17254
  'component',
17183
17255
  DropdownList,
17184
- 435,
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
- & > .qc-ext-link-img {
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
- & > .qc-ext-link-img {
112
- background-color: token-value(color, link, active);
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
- & > .qc-ext-link-img {
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
- a.pseudo-focus & {
134
- background: token-value(color link hover)!important;
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
- a.not-visited:visited:not(:hover) & {
143
- background: token-value(color link text)!important;
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 interne</dt>
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
- display: inline-block;
43
- mask-repeat: no-repeat;
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: rem(8);
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
- background-color: rgba(map.get(map.get(map.get($xl-tokens, color), blue), piv), 0.16);
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(map.get(map.get(map.get($xl-tokens, color), blue), piv), 0.08);
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
- background-color: rgba(map.get(map.get(map.get($xl-tokens, color), grey), light), 0.24);
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(map.get(map.get(map.get($xl-tokens, color), grey), light), 0.24);
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(map.get(map.get(map.get($xl-tokens, color), grey), light), 0.16);
144
+ background-color: rgba(var(--qc-color-grey-light-rgb), 0.16);
137
145
  }
138
146
 
139
147
  &:disabled,
@@ -255,6 +255,14 @@
255
255
  }
256
256
  });
257
257
 
258
+ $effect(() => {
259
+ if (value) {
260
+ items.forEach((item) => {
261
+ item.checked = value.includes(item.value);
262
+ });
263
+ }
264
+ });
265
+
258
266
  $effect(() => {
259
267
  items.forEach((item) => {
260
268
  if (!item.id) {
@@ -13,20 +13,76 @@ let {
13
13
  } = $props();
14
14
 
15
15
  let imgElement = $state();
16
- let processedLinks = new Set();
17
16
 
18
- function addExternalLinkIcon(links) {
19
- links.forEach(link => {
20
- if (processedLinks.has(link.innerHTML)) {
21
- return;
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
- let linkContent = link.innerHTML;
25
- linkContent = `<span class="qc-ext-link-text">${linkContent}</span>&nbsp;${imgElement.outerHTML}`;
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
- link.innerHTML = linkContent;
28
- processedLinks.add(linkContent);
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
- addExternalLinkIcon(links);
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
- const nestedExternalLinks = $host().querySelector('qc-external-link');
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 {links} bind:isUpdating {nestedExternalLinks} {...props} />
54
+ <ExternalLink bind:links bind:isUpdating {nestedExternalLinks} {...props} />