@hyvor/design 2.1.3 → 2.1.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.
- package/dist/components/CodeBlock/CodeBlock.svelte +6 -34
- package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +1 -1
- package/dist/components/CodeBlock/getCode.d.ts +11 -3
- package/dist/components/CodeBlock/getCode.js +51 -29
- package/dist/components/CodeBlock/types.codeblock.d.ts +1 -0
- package/dist/components/CodeBlock/types.codeblock.js +1 -0
- package/dist/components/TabNav/TabNav.svelte +38 -6
- package/dist/components/TabNav/TabNav.svelte.d.ts +12 -3
- package/dist/components/TabNav/TabNavItem.svelte +9 -5
- package/dist/components/TabNav/tabnav.d.ts +4 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/components/markdown/markdown.js +17 -0
- package/dist/index.css +31 -0
- package/package.json +2 -1
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import Button from '../Button/Button.svelte';
|
|
3
3
|
import IconCopy from '@hyvor/icons/IconCopy';
|
|
4
4
|
import toast from '../Toast/toast.js';
|
|
5
|
-
import {
|
|
5
|
+
import { highlightCode, sanitizeLines } from './getCode.js';
|
|
6
|
+
import type { Language } from './types.codeblock.js';
|
|
6
7
|
|
|
7
8
|
interface Props {
|
|
8
9
|
code: string;
|
|
@@ -19,22 +20,22 @@
|
|
|
19
20
|
}
|
|
20
21
|
</script>
|
|
21
22
|
|
|
22
|
-
<div class="code-
|
|
23
|
+
<div class="hds-code-block">
|
|
23
24
|
<div class="copy-button">
|
|
24
25
|
<Button color="input" size="x-small" onclick={copyToClipboard}>
|
|
25
26
|
<IconCopy size={10} />
|
|
26
27
|
</Button>
|
|
27
28
|
</div>
|
|
28
|
-
{@html await
|
|
29
|
+
{@html await highlightCode(sanitizedCode, language)}
|
|
29
30
|
</div>
|
|
30
31
|
|
|
31
32
|
<style>
|
|
32
33
|
/*styles for CodeBlock component */
|
|
33
|
-
.code-
|
|
34
|
+
.hds-code-block {
|
|
34
35
|
position: relative;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
.
|
|
38
|
+
.copy-button {
|
|
38
39
|
position: absolute;
|
|
39
40
|
top: 0px;
|
|
40
41
|
right: 12px;
|
|
@@ -45,33 +46,4 @@
|
|
|
45
46
|
.copy-button :global(button) {
|
|
46
47
|
border: 1px solid var(--border);
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
-
.code-container :global(pre) {
|
|
50
|
-
text-align: left;
|
|
51
|
-
white-space: pre;
|
|
52
|
-
word-spacing: normal;
|
|
53
|
-
word-break: normal;
|
|
54
|
-
word-wrap: normal;
|
|
55
|
-
overflow: auto;
|
|
56
|
-
border-radius: 20px;
|
|
57
|
-
padding: 20px;
|
|
58
|
-
line-height: 1.2;
|
|
59
|
-
background-color: #f4f2f0 !important;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.code-container :global(pre code) {
|
|
63
|
-
all: unset;
|
|
64
|
-
font-size: 14px;
|
|
65
|
-
line-height: 1.5 !important;
|
|
66
|
-
tab-size: 4;
|
|
67
|
-
hyphens: none;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
:global(:root.dark .shiki, :root.dark .shiki span) {
|
|
71
|
-
color: var(--shiki-dark) !important;
|
|
72
|
-
background-color: var(--shiki-dark-bg) !important;
|
|
73
|
-
font-style: var(--shiki-dark-font-style) !important;
|
|
74
|
-
font-weight: var(--shiki-dark-font-weight) !important;
|
|
75
|
-
text-decoration: var(--shiki-dark-text-decoration) !important;
|
|
76
|
-
}
|
|
77
49
|
</style>
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} code
|
|
3
|
+
* @returns {string}
|
|
4
|
+
*/
|
|
5
|
+
export function sanitizeLines(code: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} code
|
|
8
|
+
* @param {import('./types.codeblock.ts').Language | null} language
|
|
9
|
+
* @returns {Promise<string>}
|
|
10
|
+
*/
|
|
11
|
+
export function highlightCode(code: string, language: import("./types.codeblock.ts").Language | null): Promise<string>;
|
|
@@ -1,33 +1,55 @@
|
|
|
1
1
|
import { codeToHtml } from 'shiki';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} code
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
2
7
|
export function sanitizeLines(code) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
let ret = code;
|
|
9
|
+
|
|
10
|
+
// remove the first empty line
|
|
11
|
+
ret = ret.replace(/^[^\S\r\n]*\n/, '');
|
|
12
|
+
// remove the last empty line
|
|
13
|
+
ret = ret.replace(/\n[^\S\r\n]*$/, '');
|
|
14
|
+
|
|
15
|
+
let lines = ret.split('\n');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @type {null | number}
|
|
19
|
+
*/
|
|
20
|
+
let indent = null; // number of spaces to remove from each line
|
|
21
|
+
|
|
22
|
+
lines = lines.map((line) => {
|
|
23
|
+
if (indent === null) {
|
|
24
|
+
// find the indent
|
|
25
|
+
const match = line.match(/^(\s*)/);
|
|
26
|
+
indent = match ? match[1].length : 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (line.substring(0, indent).trim() !== '') {
|
|
30
|
+
return line;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// remove the indent
|
|
34
|
+
line = line.substring(indent);
|
|
35
|
+
|
|
36
|
+
return line;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return lines.join('\n');
|
|
24
40
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {string} code
|
|
44
|
+
* @param {import('./types.codeblock.ts').Language | null} language
|
|
45
|
+
* @returns {Promise<string>}
|
|
46
|
+
*/
|
|
47
|
+
export async function highlightCode(code, language) {
|
|
48
|
+
return await codeToHtml(code, {
|
|
49
|
+
lang: language || 'text',
|
|
50
|
+
themes: {
|
|
51
|
+
light: 'vitesse-light',
|
|
52
|
+
dark: 'nord'
|
|
53
|
+
}
|
|
54
|
+
});
|
|
33
55
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Language = 'html' | 'css' | 'js' | 'ts' | 'yaml' | 'json' | 'svelte' | 'jsx' | 'php' | 'sh' | string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,17 +1,49 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { setContext } from 'svelte';
|
|
3
|
+
import type { TabNavState } from './tabnav.js';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
type Props = (
|
|
6
|
+
| {
|
|
7
|
+
basePath?: undefined;
|
|
8
|
+
pathname?: undefined;
|
|
9
|
+
goto?: undefined;
|
|
10
|
+
}
|
|
11
|
+
| {
|
|
12
|
+
basePath: string;
|
|
13
|
+
// SvelteKit's `page.url.pathname`, e.g. `import { page } from '$app/state'`.
|
|
14
|
+
pathname: string;
|
|
15
|
+
// SvelteKit's `goto`, e.g. `import { goto } from '$app/navigation'`.
|
|
16
|
+
goto: (url: string, opts?: { replaceState?: boolean }) => void;
|
|
17
|
+
}
|
|
18
|
+
) & {
|
|
6
19
|
replaceState?: boolean;
|
|
7
20
|
children?: import('svelte').Snippet;
|
|
8
|
-
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let { children, basePath, replaceState = false, pathname: pathnameProp, goto }: Props = $props();
|
|
24
|
+
|
|
25
|
+
let fallbackPathname = $state(typeof window !== 'undefined' ? window.location.pathname : '');
|
|
26
|
+
|
|
27
|
+
$effect(() => {
|
|
28
|
+
if (!basePath || pathnameProp !== undefined) return;
|
|
9
29
|
|
|
10
|
-
|
|
30
|
+
const onPopState = () => {
|
|
31
|
+
fallbackPathname = window.location.pathname;
|
|
32
|
+
};
|
|
33
|
+
window.addEventListener('popstate', onPopState);
|
|
34
|
+
return () => window.removeEventListener('popstate', onPopState);
|
|
35
|
+
});
|
|
11
36
|
|
|
12
|
-
const tabNavState = {
|
|
37
|
+
const tabNavState: TabNavState = {
|
|
13
38
|
basePath,
|
|
14
|
-
replaceState
|
|
39
|
+
replaceState,
|
|
40
|
+
goto,
|
|
41
|
+
get pathname() {
|
|
42
|
+
return pathnameProp ?? fallbackPathname;
|
|
43
|
+
},
|
|
44
|
+
set pathname(value: string) {
|
|
45
|
+
fallbackPathname = value;
|
|
46
|
+
}
|
|
15
47
|
};
|
|
16
48
|
|
|
17
49
|
setContext('tab-nav-state', tabNavState);
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
basePath?:
|
|
1
|
+
type Props = ({
|
|
2
|
+
basePath?: undefined;
|
|
3
|
+
pathname?: undefined;
|
|
4
|
+
goto?: undefined;
|
|
5
|
+
} | {
|
|
6
|
+
basePath: string;
|
|
7
|
+
pathname: string;
|
|
8
|
+
goto: (url: string, opts?: {
|
|
9
|
+
replaceState?: boolean;
|
|
10
|
+
}) => void;
|
|
11
|
+
}) & {
|
|
3
12
|
replaceState?: boolean;
|
|
4
13
|
children?: import('svelte').Snippet;
|
|
5
|
-
}
|
|
14
|
+
};
|
|
6
15
|
declare const TabNav: import("svelte").Component<Props, {}, "">;
|
|
7
16
|
type TabNav = ReturnType<typeof TabNav>;
|
|
8
17
|
export default TabNav;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContext } from 'svelte';
|
|
3
|
-
import { page } from '$app/state';
|
|
4
|
-
import { goto } from '$app/navigation';
|
|
5
3
|
import type { TabNavState } from './tabnav.js';
|
|
6
4
|
|
|
7
5
|
interface Props {
|
|
@@ -28,8 +26,7 @@
|
|
|
28
26
|
if (active) return true;
|
|
29
27
|
|
|
30
28
|
if (tabNavState.basePath) {
|
|
31
|
-
|
|
32
|
-
return currentUrl === getTabPath();
|
|
29
|
+
return tabNavState.pathname === getTabPath();
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
return false;
|
|
@@ -37,7 +34,14 @@
|
|
|
37
34
|
|
|
38
35
|
function handleClick(event: MouseEvent) {
|
|
39
36
|
if (tabNavState.basePath) {
|
|
40
|
-
|
|
37
|
+
const path = getTabPath();
|
|
38
|
+
|
|
39
|
+
if (tabNavState.goto) {
|
|
40
|
+
tabNavState.goto(path, { replaceState: tabNavState.replaceState });
|
|
41
|
+
tabNavState.pathname = path;
|
|
42
|
+
} else {
|
|
43
|
+
window.location.href = path;
|
|
44
|
+
}
|
|
41
45
|
}
|
|
42
46
|
onclick?.(event);
|
|
43
47
|
}
|
|
@@ -12,6 +12,8 @@ export { default as BoxShadowPicker } from './BoxShadowPicker/BoxShadowPicker.sv
|
|
|
12
12
|
export { default as Callout } from './Callout/Callout.svelte';
|
|
13
13
|
export { default as Checkbox } from './Checkbox/Checkbox.svelte';
|
|
14
14
|
export { default as CodeBlock } from './CodeBlock/CodeBlock.svelte';
|
|
15
|
+
export { highlightCode } from './CodeBlock/getCode.js';
|
|
16
|
+
export { markdownPlugin } from './markdown/markdown.js';
|
|
15
17
|
export { default as TabbedCodeBlock } from './CodeBlock/TabbedCodeBlock.svelte';
|
|
16
18
|
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
17
19
|
export { default as ConsoleLoader } from './ConsoleLoader/ConsoleLoader.svelte';
|
package/dist/components/index.js
CHANGED
|
@@ -12,6 +12,8 @@ export { default as BoxShadowPicker } from './BoxShadowPicker/BoxShadowPicker.sv
|
|
|
12
12
|
export { default as Callout } from './Callout/Callout.svelte';
|
|
13
13
|
export { default as Checkbox } from './Checkbox/Checkbox.svelte';
|
|
14
14
|
export { default as CodeBlock } from './CodeBlock/CodeBlock.svelte';
|
|
15
|
+
export { highlightCode } from './CodeBlock/getCode.js';
|
|
16
|
+
export { markdownPlugin } from './markdown/markdown.js';
|
|
15
17
|
export { default as TabbedCodeBlock } from './CodeBlock/TabbedCodeBlock.svelte';
|
|
16
18
|
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
17
19
|
export { default as ConsoleLoader } from './ConsoleLoader/ConsoleLoader.svelte';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { mdsvex, escapeSvelte } from 'mdsvex';
|
|
2
|
+
import { highlightCode } from '../CodeBlock/getCode.js';
|
|
3
|
+
|
|
4
|
+
// this is a JS file because we can use it in svelte.config.js locally
|
|
5
|
+
|
|
6
|
+
export function markdownPlugin() {
|
|
7
|
+
return mdsvex({
|
|
8
|
+
extensions: ['.md'],
|
|
9
|
+
highlight: {
|
|
10
|
+
highlighter: async (code, lang) => {
|
|
11
|
+
const highlitedCode = await highlightCode(code, lang || null);
|
|
12
|
+
const html = `<div class="hds-code-block">${highlitedCode}</div>`;
|
|
13
|
+
return escapeSvelte(html);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
package/dist/index.css
CHANGED
|
@@ -61,3 +61,34 @@ a {
|
|
|
61
61
|
color: var(--link);
|
|
62
62
|
text-decoration: underline;
|
|
63
63
|
}
|
|
64
|
+
|
|
65
|
+
/** code block styles */
|
|
66
|
+
.hds-code-block pre {
|
|
67
|
+
text-align: left;
|
|
68
|
+
white-space: pre;
|
|
69
|
+
word-spacing: normal;
|
|
70
|
+
word-break: normal;
|
|
71
|
+
word-wrap: normal;
|
|
72
|
+
overflow: auto;
|
|
73
|
+
border-radius: 20px;
|
|
74
|
+
padding: 20px;
|
|
75
|
+
line-height: 1.2;
|
|
76
|
+
background-color: #f4f2f0 !important;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.hds-code-block pre code {
|
|
80
|
+
all: unset;
|
|
81
|
+
font-size: 14px;
|
|
82
|
+
line-height: 1.5 !important;
|
|
83
|
+
tab-size: 4;
|
|
84
|
+
hyphens: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
:root.dark .shiki,
|
|
88
|
+
:root.dark .shiki span {
|
|
89
|
+
color: var(--shiki-dark) !important;
|
|
90
|
+
background-color: var(--shiki-dark-bg) !important;
|
|
91
|
+
font-style: var(--shiki-dark-font-style) !important;
|
|
92
|
+
font-weight: var(--shiki-dark-font-weight) !important;
|
|
93
|
+
text-decoration: var(--shiki-dark-text-decoration) !important;
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyvor/design",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"deepmerge-ts": "^7.1.5",
|
|
66
66
|
"emojibase-data": "^17.0.0",
|
|
67
67
|
"intl-messageformat": "^11.1.2",
|
|
68
|
+
"mdsvex": "^0.12.8",
|
|
68
69
|
"shiki": "^3.22.0",
|
|
69
70
|
"svelte-awesome-color-picker": "^4.1.1",
|
|
70
71
|
"tocbot": "^4.36.4"
|