Skip to content

Commit

Permalink
refactor: leaner enhanced-code-block components
Browse files Browse the repository at this point in the history
  • Loading branch information
vnphanquang committed Oct 24, 2024
1 parent db201bb commit 7146f36
Show file tree
Hide file tree
Showing 15 changed files with 1,023 additions and 867 deletions.
22 changes: 5 additions & 17 deletions packages/preprocess-markdown/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,11 @@
"types": "./types/index.d.ts",
"import": "./src/index.js"
},
"./EnhancedCodeBlock.svelte": {
"types": "./src/enhance-code-block/EnhancedCodeBlock.svelte.d.ts",
"svelte": "./src/enhance-code-block/EnhancedCodeBlock.svelte"
"./CodeBlock.svelte": {
"svelte": "./src/enhance-code-block/CodeBlock.svelte"
},
"./EnhancedCodeBlockGroup.svelte": {
"types": "./src/enhance-code-block/EnhancedCodeBlockGroup.svelte.d.ts",
"svelte": "./src/enhance-code-block/EnhancedCodeBlockGroup.svelte"
}
},
"typesVersions": {
"*": {
"EnhancedCodeBlock.svelte": [
"./src/enhance-code-block/EnhancedCodeBlock.svelte.d.ts"
],
"EnhancedCodeBlockGroup.svelte": [
"./src/enhance-code-block/EnhancedCodeBlockGroup.svelte.d.ts"
]
"./CodeBlockGroup.svelte": {
"svelte": "./src/enhance-code-block/CodeBlockGroup.svelte"
}
},
"publishConfig": {
Expand Down Expand Up @@ -70,7 +58,7 @@
"@types/hast": "^3.0.4"
},
"peerDependencies": {
"svelte": "^5.0.0"
"svelte": "^5.1.0"
},
"dependencies": {
"@shikijs/rehype": "^1.22.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script lang="ts" module>
import type { HTMLLabelAttributes } from 'svelte/elements';
export interface ButtonCollapseProps extends HTMLLabelAttributes {
id: string;
/** $bindable */
collapsed: boolean;
}
</script>

<script lang="ts">
let { id, collapsed = $bindable(), ...rest }: ButtonCollapseProps = $props();
</script>

<label {...rest}>
<input class="codeblock-collapsed sr-only" type="checkbox" bind:checked={collapsed} {id} />
<span class="sr-only">Collapse</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="currentcolor"
viewBox="0 0 256 256"
>
<path
d="M213.66,165.66a8,8,0,0,1-11.32,0L128,91.31,53.66,165.66a8,8,0,0,1-11.32-11.32l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,213.66,165.66Z"
>
</path>
</svg>
</label>

<style lang="postcss">
/** copied from CodeBlock.svelte */
@custom-selector :--fullscreen :has(.codeblock-fullscreen:checked);
@custom-selector :--collapsed :has(.codeblock-collapsed:checked);
@custom-selector :--c-collapsible-not-fullscreen
:global(.codeblock.collapsible:not(:--fullscreen));
@custom-selector :--c-not-collapsed :global(.codeblock:not(:--collapsed));
label {
transform: rotate(180deg);
display: none;
transition: transform 150ms ease-out;
:--c-collapsible-not-fullscreen & {
display: block;
}
:--c-not-collapsed & {
transform: rotate(0deg);
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<script lang="ts" module>
import type { TextResolverInput } from '@svelte-put/copy';
import type { HTMLButtonAttributes } from 'svelte/elements';
export interface ButtonCopyProps extends HTMLButtonAttributes {
/** $bindable. The button element. Pass as `trigger` arg to `@svelte-put/copy` */
trigger?: HTMLButtonElement;
}
/**
* copy code exclude meta lines. Pass as `text` arg to `@svelte-put/copy`
*/
export function copyCode(input: TextResolverInput<'click'>): string {
const codeNode = input.node.getElementsByTagName('code')[0];
if (!codeNode) return '';
let text = '';
for (const lineNode of codeNode.children) {
// assuming shiki build output and transformers set up at mdsvex.config.js
if ((lineNode as HTMLElement).dataset.lineDiff === '-') continue;
text += (lineNode.textContent || '') + '\n';
}
return text;
}
</script>

<script lang="ts">
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';
let { trigger = $bindable(), ...rest }: ButtonCopyProps = $props();
let timeoutId: ReturnType<typeof setTimeout> | undefined = undefined;
let optimistic = $state(false);
function onClick() {
optimistic = true;
}
function onMouseEnter() {
clearTimeout(timeoutId);
}
function onMouseLeave() {
timeoutId = setTimeout(() => {
optimistic = false;
}, 1800);
}
let hydrated = $state(false);
onMount(() => {
hydrated = true;
});
</script>

{#if hydrated}
<button
type="button"
bind:this={trigger}
disabled={optimistic}
onmouseleave={onMouseLeave}
onmouseenter={onMouseEnter}
onclick={onClick}
{...rest}
>
<span class="sr-only">Copy</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="currentcolor"
viewBox="0 0 256 256"
>
{#if optimistic}
<path
d="M168,152a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,152Zm-8-40H96a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16Zm56-64V216a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V48A16,16,0,0,1,56,32H92.26a47.92,47.92,0,0,1,71.48,0H200A16,16,0,0,1,216,48ZM96,64h64a32,32,0,0,0-64,0ZM200,48H173.25A47.93,47.93,0,0,1,176,64v8a8,8,0,0,1-8,8H88a8,8,0,0,1-8-8V64a47.93,47.93,0,0,1,2.75-16H56V216H200Z"
in:fade={{ duration: 150 }}
>
</path>
{:else}
<path
d="M200,32H163.74a47.92,47.92,0,0,0-71.48,0H56A16,16,0,0,0,40,48V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V48A16,16,0,0,0,200,32Zm-72,0a32,32,0,0,1,32,32H96A32,32,0,0,1,128,32Zm72,184H56V48H82.75A47.93,47.93,0,0,0,80,64v8a8,8,0,0,0,8,8h80a8,8,0,0,0,8-8V64a47.93,47.93,0,0,0-2.75-16H200Z"
in:fade={{ duration: 150 }}
>
</path>
{/if}
</svg>
</button>
{/if}

<style lang="postcss">
button {
&:disabled {
/* allow clicking even if already copied */
cursor: pointer;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<script lang="ts" module>
import type { HTMLLabelAttributes } from 'svelte/elements';
export interface ButtonFullScreeenProps extends HTMLLabelAttributes {
id: string;
codeblock?: HTMLElement;
}
</script>

<script lang="ts">
import { onMount } from 'svelte';
import { CodeBlockGroupContext } from './CodeBlockGroup.svelte';
let { id, codeblock, ...rest }: ButtonFullScreeenProps = $props();
let fullscreen = $state(false);
const groupContext = CodeBlockGroupContext.get();
function onFullScreenChange() {
fullscreen = !!document.fullscreenElement;
}
function goFullscreen() {
if (!document.fullscreenElement) {
if (groupContext?.node) {
groupContext.node.requestFullscreen();
} else {
codeblock?.requestFullscreen();
}
} else if (document.exitFullscreen) {
document.exitFullscreen();
}
}
function onKeyDown(e: KeyboardEvent) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
goFullscreen();
}
}
function onClick(e: MouseEvent) {
e.preventDefault();
goFullscreen();
}
onMount(() => {
codeblock?.addEventListener('fullscreenchange', onFullScreenChange);
return () => {
codeblock?.removeEventListener('fullscreenchange', onFullScreenChange);
};
});
</script>

<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<label for={id} {...rest} onclick={onClick} onkeydown={onKeyDown}>
<span class="sr-only">Toggle full screen</span>
{#if !groupContext}
<input class="codeblock-fullscreen sr-only" type="checkbox" {id} bind:checked={fullscreen} />
{/if}
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="currentcolor"
viewBox="0 0 256 256"
>
<path
class="maximize"
d="M216,48V88a8,8,0,0,1-16,0V56H168a8,8,0,0,1,0-16h40A8,8,0,0,1,216,48ZM88,200H56V168a8,8,0,0,0-16,0v40a8,8,0,0,0,8,8H88a8,8,0,0,0,0-16Zm120-40a8,8,0,0,0-8,8v32H168a8,8,0,0,0,0,16h40a8,8,0,0,0,8-8V168A8,8,0,0,0,208,160ZM88,40H48a8,8,0,0,0-8,8V88a8,8,0,0,0,16,0V56H88a8,8,0,0,0,0-16Z"
></path>
<path
class="minimize"
d="M152,96V48a8,8,0,0,1,16,0V88h40a8,8,0,0,1,0,16H160A8,8,0,0,1,152,96ZM96,152H48a8,8,0,0,0,0,16H88v40a8,8,0,0,0,16,0V160A8,8,0,0,0,96,152Zm112,0H160a8,8,0,0,0-8,8v48a8,8,0,0,0,16,0V168h40a8,8,0,0,0,0-16ZM96,40a8,8,0,0,0-8,8V88H48a8,8,0,0,0,0,16H96a8,8,0,0,0,8-8V48A8,8,0,0,0,96,40Z"
></path>
</svg>
</label>

<style lang="postcss">
/** copied from CodeBlock.svelte */
@custom-selector :--fullscreen :has(.codeblock-fullscreen:checked);
@custom-selector :--g-fullscreen
:global(.codeblock-group:has(.codeblock-group-fullscreen:checked));
.minimize {
display: none;
}
:--g-fullscreen,
label:has(:global(.codeblock-fullscreen:checked)) {
& .maximize {
display: none;
}
& .minimize {
display: block;
}
}
</style>
Loading

0 comments on commit 7146f36

Please sign in to comment.