@hyvor/design 2.0.0-beta.1 → 2.0.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 (54) hide show
  1. package/README.md +9 -0
  2. package/dist/cloud/HyvorBar/BarProducts/BarProducts.svelte +1 -4
  3. package/dist/cloud/HyvorBar/BarUpdatesList.svelte +1 -3
  4. package/dist/cloud/HyvorBar/HyvorBar.svelte +0 -2
  5. package/dist/cloud/HyvorBar/bar.d.ts +1 -1
  6. package/dist/cloud/OrganizationMembers/OrganizationMembersSearch.svelte +1 -4
  7. package/dist/cloud/ResourceCreator/Accordian.svelte +2 -4
  8. package/dist/components/Accordion/Accordion.svelte +134 -134
  9. package/dist/components/Button/Button.svelte +2 -12
  10. package/dist/components/CodeBlock/CodeBlock.svelte +45 -28
  11. package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +2 -3
  12. package/dist/components/CodeBlock/TabbedCodeBlock.svelte +60 -64
  13. package/dist/components/CodeBlock/TabbedCodeBlock.svelte.d.ts +1 -1
  14. package/dist/components/CodeBlock/getCode.d.ts +3 -1
  15. package/dist/components/CodeBlock/getCode.js +33 -50
  16. package/dist/components/ColorPicker/ColorPicker.svelte +1 -1
  17. package/dist/components/Dark/DarkProvider.svelte +1 -1
  18. package/dist/components/DetailCard/DetailCard.svelte +43 -46
  19. package/dist/components/DetailCard/DetailCard.svelte.d.ts +1 -1
  20. package/dist/components/DetailCard/DetailCards.svelte +13 -16
  21. package/dist/components/DetailCard/DetailCards.svelte.d.ts +1 -1
  22. package/dist/components/Dropdown/DropdownContent.svelte +1 -2
  23. package/dist/components/EmojiPicker/EmojiSelector.svelte +3 -14
  24. package/dist/components/EmojiPicker/emojidata.js +3 -3
  25. package/dist/components/FileUploader/Preview/Preview.svelte +1 -1
  26. package/dist/components/FileUploader/TabUpload/TabUpload.svelte +2 -4
  27. package/dist/components/FileUploader/file-uploader.js +5 -10
  28. package/dist/components/FileUploader/helpers.js +1 -1
  29. package/dist/components/IconButton/IconButton.svelte +2 -10
  30. package/dist/components/Internationalization/LanguageToggle.svelte +2 -2
  31. package/dist/components/Internationalization/T.svelte +2 -9
  32. package/dist/components/Internationalization/i18n.js +3 -1
  33. package/dist/components/Modal/Modal.svelte +16 -12
  34. package/dist/components/TextInput/TextInput.svelte +29 -52
  35. package/dist/components/TextInput/TextInput.svelte.d.ts +5 -3
  36. package/dist/components/Textarea/Textarea.svelte +84 -98
  37. package/dist/index.css +4 -4
  38. package/dist/legacy.js +2 -2
  39. package/dist/marketing/Affiliate/Affiliate.svelte +53 -51
  40. package/dist/marketing/Container/Container.svelte +4 -5
  41. package/dist/marketing/Docs/Nav/Nav.svelte +1 -2
  42. package/dist/marketing/Footer/Footer.svelte +2 -2
  43. package/dist/marketing/Header/Header.svelte +131 -140
  44. package/dist/marketing/Header/Header.svelte.d.ts +3 -1
  45. package/dist/marketing/Header/HeaderNotification.svelte +64 -0
  46. package/dist/marketing/Header/HeaderNotification.svelte.d.ts +7 -0
  47. package/dist/marketing/cloud.d.ts +1 -0
  48. package/dist/marketing/cloud.js +15 -0
  49. package/dist/marketing/track/track.d.ts +0 -1
  50. package/dist/marketing/track/track.js +3 -6
  51. package/dist/variables.scss +1 -1
  52. package/package.json +24 -22
  53. package/dist/components/CodeBlock/hljs.scss +0 -228
  54. package/dist/components/CodeBlock/prism.scss +0 -375
