Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@expressive-code/plugin-frames

Package Overview
Dependencies
Maintainers
1
Versions
78
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@expressive-code/plugin-frames - npm Package Compare versions

Comparing version 0.4.1 to 0.5.0

7

dist/index.d.ts
import { StyleSettings, ExpressiveCodePlugin, AttachedPluginData } from '@expressive-code/core';
declare const framesStyleSettings: StyleSettings<"shadowColor" | "frameBoxShadowCssValue" | "editorActiveTabBackground" | "editorActiveTabForeground" | "editorActiveTabBorder" | "editorActiveTabBorderTop" | "editorActiveTabBorderBottom" | "editorActiveTabMarginInlineStart" | "editorActiveTabMarginBlockStart" | "editorTabBorderRadius" | "editorTabBarBackground" | "editorTabBarBorderColor" | "editorTabBarBorderBottom" | "editorBackground" | "terminalTitlebarDotsForeground" | "terminalTitlebarBackground" | "terminalTitlebarForeground" | "terminalTitlebarBorderBottom" | "terminalBackground">;
declare const framesStyleSettings: StyleSettings<"shadowColor" | "frameBoxShadowCssValue" | "editorActiveTabBackground" | "editorActiveTabForeground" | "editorActiveTabBorder" | "editorActiveTabBorderTop" | "editorActiveTabBorderBottom" | "editorActiveTabMarginInlineStart" | "editorActiveTabMarginBlockStart" | "editorTabBorderRadius" | "editorTabBarBackground" | "editorTabBarBorderColor" | "editorTabBarBorderBottom" | "editorBackground" | "terminalTitlebarDotsForeground" | "terminalTitlebarBackground" | "terminalTitlebarForeground" | "terminalTitlebarBorderBottom" | "terminalBackground" | "inlineButtonForeground" | "inlineButtonHoverBackground" | "inlineButtonActiveBorder" | "tooltipSuccessBackground" | "tooltipSuccessForeground">;

@@ -12,2 +12,7 @@ interface PluginFramesOptions {

extractFileNameFromCode?: boolean;
/**
* If this is true (default), a "Copy to clipboard" button
* will be shown for each code block.
*/
showCopyToClipboardButton?: boolean;
styleOverrides?: Partial<typeof framesStyleSettings.defaultSettings>;

@@ -14,0 +19,0 @@ }

@@ -6,3 +6,3 @@ // src/index.ts

// src/styles.ts
import { StyleSettings, multiplyAlpha, onBackground, toRgbaString } from "@expressive-code/core";
import { StyleSettings, multiplyAlpha, onBackground, toRgbaString, setAlpha } from "@expressive-code/core";
var framesStyleSettings = new StyleSettings({

@@ -27,3 +27,8 @@ shadowColor: ({ theme, coreStyles }) => theme.colors["widget.shadow"] || multiplyAlpha(coreStyles.borderColor, 0.75),

terminalTitlebarBorderBottom: ({ theme, coreStyles }) => onBackground(coreStyles.borderColor, theme.type === "dark" ? "#000000bf" : "#ffffffbf"),
terminalBackground: ({ theme }) => theme.colors["terminal.background"]
terminalBackground: ({ theme }) => theme.colors["terminal.background"],
inlineButtonForeground: ({ coreStyles }) => coreStyles.codeForeground,
inlineButtonHoverBackground: ({ resolveSetting }) => setAlpha(resolveSetting("inlineButtonForeground"), 0.2),
inlineButtonActiveBorder: ({ resolveSetting }) => setAlpha(resolveSetting("inlineButtonForeground"), 0.4),
tooltipSuccessBackground: "#177d07",
tooltipSuccessForeground: "white"
});