@@ -1 +1,3 @@
1
- export {};
1
+ export type Language = 'html' | 'css' | 'js' | 'ts' | 'yaml' | 'json' | 'svelte' | 'jsx' | 'php' | 'sh' | string;
2
+ export declare function sanitizeLines(code: string): string;
3
+ export declare function getCode(code: string, language: Language | null): Promise<string>;
@@ -1,50 +1,33 @@
1
- "use strict";
2
- // // import hljs from 'highlight.js/lib/core';
3
- // // import javascript from 'highlight.js/lib/languages/javascript';
4
- // // import xml from 'highlight.js/lib/languages/xml';
5
- // // import css from 'highlight.js/lib/languages/css';
6
- // // import ts from 'highlight.js/lib/languages/typescript';
7
- // // import yaml from 'highlight.js/lib/languages/yaml';
8
- // // import json from 'highlight.js/lib/languages/json';
9
- // // import php from 'highlight.js/lib/languages/php';
10
- // hljs.registerLanguage('javascript', javascript);
11
- // hljs.registerLanguage('xml', xml);
12
- // hljs.registerLanguage('css', css);
13
- // hljs.registerLanguage('ts', ts);
14
- // hljs.registerLanguage('yaml', yaml);
15
- // hljs.registerLanguage('json', json);
16
- // hljs.registerLanguage('php', php);
17
- // export type Language = 'html' | 'css' | 'js' | 'ts';
18
- // export default function getCode(code: string, language: Language | null): string {
19
- // let ret = code;
20
- // // remove the first empty line
21
- // ret = ret.replace(/^[^\S\r\n]*\n/, '');
22
- // // remove the last empty line
23
- // ret = ret.replace(/\n[^\S\r\n]*$/, '');
24
- // let lines = ret.split('\n');
25
- // let indent: null | number = null; // number of spaces to remove from each line
26
- // lines = lines.map((line) => {
27
- // if (indent === null) {
28
- // // find the indent
29
- // const match = line.match(/^(\s*)/);
30
- // indent = match ? match[1].length : 0;
31
- // }
32
- // if (line.substring(0, indent).trim() !== '') {
33
- // return line;
34
- // }
35
- // // remove the indent
36
- // line = line.substring(indent);
37
- // return line;
38
- // });
39
- // ret = lines.join('\n');
40
- // return language === null ?
41
- // encodeHtml(ret) :
42
- // hljs.highlight(ret, { language }).value;
43
- // }
44
- // function encodeHtml(str: string): string {
45
- // return str.replace(/&/g, '&amp;')
46
- // .replace(/</g, '&lt;')
47
- // .replace(/>/g, '&gt;')
48
- // .replace(/"/g, '&quot;')
49
- // .replace(/'/g, '&#39;');
50
- // }
1
+ import { codeToHtml } from 'shiki';
2
+ export function sanitizeLines(code) {
3
+ let ret = code;
4
+ // remove the first empty line
5
+ ret = ret.replace(/^[^\S\r\n]*\n/, '');
6
+ // remove the last empty line
7
+ ret = ret.replace(/\n[^\S\r\n]*$/, '');
8
+ let lines = ret.split('\n');
9
+ let indent = null; // number of spaces to remove from each line
10
+ lines = lines.map((line) => {
11
+ if (indent === null) {
12
+ // find the indent
13
+ const match = line.match(/^(\s*)/);
14
+ indent = match ? match[1].length : 0;
15
+ }
16
+ if (line.substring(0, indent).trim() !== '') {
17
+ return line;
18
+ }
19
+ // remove the indent
20
+ line = line.substring(indent);
21
+ return line;
22
+ });
23
+ return lines.join('\n');
24
+ }
25
+ export async function getCode(code, language) {
26
+ return await codeToHtml(code, {
27
+ lang: language || 'text',
28
+ themes: {
29
+ light: 'vitesse-light',
30
+ dark: 'nord'
31
+ }
32
+ });
33
+ }
@@ -98,7 +98,7 @@
98
98
  --input-size={size + 'px'}
99
99
  isDialog={false}
100
100
  isAlpha={alpha}
101
- on:input={handleInput}
101
+ onInput={handleInput}
102
102
  />
103
103
  </div>
104
104
  {/if}
@@ -11,7 +11,7 @@
11
11
  <script>
12
12
  // to prevent white screen on page load
13
13
  // until the dark mode is initialized from the store
14
- const isDarkMode = !!localStorage.getItem("hds-dark");
14
+ const isDarkMode = !!localStorage.getItem('hds-dark');
15
15
  if (isDarkMode) {
16
16
  document.documentElement.classList.add('dark');
17
17
  }
@@ -1,56 +1,53 @@
1
1
  <script lang="ts">
2
- import type { Snippet } from "svelte";
2
+ import type { Snippet } from 'svelte';
3
3
 
4
- interface Props {
5
- label: string | Snippet;
6
- content?: string;
7
- children?: Snippet;
8
- }
4
+ interface Props {
5
+ label: string | Snippet;
6
+ content?: string;
7
+ children?: Snippet;
8
+ }
9
9
 
10
- let { label, content, children }: Props = $props();
11
-
12
- const labelId = `detail-card-${Math.random().toString(36).substring(2, 15)}`;
10
+ let { label, content, children }: Props = $props();
13
11
 
12
+ const labelId = `detail-card-${Math.random().toString(36).substring(2, 15)}`;
14
13
  </script>
15
14
 
16
15
  <div class="detail-card" role="region" aria-labelledby={labelId}>
17
-
18
- <div class="label" id={labelId}>
19
- {#if typeof label === "string"}
20
- {label}
21
- {:else}
22
- {@render label()}
23
- {/if}
24
- </div>
25
-
26
- <div class="content">
27
- {#if children}
28
- {@render children()}
29
- {:else if content}
30
- {content}
31
- {/if}
32
- </div>
33
-
16
+ <div class="label" id={labelId}>
17
+ {#if typeof label === 'string'}
18
+ {label}
19
+ {:else}
20
+ {@render label()}
21
+ {/if}
22
+ </div>
23
+
24
+ <div class="content">
25
+ {#if children}
26
+ {@render children()}
27
+ {:else if content}
28
+ {content}
29
+ {/if}
30
+ </div>
34
31
  </div>
35
32
 
36
33
  <style>
37
- .detail-card {
38
- background: var(--hover);
39
- padding: 15px 20px;
40
- border-radius: var(--box-radius);
41
- border: 1px solid var(--border);
42
- }
43
- .label {
44
- display: block;
45
- font-size: 12px;
46
- font-weight: 600;
47
- color: var(--text-light);
48
- text-transform: uppercase;
49
- letter-spacing: 0.5px;
50
- margin-bottom: 6px;
51
- }
52
- .content {
53
- font-size: 14px;
54
- word-break: break-word;
55
- }
56
- </style>
34
+ .detail-card {
35
+ background: var(--hover);
36
+ padding: 15px 20px;
37
+ border-radius: var(--box-radius);
38
+ border: 1px solid var(--border);
39
+ }
40
+ .label {
41
+ display: block;
42
+ font-size: 12px;
43
+ font-weight: 600;
44
+ color: var(--text-light);
45
+ text-transform: uppercase;
46
+ letter-spacing: 0.5px;
47
+ margin-bottom: 6px;
48
+ }
49
+ .content {
50
+ font-size: 14px;
51
+ word-break: break-word;
52
+ }
53
+ </style>
@@ -1,4 +1,4 @@
1
- import type { Snippet } from "svelte";
1
+ import type { Snippet } from 'svelte';
2
2
  interface Props {
3
3
  label: string | Snippet;
4
4
  content?: string;
@@ -1,25 +1,22 @@
1
1
  <script lang="ts">
2
- import type { Snippet } from "svelte";
2
+ import type { Snippet } from 'svelte';
3
3
 
4
- interface Props {
5
- children?: Snippet
6
- min?: number;
7
- }
4
+ interface Props {
5
+ children?: Snippet;
6
+ min?: number;
7
+ }
8
8
 
9
- let {
10
- children,
11
- min = 300
12
- }: Props = $props();
9
+ let { children, min = 300 }: Props = $props();
13
10
  </script>
14
11
 
15
12
  <div class="cards" style="--min: {min}px">
16
- {@render children?.()}
13
+ {@render children?.()}
17
14
  </div>
18
15
 
19
16
  <style>
20
- .cards {
21
- display: grid;
22
- grid-template-columns: repeat(auto-fit, minmax(var(--min), 1fr));
23
- gap: 10px;
24
- }
25
- </style>
17
+ .cards {
18
+ display: grid;
19
+ grid-template-columns: repeat(auto-fit, minmax(var(--min), 1fr));
20
+ gap: 10px;
21
+ }
22
+ </style>
@@ -1,4 +1,4 @@
1
- import type { Snippet } from "svelte";
1
+ import type { Snippet } from 'svelte';
2
2
  interface Props {
3
3
  children?: Snippet;
4
4
  min?: number;
@@ -68,8 +68,7 @@
68
68
  }
69
69
  } else if (align === 'center') {
70
70
  contentWrap.style.left =
71
- Math.max(triggerRect.left + triggerRect.width / 2 - width / 2, SPACE_AROUND) +
72
- 'px';
71
+ Math.max(triggerRect.left + triggerRect.width / 2 - width / 2, SPACE_AROUND) + 'px';
73
72
  } else if (align === 'end') {
74
73
  contentWrap.style.left = Math.max(triggerRect.right - width, SPACE_AROUND) + 'px';
75
74
  }
@@ -84,19 +84,12 @@
84
84
  </div>
85
85
  <div class="right">
86
86
  {#if removable}
87
- <Button size="small" color="input" onclick={() => onselect(undefined)}
88
- >Remove</Button
89
- >
87
+ <Button size="small" color="input" onclick={() => onselect(undefined)}>Remove</Button>
90
88
  {/if}
91
89
  </div>
92
90
  </div>
93
91
  <div class="input">
94
- <TextInput
95
- block
96
- bind:value={search}
97
- bind:input={searchInput}
98
- onkeydown={handleKeydown}
99
- />
92
+ <TextInput block bind:value={search} bind:input={searchInput} onkeydown={handleKeydown} />
100
93
  </div>
101
94
  <div class="groups" bind:this={groupsEl}>
102
95
  {#if searchedEmojis !== null}
@@ -131,11 +124,7 @@
131
124
  {/snippet}
132
125
 
133
126
  {#snippet SectionButton(icon: string, group: number)}
134
- <button
135
- class="section-button"
136
- data-group={group}
137
- onclick={() => handleSectionButtonClick(group)}
138
- >
127
+ <button class="section-button" data-group={group} onclick={() => handleSectionButtonClick(group)}>
139
128
  {icon}
140
129
  </button>
141
130
  {/snippet}
@@ -20,10 +20,10 @@ function isZWJEmoji(emoji) {
20
20
  export async function loadEmojis() {
21
21
  const data = await import('emojibase-data/en/compact.json');
22
22
  const emojiData = data.default;
23
- emojis = emojiData.filter(emoji => emoji.group !== undefined);
24
- const groupedEmojis = groups.map(group => ({
23
+ emojis = emojiData.filter((emoji) => emoji.group !== undefined);
24
+ const groupedEmojis = groups.map((group) => ({
25
25
  name: group,
26
- emojis: emojis.filter(emoji => emoji.group === groups.indexOf(group) && !isZWJEmoji(emoji.unicode))
26
+ emojis: emojis.filter((emoji) => emoji.group === groups.indexOf(group) && !isZWJEmoji(emoji.unicode))
27
27
  }));
28
28
  // remove components
29
29
  groupedEmojis.splice(2, 1);
@@ -193,7 +193,7 @@
193
193
  </div>
194
194
  <TextInput
195
195
  bind:value={imageName}
196
- on:input={handleNameChange}
196
+ oninput={handleNameChange}
197
197
  placeholder="Image Name"
198
198
  state={nameError ? 'error' : 'default'}
199
199
  disabled={!shouldUpload}
@@ -46,9 +46,7 @@
46
46
  .then((blob) => {
47
47
  if (!validateMimeType(blob.type)) {
48
48
  const names = getMimeNamesJoined();
49
- toast.error(
50
- `Only ${names} files are allowed. Current file type is ${blob.type}`
51
- );
49
+ toast.error(`Only ${names} files are allowed. Current file type is ${blob.type}`);
52
50
  return;
53
51
  }
54
52
 
@@ -223,7 +221,7 @@
223
221
  block
224
222
  placeholder="Enter image URL"
225
223
  bind:value={byUrl}
226
- on:keyup={(e) => e.key === 'Enter' && handleFetch()}
224
+ onkeyup={(e) => e.key === 'Enter' && handleFetch()}
227
225
  bind:input={byUrlInputEl}
228
226
  />
229
227
  <Button disabled={byUrl.trim() === ''} on:click={handleFetch}>
@@ -1,11 +1,11 @@
1
- import { get, writable } from "svelte/store";
1
+ import { get, writable } from 'svelte/store';
2
2
  export let fileUploaderConfig = writable(null);
3
3
  export let selectedFile = writable(null);
4
4
  const defaults = {
5
5
  type: 'image',
6
6
  uploader: null,
7
7
  allowedMimeTypes: [],
8
- maxFileSizeInMB: 10,
8
+ maxFileSizeInMB: 10
9
9
  };
10
10
  // UploadedFile is uploaded
11
11
  // null means cancelled
@@ -19,7 +19,7 @@ export function uploadFile(config) {
19
19
  },
20
20
  onUpload: (file) => {
21
21
  resolve(file);
22
- },
22
+ }
23
23
  };
24
24
  if (config.allowedMimeTypes === undefined) {
25
25
  // set based on type
@@ -63,12 +63,7 @@ const ALLOWED_MIME_TYPES_IMAGE = [
63
63
  'image/apng',
64
64
  'image/avif'
65
65
  ];
66
- const ALLOWED_MIME_TYPES_AUDIO = [
67
- 'audio/mpeg',
68
- 'audio/ogg',
69
- 'audio/wav',
70
- 'audio/webm'
71
- ];
66
+ const ALLOWED_MIME_TYPES_AUDIO = ['audio/mpeg', 'audio/ogg', 'audio/wav', 'audio/webm'];
72
67
  export function validateMimeType(mimeType) {
73
68
  const config = getFileUploaderConfig();
74
69
  if (config.allowedMimeTypes.length === 0) {
@@ -81,7 +76,7 @@ export function getMimeNames() {
81
76
  if (config.allowedMimeTypes.length === 0) {
82
77
  return []; // all mime types allowed
83
78
  }
84
- return config.allowedMimeTypes.map(m => m.split('/')[1]?.split('+')[0]);
79
+ return config.allowedMimeTypes.map((m) => m.split('/')[1]?.split('+')[0]);
85
80
  }
86
81
  export function getMimeNamesJoined() {
87
82
  const names = getMimeNames();
@@ -23,7 +23,7 @@ export function toKebabCase(str) {
23
23
  }
24
24
  return str
25
25
  .replace(/\s+/g, '-') // Replace spaces with hyphens
26
- .replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`) // Add hyphen before capital letters and convert them to lowercase
26
+ .replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`) // Add hyphen before capital letters and convert them to lowercase
27
27
  .replace(/_+/g, '-') // Replace underscores with hyphens
28
28
  .replace(/--+/g, '-') // Replace multiple hyphens with a single one
29
29
  .replace(/^-|-$|^-+|-+$/g, '') // Remove leading and trailing hyphens
@@ -168,11 +168,7 @@
168
168
  .button.fill-light.orange {
169
169
  background-color: var(--orange-light);
170
170
  color: var(--orange-dark);
171
- --local-hover-shadow-color: color-mix(
172
- in srgb,
173
- var(--orange-light) 40%,
174
- transparent
175
- );
171
+ --local-hover-shadow-color: color-mix(in srgb, var(--orange-light) 40%, transparent);
176
172
  }
177
173
  .button.outline {
178
174
  border: 1px solid;
@@ -214,11 +210,7 @@
214
210
  background-color: var(--accent-light);
215
211
  border-color: var(--accent);
216
212
  color: var(--accent);
217
- --local-hover-shadow-color: color-mix(
218
- in srgb,
219
- var(--accent-light) 40%,
220
- transparent
221
- );
213
+ --local-hover-shadow-color: color-mix(in srgb, var(--accent-light) 40%, transparent);
222
214
  }
223
215
  .button.outline-fill.gray {
224
216
  background-color: var(--gray-light);
@@ -26,7 +26,7 @@
26
26
  icon = false,
27
27
  size = 'medium',
28
28
  staticPage = false,
29
- goto,
29
+ goto
30
30
  }: Props = $props();
31
31
 
32
32
  const i18n = getContext<InternationalizationService>('i18n');
@@ -45,7 +45,7 @@
45
45
  }
46
46
  const url = new URL(window.location.href);
47
47
  url.pathname = url.pathname.replace(`/${currentLocale}`, `/${language.code}`);
48
-
48
+
49
49
  if (goto) {
50
50
  goto(url.toString());
51
51
  } else {
@@ -57,10 +57,7 @@
57
57
  };
58
58
  hasComponentParams = true;
59
59
  } else if (value.hasOwnProperty('element')) {
60
- newValue = getElementFunc(
61
- (value as any).element as string,
62
- (value as any).props || {}
63
- );
60
+ newValue = getElementFunc((value as any).element as string, (value as any).props || {});
64
61
  }
65
62
  } else {
66
63
  newValue = value as PrimitiveType;
@@ -91,11 +88,7 @@
91
88
  newValue = (chunks: string | string[]) => {
92
89
  const children = typeof chunks === 'string' ? chunks : chunks.join('');
93
90
  const id =
94
- key +
95
- '-' +
96
- Math.random().toString(36).substring(7) +
97
- '-' +
98
- Date.now().toString();
91
+ key + '-' + Math.random().toString(36).substring(7) + '-' + Date.now().toString();
99
92
  componentBindings.set(id, {
100
93
  component: component!,
101
94
  props: {
@@ -28,7 +28,9 @@ export class InternationalizationService {
28
28
  this.register(language);
29
29
  }
30
30
  const localeStorageLocale = InternationalizationService.getLocaleFromLocalStorage();
31
- const browserLocale = typeof navigator !== "undefined" ? InternationalizationService.getClosestLanguageCode(navigator.language, this.languages.map((l) => l.code)) : null;
31
+ const browserLocale = typeof navigator !== 'undefined'
32
+ ? InternationalizationService.getClosestLanguageCode(navigator.language, this.languages.map((l) => l.code))
33
+ : null;
32
34
  if (forceLanguage) {
33
35
  this.setLocale(forceLanguage);
34
36
  }
@@ -1,8 +1,6 @@
1
- <!-- @migration-task Error while migrating Svelte code: This migration would change the name of a slot making the component unusable -->
2
1
  <script lang="ts">
3
2
  import ModalFooter from './ModalFooter.svelte';
4
3
  import type { Footer } from './modal-types.js';
5
- import { clickOutside } from '../directives/clickOutside.js';
6
4
  import IconX from '@hyvor/icons/IconX';
7
5
  import IconButton from './../IconButton/IconButton.svelte';
8
6
  import { fade, scale } from 'svelte/transition';
@@ -69,6 +67,13 @@
69
67
  show;
70
68
  setFlex();
71
69
  });
70
+
71
+ function handleClose(e: MouseEvent) {
72
+ // close only when clicking directy on backdrop (not inner content)
73
+ if (closeOnOutsideClick && !loading && e.target === e.currentTarget) {
74
+ handleCancel();
75
+ }
76
+ }
72
77
  </script>
73
78
 
74
79
  <svelte:window
@@ -80,13 +85,16 @@
80
85
  />
81
86
 
82
87
  {#if show}
83
- <div class="wrap" bind:this={wrapEl} in:fade={{ duration: 100 }} out:fade={{ duration: 100 }}>
88
+ <div
89
+ role="presentation"
90
+ class="wrap"
91
+ bind:this={wrapEl}
92
+ in:fade={{ duration: 100 }}
93
+ out:fade={{ duration: 100 }}
94
+ onclick={(e) => handleClose(e)}
95
+ >
84
96
  <div
85
97
  class="inner {size}"
86
- use:clickOutside={{
87
- enabled: closeOnOutsideClick,
88
- callback: () => (!loading ? handleCancel() : null)
89
- }}
90
98
  in:scale={{ duration: 100, start: 0.9, opacity: 0.9 }}
91
99
  out:scale={{ duration: 100, start: 0.9, opacity: 0.9 }}
92
100
  bind:this={innerEl}
@@ -105,11 +113,7 @@
105
113
  </div>
106
114
 
107
115
  <div class="close-wrap">
108
- <IconButton
109
- variant="invisible"
110
- on:click={handleCancel}
111
- aria-label="Close modal"
112
- >
116
+ <IconButton variant="invisible" on:click={handleCancel} aria-label="Close modal">
113
117
  <IconX size={25} />
114
118
  </IconButton>
115
119
  </div>