@@ -46,2 +51,11 @@ function getFramesBaseStyles(theme, coreStyles, styleOverrides) {

const terminalTitlebarDots = `url("data:image/svg+xml,${escapedDotsSvg}")`;
const inlineButtonFg = toRgbaString(framesStyles.inlineButtonForeground);
const copySvg = [
`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='${inlineButtonFg}' stroke-width='1.75'>`,
`<path d='M3 19a2 2 0 0 1-1-2V2a2 2 0 0 1 1-1h13a2 2 0 0 1 2 1'/>`,
`<rect x='6' y='5' width='16' height='18' rx='1.5' ry='1.5'/>`,
`</svg>`
].join("");
const escapedCopySvg = copySvg.replace(/</g, "%3C").replace(/>/g, "%3E");
const copyToClipboard = `url("data:image/svg+xml,${escapedCopySvg}")`;
const activeTabBackgrounds = [];

@@ -63,4 +77,6 @@ if (framesStyles.editorActiveTabBorderTop) {

all: unset;
position: relative;
display: block;
--header-border-radius: calc(${coreStyles.borderRadius} + ${coreStyles.borderWidth});
--button-spacing: calc(${coreStyles.borderWidth} + 0.1rem);
border-radius: var(--header-border-radius);

@@ -126,2 +142,4 @@ box-shadow: ${framesStyles.frameBoxShadowCssValue};

&.is-terminal {
--button-spacing: calc(${coreStyles.borderWidth} + 0.02rem);
/* Terminal title bar */

@@ -167,2 +185,79 @@ & .header {

}
.copy {
display: flex;
gap: 0.25rem;
flex-direction: row-reverse;
position: absolute;
top: var(--button-spacing);
inset-inline-end: 0.5rem;
button {
align-self: flex-end;
width: 1.75rem;
height: 1.75rem;
margin: 0;
padding: 0.4rem;
border-radius: 0.2rem;
z-index: 2;
cursor: pointer;
background: transparent;
border: ${coreStyles.borderWidth} solid transparent;
opacity: 0.5;
transition-property: opacity, background, border-color;
transition-duration: 0.2s;
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
&:hover, &:focus:focus-visible {
opacity: 0.75;
background: ${framesStyles.inlineButtonHoverBackground};
}
&:active {
transition-duration: 0s;
opacity: 1;
border-color: ${framesStyles.inlineButtonActiveBorder};
}
&::before {
content: ${copyToClipboard};
line-height: 0;
}
}
.feedback {
--tooltip-arrow-size: 0.35rem;
--tooltip-bg: ${framesStyles.tooltipSuccessBackground};
color: ${framesStyles.tooltipSuccessForeground};
pointer-events: none;
user-select: none;
-webkit-user-select: none;
position: relative;
align-self: center;
background-color: var(--tooltip-bg);
z-index: 99;
padding: 0.125rem 0.75rem;
border-radius: 0.2rem;
margin-inline-end: var(--tooltip-arrow-size);
opacity: 0;
transition-property: opacity, transform;
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
transform: translate3d(0, 0.25rem, 0);
&::after {
position: absolute;
content: '';
top: calc(50% - var(--tooltip-arrow-size));
inset-inline-end: calc(-2 * (var(--tooltip-arrow-size) - 0.5px));
border: var(--tooltip-arrow-size) solid transparent;
border-inline-start-color: var(--tooltip-bg);
}
}
button:focus + .feedback.show {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
`;

@@ -223,8 +318,91 @@ return styles;

// src/copy-js-module.ts
var domCopy = [
// Start of function
`function domCopy(text) {`,
// Create a new DOM element to copy from and append it to the document,
// but make sure it's not visible and does not cause reflow
`let n = document.createElement('pre');
Object.assign(n.style, {
opacity: '0',
pointerEvents: 'none',
position: 'absolute',
overflow: 'hidden',
left: '0',
top: '0',
width: '20px',
height: '20px',
webkitUserSelect: 'auto',
userSelect: 'all'
});
n.ariaHidden = 'true';
n.textContent = text;
document.body.appendChild(n);`,
// Select the DOM element's contents
`let r = document.createRange();
r.selectNode(n);
let s = getSelection();
s.removeAllRanges();
s.addRange(r);`,
// Copy the selection to the clipboard
`let ok = false;
try {
ok = document.execCommand('copy');
} finally {
s.removeAllRanges();
document.body.removeChild(n);
}
return ok;`,
// End of function
`}`
];
var handleClicks = [
// Start of loop through all buttons that adds a click handler per button
`document.querySelectorAll('[SELECTOR]').forEach((button) =>
button.addEventListener('click', async () => {`,
// Click handler code
`let ok = false;
let code = button.dataset.code.replace(/\\u007f/g, '\\n');
try {
await navigator.clipboard.writeText(code);
ok = true;
} catch (err) {
ok = domCopy(code);
}`,
// Show feedback tooltip
`if (ok && (!button.nextSibling || !button.nextSibling.classList.contains('feedback'))) {
let tt = document.createElement('div');
tt.classList.add('feedback');
tt.append(button.dataset.copied);
button.after(tt);`,
// Use offsetWidth and requestAnimationFrame to opt out of DOM batching,
// which helps to ensure that the transition on 'show' works
` tt.offsetWidth;
requestAnimationFrame(() => tt.classList.add('show'));`,
// Hide & remove the tooltip again when we no longer need it
` let h = () => {
if (!(parseFloat(getComputedStyle(tt).opacity) > 0)) tt.remove();
};
setTimeout(() => tt.classList.remove('show'), 1500);
setTimeout(() => h(), 2500);
tt.addEventListener('transitioncancel', h);
tt.addEventListener('transitionend', h);
}`,
// End of loop through all buttons
`}))`
];
var getCopyJsModule = (buttonSelector) => {
return [...domCopy, ...handleClicks].map(
(line) => line.trim().replace(/\s*[\r\n]\s*/g, "").replace(/\s*([:;,={}()<>])\s*/g, "$1").replace(/;}/g, "}")
).join("").replace("[SELECTOR]", buttonSelector);
};
// src/index.ts
function pluginFrames(options = {}) {
const extractFileNameFromCode = options.extractFileNameFromCode ?? true;
const showCopyToClipboardButton = options.showCopyToClipboardButton ?? true;
return {
name: "Frames",
baseStyles: ({ theme, coreStyles }) => getFramesBaseStyles(theme, coreStyles, options.styleOverrides || {}),
jsModules: showCopyToClipboardButton ? [getCopyJsModule(`.expressive-code .copy button`)] : void 0,
hooks: {

@@ -264,2 +442,17 @@ preprocessMetadata: ({ codeBlock }) => {

const screenReaderTitle = !titleText && isTerminal ? [h("span", { className: "sr-only" }, fallbackTerminalWindowTitle)] : [];
const extraElements = [];
if (showCopyToClipboardButton) {
const copyButtonTooltip = "Copy to clipboard";
const copyButtonCopied = "Copied!";
const codeToCopy = codeBlock.code.replace(/\n/g, "\x7F");
extraElements.push(
h("div", { className: "copy" }, [
h("button", {
title: copyButtonTooltip,
"data-copied": copyButtonCopied,
"data-code": codeToCopy
})
])
);
}
renderData.blockAst = h(

@@ -278,2 +471,3 @@ "figure",

h("figcaption", { className: "header" }, [...visibleTitle, ...screenReaderTitle]),
...extraElements,
// Render the original code block

@@ -280,0 +474,0 @@ renderData.blockAst

6

package.json
{
"name": "@expressive-code/plugin-frames",
"version": "0.4.1",
"version": "0.5.0",
"description": "Frames plugin for Expressive Code. Wraps code blocks in a styled editor or terminal frame with support for titles, multiple tabs and more.",

@@ -21,7 +21,7 @@ "keywords": [],

"dependencies": {
"@expressive-code/core": "^0.4.0",
"@expressive-code/core": "^0.5.0",
"hastscript": "^7.2.0"
},
"devDependencies": {
"@internal/test-utils": "^0.1.3",
"@internal/test-utils": "^0.2.0",
"hast-util-select": "^5.0.5",

@@ -28,0 +28,0 @@ "hast-util-to-html": "^8.0.4"

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc